Android 10文件重命名无反应问题排查(Android 11+正常)
问题:Android 10下文件重命名无反应,Android 11+正常
我编写了一套文件重命名代码,在Android 11及以上版本可正常完成文件重命名操作,但在Android 10中执行后无任何反应。相关代码实现、参数示例及调用方式如下:
原代码实现
public class PathDiv { public static String dev(String path){ return path.replaceAll("^(.*)/.*?$","$1"); } public static void renameFilesInDir(String path, String dirIn, String ext) { File checkFile = new File(path); if (checkFile.isFile()) { try { checkFile.renameTo(new File(dirIn, ext)); } catch (Exception e) { e.printStackTrace(); } } }
参数示例
- path:
/storage/emulated/0/Music/04. Kasger - Highland.mp3 - dirIn:
/storage/emulated/0/Music - ext:
Highland.mp3
调用代码
PathDiv.renameFilesInDir(songItem.realUri,PathDiv.dev(songItem.realUri),newName.toString())
问题根源
- Android 10 Scoped Storage限制:Android 10(API 29)引入了Scoped Storage机制,此时直接通过
File.renameTo()操作外部存储的媒体文件,会因为权限限制静默失败——方法返回false但不会抛出异常,而你的代码没有检查这个返回值,所以看不到操作失败的迹象。 renameTo()方法的局限性:该方法本身依赖底层文件系统支持,在不同Android版本的存储权限模型下行为不一致,且没有可靠的失败反馈机制。
修复方案
针对Android 10及以上版本,必须适配Scoped Storage,使用MediaStore API来修改媒体文件名;同时增加返回值检查,明确操作结果。
兼容版重命名代码
import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.net.Uri; import android.os.Build; import android.provider.MediaStore; import android.util.Log; import java.io.File; public class PathDiv { public static String dev(String path) { return path.replaceAll("^(.*)/.*?$", "$1"); } public static boolean renameFilesInDir(Context context, String path, String dirIn, String ext) { File checkFile = new File(path); if (!checkFile.isFile()) { return false; } // Android 10及以上,使用MediaStore修改文件名 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { Uri contentUri = MediaStore.Audio.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY); String selection = MediaStore.Audio.Media.DATA + "=?"; String[] selectionArgs = new String[]{path}; ContentResolver resolver = context.getContentResolver(); try (Cursor cursor = resolver.query(contentUri, new String[]{MediaStore.Audio.Media._ID}, selection, selectionArgs, null)) { if (cursor != null && cursor.moveToFirst()) { long mediaId = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID)); Uri itemUri = ContentUris.withAppendedId(contentUri, mediaId); ContentValues values = new ContentValues(); values.put(MediaStore.Audio.Media.DISPLAY_NAME, ext); // 执行更新 int rowsUpdated = resolver.update(itemUri, values, null, null); return rowsUpdated > 0; } } catch (Exception e) { e.printStackTrace(); return false; } return false; } else { // Android 9及以下,沿用File操作,但检查返回值 try { File targetFile = new File(dirIn, ext); boolean success = checkFile.renameTo(targetFile); if (!success) { Log.e("PathDiv", "重命名失败:原路径" + path + ",目标路径" + targetFile.getAbsolutePath()); } return success; } catch (Exception e) { e.printStackTrace(); return false; } } } }
修改后的调用方式
// 传入Context对象,接收重命名结果 boolean isSuccess = PathDiv.renameFilesInDir(getApplicationContext(), songItem.realUri, PathDiv.dev(songItem.realUri), newName.toString()); if (!isSuccess) { // 这里处理重命名失败的逻辑,比如提示用户 }
注意事项
- 权限配置:在
AndroidManifest.xml中添加权限声明,并在运行时动态申请:<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="29" /> - Android 11及以上版本,Scoped Storage进一步收紧,但
MediaStoreAPI是官方推荐的合规操作方式,能正常工作。
内容的提问来源于stack exchange,提问作者UserAndroidDeveloper
相关产品推荐
相关产品推荐

