android - java.io.IOException : Cannot make changes to file 异常

标签 android jaudiotagger

我正在使用 JAudioTagger 库来读取和写入音频文件的标签。我能够读取标签但无法写入它们。

我正在像这样检索音频文件路径:

 private String getSongPath(long songId) {
        String path = null;
        ContentResolver contentResolver = getContentResolver();
        Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
        String[] projection = {MediaStore.Audio.Media.DATA};
        String selection = MediaStore.Audio.Media._ID + " == ?";
        String[] selectionArgs = {String.valueOf(songId)};

        Cursor cursor = contentResolver.query(uri, projection, selection, selectionArgs, null);

        if (cursor != null) {
            int pathCol = cursor.getColumnIndexOrThrow(projection[0]);
            cursor.moveToFirst();
            path = cursor.getString(pathCol);
            cursor.close();
        }

        return path;
    }

然后使用 JAudioTagger 编写标签:

File songFile = new File(path); // path looks like /storage/3932-3434/Music/xyz.mp3
AudioFile audiofile = = AudioFileIO.read(songFile);
Tag tag = = audiofile.getTag();
tag.setField(FieldKey.TITLE, title);
// some more setField calls for different feilds
audiofile.commit();

commit() 方法给出以下异常:

org.jaudiotagger.audio.exceptions.CannotWriteException: java.io.IOException: Cannot make changes to file xyz.mp3 at org.jaudiotagger.audio.mp3.MP3File.commit(MP3File.java:799) at com.techapps.musicplayerplus.MainActivity$17.onClick(MainActivity.java:2125) at android.support.v7.app.AlertController$ButtonHandler.handleMessage(AlertController.java:157) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:148) at android.app.ActivityThread.main(ActivityThread.java:5417) 06-18 10:59:48.134 8802-8802/com.techapps.musicplayerplus W/System.err:
at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) Caused by: java.io.IOException: Cannot make changes to file Saibo.mp3 at org.jaudiotagger.audio.mp3.MP3File.precheck(MP3File.java:824) at org.jaudiotagger.audio.mp3.MP3File.save(MP3File.java:850) at org.jaudiotagger.audio.mp3.MP3File.save(MP3File.java:783) at org.jaudiotagger.audio.mp3.MP3File.commit(MP3File.java:795)

我在 Android 6 上运行此代码,而我的应用程序针对 SDK 22。我还在 list 中提到了以下权限。

android.permission.WRITE_EXTERNAL_STORAGE

我仍然无法写入 SD 卡。请帮我。提前致谢。

最佳答案

从 API 19 (Kitkat) 开始,您必须使用存储访问框架 (SAF) 来访问 SD 卡。

  1. 首先,我们需要要求用户提供我们要访问的文件夹的 URI。如果我们想要访问整个 SD 卡,用户需要提供 SD 卡根文件夹的 URI。 例如,当用户点击编辑按钮时,我们必须首先显示提示对话框,要求用户选择我们想要访问的 SD 卡中所需的目录。您可以在提示对话框中显示下图,要求用户选择 SD 卡的根目录:You can use this image in hint dialog box to ask user to select SD Card root directory

  2. 当用户关闭提示对话框时,您需要触发存储访问框架:

    private void triggerStorageAccessFramework() {
     Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
     startActivityForResult(intent, REQUEST_CODE_STORAGE_ACCESS);
     }
    
    public final void onActivityResult(final int requestCode, final int resultCode, final Intent resultData) {
     if (resultCode == Activity.RESULT_OK) {
            if (requestCode == REQUEST_CODE_STORAGE_ACCESS) {
                    Uri treeUri = null;
                    // Get Uri from Storage Access Framework.
                    treeUri = resultData.getData();
                    pickedDir= DocumentFile.fromTreeUri(this, treeUri);
    
                    if (!isSDCardRootDirectoryUri(treeUri)) {
                        Toast.makeText(this, "Wrong directory selected. Please select SD Card root directory.", Toast.LENGTH_LONG).show();
                        createSDCardHintDialog().show();
                        return;
                    }        
    
                    // Persist URI in shared preference so that you can use it later.                   
                    SharedPreferences sharedPreferences = getSharedPreferences(App.PREFERENCE_FILENAME, Context.MODE_PRIVATE);
                    SharedPreferences.Editor editor = sharedPreferences.edit();
                    editor.putString(App.SDCARD_URI_KEY, treeUri.toString());
                    editor.apply();  
    
                    // Persist access permissions, so you dont have to ask again
                    final int takeFlags = resultData.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
                    getContentResolver().takePersistableUriPermission(treeUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    
                }
       } 
    
    private boolean isSDCardRootDirectoryUri(Uri treeUri) {
        String uriString = treeUri.toString();
        return uriString.endsWith("%3A");
    }
    

一旦获得用户选择的目录的 Uri,就可以使用 SAF 执行写入操作:(cradit : this answer)

public void writeFile(DocumentFile pickedDir) {
    try {
        DocumentFile file = pickedDir.createFile("image/jpeg", "try2.jpg");
        OutputStream out = getContentResolver().openOutputStream(file.getUri());
        try {

            // write the image content

        } finally {
            out.close();
        }

    } catch (IOException e) {
        throw new RuntimeException("Something went wrong : " + e.getMessage(), e);
    }
}

关于android - java.io.IOException : Cannot make changes to file 异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37893684/

相关文章:

java - jaudiotagger 获取 mp3 频率

安卓 : JAudioTagger doesn't change the tags

android - JAudioTagger 和 Android - 更改 mp3 中的值?

Android BluetoothSocket OutputStream 无限写入 block

java - 如何在Parcelable类中实现读写

android - 添加proguard后cordova的相机插件中的java NullPointerException

android - 例程 :EVP_DecryptFinal_ex:wrong final block length in android

android - 我可以在使用 Linkify 后更改 TextView 链接文本吗?