Android无法在dir中创建文件getExternalStoragePublicDirectory()

时间:2015-03-03 16:57:53

标签: android

我正在尝试按照this explanationthis code将自己的警报音复制到Android系统。

问题是我无法将文件从原始资源复制到外部存储器。我在这里看了其他问题,但似乎没有答案对我有用。

这是我的AndroidManifest(我将WRITE_EXTERNAL_STORAGE置于应用程序标记之外,如here所述):

...
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

<application...

这是我的代码。它运行在从我的主要活动的onCreate开始的新线程上。从该新线程调用方法“void onFirstTime()”,并且该方法重复调用“void copyRawRingtone(File dstPath,int resId)”:

void copyRawRingtone(File dstPath, int resId) {
    final String fileName = getResources().getResourceEntryName(resId) + ".mp3";
    File dstFile = new File(dstPath, fileName);
    if (!dstFile.exists()) {
        InputStream srcStream = getResources().openRawResource(resId);
        FileOutputStream dstStream = null;
        try {
            dstFile.createNewFile(); // THIS THROWS THE EXCEPTION
            dstStream = new FileOutputStream(dstFile);
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = srcStream.read(buffer)) > 0) {
                dstStream.write(buffer, 0, bytesRead);
            }

            // Set the file metadata
            final String mimeType = "audio/mpeg";
            final String dstAbsPath = dstFile.getAbsolutePath();
            ContentValues contentValues = new ContentValues();
            contentValues.put(MediaStore.MediaColumns.DATA, dstAbsPath);
            contentValues.put(MediaStore.MediaColumns.TITLE, fileName);
            contentValues.put(MediaStore.MediaColumns.MIME_TYPE, mimeType);
            contentValues.put(MediaStore.Audio.Media.IS_ALARM, true);
            contentValues.put(MediaStore.Audio.Media.IS_NOTIFICATION, false);
            contentValues.put(MediaStore.Audio.Media.IS_RINGTONE, false);
            contentValues.put(MediaStore.Audio.Media.IS_MUSIC, false);

            // Add the metadata to the file in the database
            Uri contentUri = MediaStore.Audio.Media.getContentUriForPath(dstAbsPath);
            Uri newUri = getContentResolver().insert(contentUri, contentValues);

            // Tell the media scanner about the new ringtone
            MediaScannerConnection.scanFile(
                    this,
                    new String[]{newUri.toString()},
                    new String[]{mimeType},
                    null
            );
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (dstStream != null) {
                try {
                    dstStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        try {
            srcStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

// First time initialization (called in a new thread from onCreate)
void onFirstTime() {
    if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
        File dstPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_ALARMS);
        // This returns false but since I run it on an emulator, I don't know how to check if it actually exists:
        dstPath.mkdirs();
        Field[] rawResources = R.raw.class.getFields();
        final ProgressBar installProgress = (ProgressBar) findViewById(R.id.progressBar);
        final int length = rawResources.length;
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                installProgress.setMax(length);
            }
        });
        for (int i = 0; i < length; ++i) {
            try {
                int resId = rawResources[i].getInt(rawResources[i]);
                copyRawRingtone(dstPath, resId); // Call the method above
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            final int progress = i + 1;
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    installProgress.setProgress(progress);
                }
            });
        }
    }
}

行:dstFile.createNewFile();抛出异常:

java.io.IOException: open failed: ENOENT (No such file or directory)

我不明白可能是什么问题。我在模拟器上运行它:Nexus_S_API_21_armeabi-v7a。

我没有在我的电脑下看到模拟器的存储,所以我认为电脑模拟器存储没有安装在我的电脑上,所以我不认为this could be the problem

在异常时刻,这些是一些变量值:

dstPath="/storage/sdcard/Alarms"
fileName="whistle_alarm.mp3"
dstFile="/storage/sdcard/Alarms/whistle_alarm.mp3"

因为这返回true:

Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)

媒体似乎已挂载且可写(不是MEDIA_MOUNTED_READ_ONLY)。所以我不知道会出现什么问题!有没有人有任何想法??

修改

我添加了这两行(我还在前面放了一行,后面有一行在上下文中看到它:

File dstPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_ALARMS);
        final boolean exists = dstPath.exists(); // Added. exists=true
        final boolean canWrite = dstPath.canWrite(); // Added. canWrite=true
        dstPath.mkdirs();

我也删除了:

dstFile.createNewFile(); // THIS THROWS THE EXCEPTION

它现在有效!

但是我已经多次测试过没有这个createNewFile()行,但它没有用。确实,我添加了这一行,看看我是否可以使用它。所以我再次尝试使用那条线,它也有效!

我怀疑实际的解决方案是重启模拟器。

0 个答案:

没有答案