Android文件拷贝

最近项目中协助做了个小的测试程序,需要拷贝文件。代码如下:

    // fixed for raw data test.
    private static final String RAW_DATA_TEST = "***123***";
    private static final String EXTERNAL_STORAGE = "/mnt/sdcard2";
    private static final String INTERNAL_STORAGE = "/mnt/sdcard";    
    private static final String RAW_DATA_CFG_FILE_NAME = "config.xml";

    // fixed for raw data test.
    static public boolean handleRawDataTest(Context context, String input) {
        if (RAW_DATA_TEST.equals(input)) {
            Log.d(TAG, "handleRawDataTest");

            if (!copyRawDataCfgFile()) {
                Log.d(TAG, "handleRawDataTest, get Raw Data Cfg file failed!");
                Toast.makeText(context, 
                    context.getString(R.string.raw_data_cfg_file_not_exist), 
                    Toast.LENGTH_SHORT).show();
                return false;
            }
            
            Intent intent = new Intent();
            intent.setComponent(new ComponentName("com.goodix.rawdata", 
                                        "com.goodix.rawdata.RawDataTest"));
            context.startActivity(intent);
            return true;
        }
        
        return false;
    }

    public static boolean copyRawDataCfgFile() {
        String state = Environment.getExternalStorageState();
        if (!Environment.MEDIA_MOUNTED.equals(state)) {
            return false;
        }

        String srcFileName = EXTERNAL_STORAGE + File.separator + RAW_DATA_CFG_FILE_NAME;
        String destFileName = INTERNAL_STORAGE + File.separator + RAW_DATA_CFG_FILE_NAME;
        Log.d(TAG, "copyRawDataCfgFile, srcFileName = " + srcFileName + ", destFileName = " + destFileName);
        try {
            if (copyFile(srcFileName, destFileName, true)) {
                Log.d(TAG, "copyRawDataCfgFile, successfull!");
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        Log.d(TAG, "copyRawDataCfgFile, fail!");
        return false;
    }

    public static boolean copyFile(String srcFileName, String destFileName, boolean reWrite) 
        throws IOException {
        Log.d(TAG, "copyFile, begin");
        File srcFile = new File(srcFileName);
        File destFile = new File(destFileName);        
        if(!srcFile.exists()) {
            Log.d(TAG, "copyFile, source file not exist.");
            return false;
        }
        if(!srcFile.isFile()) {
            Log.d(TAG, "copyFile, source file not a file.");
            return false;
        }
        if(!srcFile.canRead()) {
            Log.d(TAG, "copyFile, source file can't read.");
            return false;
        }
        if(destFile.exists() && reWrite){
            Log.d(TAG, "copyFile, before copy File, delete first.");
            destFile.delete();
        }

        try {
            InputStream inStream = new FileInputStream(srcFile);
            FileOutputStream outStream = new FileOutputStream(destFile);
            byte[] buf = new byte[1024];
            int byteRead = 0;
            while ((byteRead = inStream.read(buf)) != -1) {
                outStream.write(buf, 0, byteRead);
            }
            outStream.flush();
            outStream.close();
            inStream.close();
        } catch (IOException e) {
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
        }

        Log.d(TAG, "copyFile, success");
        return true;
    }      
代码比较简单,但是中间报了个很奇怪的异常,纠结了很长时间,幸好在临下班前找到问题根结所在。记下这次事件,以此勉之。

异常如下:

01-01 00:14:31.070: E/StrictMode(3297): A resource was acquired at attached stack trace but never released. See java.io.Closeable for information on avoiding resource leaks.
01-01 00:14:31.070: E/StrictMode(3297): java.lang.Throwable: Explicit termination method 'close' not called
01-01 00:14:31.070: E/StrictMode(3297): 	at dalvik.system.CloseGuard.open(CloseGuard.java:184)
01-01 00:14:31.070: E/StrictMode(3297): 	at java.io.FileInputStream.<init>(FileInputStream.java:80)
01-01 00:14:31.070: E/StrictMode(3297): 	at com.android.dialer.SpecialCharSequenceMgr.copyFile(SpecialCharSequenceMgrProxy.java:768)
01-01 00:14:31.070: E/StrictMode(3297): 	at com.android.dialer.SpecialCharSequenceMgr.copyRawDataCfgFile(SpecialCharSequenceMgrProxy.java:702)
01-01 00:14:31.070: E/StrictMode(3297): 	at com.android.dialer.SpecialCharSequenceMgr.handleRawDataTest(SpecialCharSequenceMgrProxy.java:674)
01-01 00:14:31.070: E/StrictMode(3297): 	at com.android.dialer.SpecialCharSequenceMgr.handleCharsForTest(SpecialCharSequenceMgrProxy.java:618)
01-01 00:14:31.070: E/StrictMode(3297): 	at com.android.dialer.SpecialCharSequenceMgr.handleChars(SpecialCharSequenceMgrProxy.java:88)
01-01 00:14:31.070: E/StrictMode(3297): 	at com.android.dialer.dialpad.DialpadFragment.afterTextChanged(DialpadFragment.java:451)
01-01 00:14:31.070: E/StrictMode(3297): 	at android.widget.TextView.sendAfterTextChanged(TextView.java:7626)
01-01 00:14:31.070: E/StrictMode(3297): 	at android.widget.TextView$ChangeWatcher.afterTextChanged(TextView.java:9424)
在网上也搜过“java.io.Closeable for information on avoiding resource leaks”和“java.lang.Throwable: Explicit termination method ‘close‘ not called”,都没找到和我这个问题类似的情况,一般都是cursor导致的内存泄漏的问题。最终,在反复查看代码才发现,原来问题的根结在我拷贝文件的目标目录未指定正确。出现问题的时候,我指定了INTERNAL_STORAGE为“/mnt/sdcard0”,在调用到new FileOutputStream(destFile)时会抛出异常,原因是并没有这个目录。手机内部存储根目录是“/mnt/sdcard”,这个路径实际指向了“/storage/sdcard0”。



Android文件拷贝

上一篇:修改android4.4图库系列四(五)——android4.4.2图库整体架构分析


下一篇:Codeforces Round #263 (Div. 2) D. Appleman and Tree(树形DP)