Android java.io.IOException:无法更改文件
我正在使用JAudioTagger库读取和写入音频文件的标记。我能读标签,但不能写 我正在检索音频文件路径,如下所示: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
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卡
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");
}
我看到您已经在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方法写入
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);
}
}