Android本地JSON文件读写路径适配问题求助
解决Android 11下外部存储JSON文件读写失败问题
问题根源
Android 11(API 30)引入了Scoped Storage机制,严格限制应用对外部存储公共目录的直接访问权限。你的代码依赖Environment.getExternalStorageDirectory()访问外部存储根目录或Download目录,在Android 11及以上系统中会被权限拦截;而Android 5.1没有该限制,因此模拟器能正常运行。
方案1:改用应用内部私有存储(推荐)
应用内部私有存储无需任何权限,文件仅当前应用可访问,适合存储应用专属的JSON文件。
修改读文件代码(fetchData类)
替换文件路径为应用内部存储目录:
class fetchData extends Thread { @Override public void run() { try { // 文件将保存在 /data/data/你的应用包名/files/TEST.json File yourFile = new File(getFilesDir(), "TEST.json"); FileInputStream stream = new FileInputStream(yourFile); String data = null; try { FileChannel fc = stream.getChannel(); MappedByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()); data = Charset.defaultCharset().decode(bb).toString(); } catch(Exception e){ e.printStackTrace(); } finally { stream.close(); } JSONObject jsonObject = new JSONObject(data); JSONArray Data = jsonObject.getJSONArray("DATA"); for (int i = 0; i < Data.length(); i++) { Urun urun = new Urun(); //(CENSORED) uruns.add(urun); } } catch (Exception e) { e.printStackTrace(); } recyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext())); adapter = new Adapter(getApplicationContext(), uruns); recyclerView.setAdapter(adapter); } }
修改写文件代码(fetchDataWrite类)
同样替换路径为内部存储,新增文件存在性判断:
class fetchDataWrite extends Thread { @Override public void run() { try { File yourFile = new File(getFilesDir(), "TEST.json"); // 若文件不存在则创建 if (!yourFile.exists()) { yourFile.createNewFile(); } FileInputStream stream = new FileInputStream(yourFile); String data = null; try { FileChannel fc = stream.getChannel(); MappedByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()); data = Charset.defaultCharset().decode(bb).toString(); } catch(Exception e){ e.printStackTrace(); } finally { stream.close(); } JSONObject jsonObject = new JSONObject(data); JSONArray Data = jsonObject.getJSONArray("DATA"); //(CENSORED) FileWriter fileWriter = new FileWriter(yourFile); BufferedWriter bufferedWriter = new BufferedWriter(fileWriter); bufferedWriter.write(/*CENSORED STRING*/); bufferedWriter.close(); } catch (Exception e) { e.printStackTrace(); } } }
补充说明
- 可通过Android Studio的Device File Explorer查看内部存储文件,路径为
data/data/你的应用包名/files/ - 若需迁移原外部存储的
TEST.json,可手动通过Device File Explorer复制到内部存储目录,或在应用启动时添加自动迁移逻辑
方案2:适配Scoped Storage(需保留外部存储时使用)
如果必须将文件放在外部存储公共目录(如Download),需使用MediaStore或存储访问框架(SAF)操作文件:
写入Download目录示例
private void writeToDownloadDir(String fileName, String content) { ContentValues values = new ContentValues(); values.put(MediaStore.Downloads.DISPLAY_NAME, fileName); values.put(MediaStore.Downloads.MIME_TYPE, "application/json"); values.put(MediaStore.Downloads.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS); Uri uri = getContentResolver().insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, values); if (uri != null) { try (OutputStream outputStream = getContentResolver().openOutputStream(uri)) { if (outputStream != null) { outputStream.write(content.getBytes()); } } catch (IOException e) { e.printStackTrace(); } } }
读取Download目录的TEST.json示例
private String readFromDownloadDir(String fileName) { Uri uri = MediaStore.Downloads.EXTERNAL_CONTENT_URI; String[] projection = {MediaStore.Downloads._ID, MediaStore.Downloads.DATA}; String selection = MediaStore.Downloads.DISPLAY_NAME + " = ?"; String[] selectionArgs = {fileName}; Cursor cursor = getContentResolver().query(uri, projection, selection, selectionArgs, null); if (cursor != null && cursor.moveToFirst()) { int dataIndex = cursor.getColumnIndex(MediaStore.Downloads.DATA); String filePath = cursor.getString(dataIndex); cursor.close(); try (FileInputStream stream = new FileInputStream(filePath)) { FileChannel fc = stream.getChannel(); MappedByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()); return Charset.defaultCharset().decode(bb).toString(); } catch (IOException e) { e.printStackTrace(); } } return null; }
注意事项
- Android 10(API 29)可通过在
AndroidManifest.xml中添加android:requestLegacyExternalStorage="true"暂时绕过Scoped Storage,但该属性在Android 11及以上系统无效
内容的提问来源于stack exchange,提问作者can
相关产品推荐
相关产品推荐

