2016-06-18 42 views
1

我正在使用JAudioTagger库来读取和写入音频文件的标签。我能够读取标签但无法写入。java.io.IOException:无法更改文件

我检索音频文件的路径是这样的:

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()方法是给予以下异常:

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写标签org.jaudiotagger.audio.exceptions.CannotWriteException: java.io.IOException:无法更改文件xyz.mp3在 org.jaudiotagger.audio.mp3.MP3File.commit(MP3File.java:799)在 com.techapps.musicplayerplus.MainActivity $ 17.onClick(MainActivity.java:2125) 在 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)导致 作者:java.io.IOException:无法更改文件Saibo.mp3 org.jaudiotagger.audio.mp3.MP3File.precheck(MP3File的.java:824)留在 org.jaudiotagger org.jaudiotagger.audio.mp3.MP3File.save(MP3File.java:850)在 org.jaudiotagger.audio.mp3.MP3File.save(MP3File.java:783) .audio.mp3.MP3File.commit(MP3File.java:795)

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

android.permission.WRITE_EXTERNAL_STORAGE

不过我不能写入SD卡。请帮帮我。提前致谢。

+0

嗨!我有同样的问题(阅读下面的评论)!请告诉我,如果你已经解决了它! –

回答

0

这可能是你指向不存在的文件。

使用Log检查您的路径文件。

Log.d("Activity", "path = " + path); 
+0

我在上面的代码中提到了路径示例。它看起来像/storage/3932-3434/Music/xyz.mp3。我通过文件资源管理器检查了它的文件。 – akshay7692

+0

我有同样的问题!我的路径是/storage/6332-6461/Music/xyz.mp3,我认为问题是数字..也许jaudiotagger不支持?请告诉我,如果你已经解决了你的问题! –

0

Android-M或API 23引入了运行时权限以减少Android设备的安全漏洞。

要使用Google Play服务更新您的应用以处理Android 6.0权限,最好管理用户设置运行时可能需要的权限的期望。以下link将帮助您避免潜在的问题。

https://developer.android.com/training/permissions/requesting.html

+0

但AFAIK,因为我的应用程序针对的是API 22,所以在安装应用程序时授予WRITE_EXTERNAL_STORAGE权限时,不需要运行时权限,并且应用程序应该正常运行。 – akshay7692

0

有你声明的许可 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

+0

我已经在我的问题中提到我已经声明上述许可。 – akshay7692

1

您必须使用存储访问框架(SAF)从API 19(Kitkat)开始访问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"); 
    } 
    

一旦你拿起用户目录的开放的,你可以使用SAF进行写操作:(空间日志相册: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); 
    } 
}