Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/194.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android java.io.IOException:无法更改文件_Android_Jaudiotagger - Fatal编程技术网

Android java.io.IOException:无法更改文件

Android java.io.IOException:无法更改文件,android,jaudiotagger,Android,Jaudiotagger,我正在使用JAudioTagger库读取和写入音频文件的标记。我能读标签,但不能写 我正在检索音频文件路径,如下所示: private String getSongPath(long songId) { String path = null; ContentResolver contentResolver = getContentResolver(); Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTE

我正在使用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:无法在以下位置更改文件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) 位于android.os.Handler.dispatchMessage(Handler.java:102) Looper.loop(Looper.java:148)位于 android.app.ActivityThread.main(ActivityThread.java:5417)06-18 10:59:48.134 8802-8802/com.techapps.musicplayerplus W/System.err:
在java.lang.reflect.Method.invoke(本机方法)中 com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) 在com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)上 by:java.io.IOException:无法更改位于的文件Saibo.mp3 org.jaudiotagger.audio.mp3.MP3File.precheck(MP3File.java:824)位于 org.jaudiotagger.audio.mp3.MP3File.save(MP3File.java:850)位于 org.jaudiotagger.audio.mp3.MP3File.save(MP3File.java:783)位于 org.jaudiotagger.audio.mp3.MP3File.commit(MP3File.java:795)

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

android.permission.WRITE\u外部存储


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

可能是您指向了不存在的文件

使用日志检查路径文件

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

Android-M或API 23引入了运行时权限,以减少Android设备中的安全缺陷

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


您已经声明了权限吗

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

  • 首先,我们需要要求用户提供我们想要访问的文件夹的URI。若我们想要访问整个SD卡,用户需要提供SD卡根文件夹的URI。 例如,当用户点击编辑按钮时,我们必须首先显示提示对话框,要求用户在SD卡中选择我们想要访问的所需目录。您可以在提示对话框中显示下图,要求用户选择SD卡的根目录:

  • 当用户取消提示对话框时,您需要触发存储访问框架:

    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:(creadit:)执行写操作


    我看到您已经在JAudioTagger GitHub存储库中创建了一个问题,这是可取的,但从未得到一个通用的解决方案。我的调查结果如下:

    • 提到SAF的答案是正确的,但它不会帮助您,因为SAF将提供一个文档文件,而不是一个文件
    • 您可以尝试根据需要修改JAudioTagger,将文件替换为DocumentFile,但DocumentFile并没有您需要的所有功能
    • 此外,InputStream和OutputStream对您也没有帮助,因为JAudioTagger需要文件,并且在内部大量使用RandomAccessFile,这两个文件也不可用
    • 谷歌“忘记”提供一些getRandomAccessFileFromUri(),这让事情变得更糟(是的,有黑客使用Java反射来解决这个限制…)
    • “/proc/self/fd”方法()也不会立即工作,因为JAudioTagger需要复制和重命名不适用于此类文件的函数。尤其是JAudioTagger找不到合适的文件扩展名,如“.m4a”。当然,你可以试着相应地改变Jaudiotager
    • 您可以按照建议将文件复制到您的个人存储中,然后对其应用JAudioTagger,最后将其复制回SD卡,但是:
    • 如果你想使用JAudioTagger从SD卡上读取数据,正如谷歌所宣布的那样,Android 10将失败。从该版本开始,您甚至无法通过文件接口读取SD卡
    • 此外,文件接口允许您读取Android 9及以下版本的SD卡,但不能读取其他SAF设备,如USB OTG内存或SMB共享等
    • 当然,您也可以复制每个文件以读取其元数据,但这将非常缓慢,如果您有多个文件,则不适合这样做
    因此,我目前的建议是:

    • 尝试“/proc/self/fd”方法并相应地修改JAudioTagger
    • 如果更改太多,请使用fd方法读取标记,使用copy方法写入
    顺便说一句:我目前正在修改JAudioTagger的一个旧版本,以便透明地使用File和DocumentFile,但是更改非常大,风险很高,需要一些帮助课程,而且工作尚未完成


    BTSW:与文件函数相比,DocumentFile函数的速度非常慢。

    我在上面的代码中提到了路径示例。它看起来像/storage/3932-3434/Music/xyz.mp3。我通过文件资源管理器检查了这个文件,发现了同样的问题!我的路径是/storage/6332-6461/Music/xyz.mp3,我认为问题在于数字。。也许Jaudiotager不支持这一点?请告诉我你的问题是否解决了!我已经在我的问题中提到,我已经声明了上述权限。但顺便说一句,因为我的应用程序是针对API 22的,所以不需要运行时权限,当授予写入外部存储权限时,应用程序应该可以正常运行
    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);
        }
    }