Android有什么办法可以在SD卡上随便写吗?
Is there any way to write wherever I want on a SD card in Android?
自 KitKat 以来,我在 Android 和 SD 卡上阅读了很多东西。但最终,我找不到一个明确的全局答案,所以我会尝试从你们那里得到一个相关的答案。
我想在 SD 卡的任意位置写入一个文件,一个文本文件。
让我们用这个简单的例子来关注Android6。清单中存在写入权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
我有这个辅助方法
private void writeFile(File parent)
{
try
{
File f = new File(parent, "test.txt");
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream(f));
outputStreamWriter.write("test");
outputStreamWriter.close();
Log.i(TAG, "File created : " + f.getAbsolutePath());
}
catch (IOException e)
{
Log.e(TAG, "File write failed", e);
}
}
并在测试中 Activity :
if (Build.VERSION.SDK_INT >= 23)
{
if (ContextCompat.checkSelfPermission(MainActivity.this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED
|| ContextCompat.checkSelfPermission(MainActivity.this, android.Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)
{
ActivityCompat.requestPermissions(MainActivity.this, new String[] {
android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
android.Manifest.permission.READ_EXTERNAL_STORAGE }, 1);
}
else
{
File path = getExternalFilesDirs(Environment.DIRECTORY_PICTURES)[1];
writeFile(path);
path = getExternalFilesDirs(null)[1];
writeFile(path);
writeFile(new File("/storage/3635-3533/"));
}
}
/!\ 是的,通过正确检索 SD 卡路径对第 3 次测试的路径进行了硬编码 /!\
首次启动,permission asked,一切正常(抱歉法国设备)
第二次发射,结果如下
10-03 12:40:10.414: I/TESTSDCARD(26006): File created : /storage/3635-3533/Android/data/com.example.testsdcard/files/Pictures/test.txt
10-03 12:40:10.415: I/TESTSDCARD(26006): File created : /storage/3635-3533/Android/data/com.example.testsdcard/files/test.txt
10-03 12:40:10.426: E/TESTSDCARD(26006): File write failed
10-03 12:40:10.426: E/TESTSDCARD(26006): java.io.FileNotFoundException: /storage/3635-3533/test.txt: open failed: EACCES (Permission denied)
10-03 12:40:10.426: E/TESTSDCARD(26006): at libcore.io.IoBridge.open(IoBridge.java:459)
10-03 12:40:10.426: E/TESTSDCARD(26006): at java.io.FileOutputStream.<init>(FileOutputStream.java:87)
10-03 12:40:10.426: E/TESTSDCARD(26006): at java.io.FileOutputStream.<init>(FileOutputStream.java:72)
10-03 12:40:10.426: E/TESTSDCARD(26006): at com.example.testsdcard.MainActivity.writeFile(MainActivity.java:61)
10-03 12:40:10.426: E/TESTSDCARD(26006): at com.example.testsdcard.MainActivity.onCreate(MainActivity.java:50)
10-03 12:40:10.426: E/TESTSDCARD(26006): at android.app.Activity.performCreate(Activity.java:6367)
10-03 12:40:10.426: E/TESTSDCARD(26006): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1110)
10-03 12:40:10.426: E/TESTSDCARD(26006): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2397)
10-03 12:40:10.426: E/TESTSDCARD(26006): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2504)
10-03 12:40:10.426: E/TESTSDCARD(26006): at android.app.ActivityThread.access0(ActivityThread.java:165)
10-03 12:40:10.426: E/TESTSDCARD(26006): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1368)
10-03 12:40:10.426: E/TESTSDCARD(26006): at android.os.Handler.dispatchMessage(Handler.java:102)
10-03 12:40:10.426: E/TESTSDCARD(26006): at android.os.Looper.loop(Looper.java:150)
10-03 12:40:10.426: E/TESTSDCARD(26006): at android.app.ActivityThread.main(ActivityThread.java:5546)
10-03 12:40:10.426: E/TESTSDCARD(26006): at java.lang.reflect.Method.invoke(Native Method)
10-03 12:40:10.426: E/TESTSDCARD(26006): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:794)
10-03 12:40:10.426: E/TESTSDCARD(26006): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:684)
10-03 12:40:10.426: E/TESTSDCARD(26006): Caused by: android.system.ErrnoException: open failed: EACCES (Permission denied)
10-03 12:40:10.426: E/TESTSDCARD(26006): at libcore.io.Posix.open(Native Method)
10-03 12:40:10.426: E/TESTSDCARD(26006): at libcore.io.BlockGuardOs.open(BlockGuardOs.java:186)
10-03 12:40:10.426: E/TESTSDCARD(26006): at libcore.io.IoBridge.open(IoBridge.java:445)
10-03 12:40:10.426: E/TESTSDCARD(26006): ... 16 more
如您所见,使用 getExternalFilesDirs
的两个测试都有效(不足为奇,应该如此)
但是第三次,尝试写入SD卡的根目录,失败了。
我做错了吗?有什么办法可以执行此操作?希望不使用存储访问框架,这对我的应用程序上下文来说真的很痛苦。
此外,存储访问框架是否允许在没有大量代码的情况下对文件执行所有基本操作(写入、删除、重命名...)?
I want to write a file, a text file, on an arbitrary location on the SD card.
这在 Android 4.4+ 附带的设备上是不可能的,除非在 root 设备上。
Write permission is present in the manifest
该权限用于外部存储。外部存储不是移动存储。
Am i doing it wrong ?
是的,只要您没有 read/write 访问可移动存储上任意位置的权限。
does the Storage Access Framework allow to perform every basic operation on file (write, delete, rename...) without a huge amount of code ?
除了您,没有人知道您认为 "a huge amount of code" 是什么。一般来说,如果您获得了用户对一段内容(或其容器)的许可,您可以执行您在 DocumentFile
.
上看到的各种操作
自 KitKat 以来,我在 Android 和 SD 卡上阅读了很多东西。但最终,我找不到一个明确的全局答案,所以我会尝试从你们那里得到一个相关的答案。
我想在 SD 卡的任意位置写入一个文件,一个文本文件。
让我们用这个简单的例子来关注Android6。清单中存在写入权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
我有这个辅助方法
private void writeFile(File parent)
{
try
{
File f = new File(parent, "test.txt");
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream(f));
outputStreamWriter.write("test");
outputStreamWriter.close();
Log.i(TAG, "File created : " + f.getAbsolutePath());
}
catch (IOException e)
{
Log.e(TAG, "File write failed", e);
}
}
并在测试中 Activity :
if (Build.VERSION.SDK_INT >= 23)
{
if (ContextCompat.checkSelfPermission(MainActivity.this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED
|| ContextCompat.checkSelfPermission(MainActivity.this, android.Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)
{
ActivityCompat.requestPermissions(MainActivity.this, new String[] {
android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
android.Manifest.permission.READ_EXTERNAL_STORAGE }, 1);
}
else
{
File path = getExternalFilesDirs(Environment.DIRECTORY_PICTURES)[1];
writeFile(path);
path = getExternalFilesDirs(null)[1];
writeFile(path);
writeFile(new File("/storage/3635-3533/"));
}
}
/!\ 是的,通过正确检索 SD 卡路径对第 3 次测试的路径进行了硬编码 /!\
首次启动,permission asked,一切正常(抱歉法国设备)
第二次发射,结果如下
10-03 12:40:10.414: I/TESTSDCARD(26006): File created : /storage/3635-3533/Android/data/com.example.testsdcard/files/Pictures/test.txt
10-03 12:40:10.415: I/TESTSDCARD(26006): File created : /storage/3635-3533/Android/data/com.example.testsdcard/files/test.txt
10-03 12:40:10.426: E/TESTSDCARD(26006): File write failed
10-03 12:40:10.426: E/TESTSDCARD(26006): java.io.FileNotFoundException: /storage/3635-3533/test.txt: open failed: EACCES (Permission denied)
10-03 12:40:10.426: E/TESTSDCARD(26006): at libcore.io.IoBridge.open(IoBridge.java:459)
10-03 12:40:10.426: E/TESTSDCARD(26006): at java.io.FileOutputStream.<init>(FileOutputStream.java:87)
10-03 12:40:10.426: E/TESTSDCARD(26006): at java.io.FileOutputStream.<init>(FileOutputStream.java:72)
10-03 12:40:10.426: E/TESTSDCARD(26006): at com.example.testsdcard.MainActivity.writeFile(MainActivity.java:61)
10-03 12:40:10.426: E/TESTSDCARD(26006): at com.example.testsdcard.MainActivity.onCreate(MainActivity.java:50)
10-03 12:40:10.426: E/TESTSDCARD(26006): at android.app.Activity.performCreate(Activity.java:6367)
10-03 12:40:10.426: E/TESTSDCARD(26006): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1110)
10-03 12:40:10.426: E/TESTSDCARD(26006): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2397)
10-03 12:40:10.426: E/TESTSDCARD(26006): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2504)
10-03 12:40:10.426: E/TESTSDCARD(26006): at android.app.ActivityThread.access0(ActivityThread.java:165)
10-03 12:40:10.426: E/TESTSDCARD(26006): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1368)
10-03 12:40:10.426: E/TESTSDCARD(26006): at android.os.Handler.dispatchMessage(Handler.java:102)
10-03 12:40:10.426: E/TESTSDCARD(26006): at android.os.Looper.loop(Looper.java:150)
10-03 12:40:10.426: E/TESTSDCARD(26006): at android.app.ActivityThread.main(ActivityThread.java:5546)
10-03 12:40:10.426: E/TESTSDCARD(26006): at java.lang.reflect.Method.invoke(Native Method)
10-03 12:40:10.426: E/TESTSDCARD(26006): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:794)
10-03 12:40:10.426: E/TESTSDCARD(26006): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:684)
10-03 12:40:10.426: E/TESTSDCARD(26006): Caused by: android.system.ErrnoException: open failed: EACCES (Permission denied)
10-03 12:40:10.426: E/TESTSDCARD(26006): at libcore.io.Posix.open(Native Method)
10-03 12:40:10.426: E/TESTSDCARD(26006): at libcore.io.BlockGuardOs.open(BlockGuardOs.java:186)
10-03 12:40:10.426: E/TESTSDCARD(26006): at libcore.io.IoBridge.open(IoBridge.java:445)
10-03 12:40:10.426: E/TESTSDCARD(26006): ... 16 more
如您所见,使用 getExternalFilesDirs
的两个测试都有效(不足为奇,应该如此)
但是第三次,尝试写入SD卡的根目录,失败了。
我做错了吗?有什么办法可以执行此操作?希望不使用存储访问框架,这对我的应用程序上下文来说真的很痛苦。
此外,存储访问框架是否允许在没有大量代码的情况下对文件执行所有基本操作(写入、删除、重命名...)?
I want to write a file, a text file, on an arbitrary location on the SD card.
这在 Android 4.4+ 附带的设备上是不可能的,除非在 root 设备上。
Write permission is present in the manifest
该权限用于外部存储。外部存储不是移动存储。
Am i doing it wrong ?
是的,只要您没有 read/write 访问可移动存储上任意位置的权限。
does the Storage Access Framework allow to perform every basic operation on file (write, delete, rename...) without a huge amount of code ?
除了您,没有人知道您认为 "a huge amount of code" 是什么。一般来说,如果您获得了用户对一段内容(或其容器)的许可,您可以执行您在 DocumentFile
.