gpt4 book ai didi

java - ContentResolver.openOutputStream() 抛出 FileNotFoundException

转载 作者:行者123 更新时间:2023-11-30 00:08:32 25 4
gpt4 key购买 nike

我的目的是能够在 Android 21+ 上编辑可移动外部存储上的文件。为此,必须使用存储访问框架。

首先我授予了我感兴趣的文件夹的读写权限:

startActivityForResult(new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE), 123);

@Override
public void onActivityResult(int requestCode,int resultCode,Intent resultData) {
if (resultCode != RESULT_OK)
return;
Uri treeUri = resultData.getData();

PreferenceUtils.setPersistedUri(this, treeUri);

grantUriPermission(getPackageName(), treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
getContentResolver().takePersistableUriPermission(treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
}

我确信这是正确完成的,因为我仔细检查了它:

for(UriPermission uri : getContentResolver().getPersistedUriPermissions())
if(uri.isReadPermission() && uri.isWritePermission())
// This prints the correct folder

如果相关,我还在 list 中声明并请求了 READ_EXTERNAL_STORAGEWRITE_EXTERNAL_STORAGE 的运行时权限。

DocumentFile parentDocumentFile = DocumentFile.fromTreeUri(getActivity(), PreferenceUtils.getPersistedUri());
if(parentDocumentFile == null) return;
for(DocumentFile file : parentDocumentFile.listFiles()) {
if(file.canRead() && file.canWrite() && file.exists()) {
try
{
OutputStream outStream = getActivity().getContentResolver().openOutputStream(file.getUri());

// I/O operations
} (catch FileNotFoundException e) {}
}
}

在代码的后面,我获得了对我感兴趣的文件的引用,该文件的内容 URI 由 DocumentFile 包装。我想强调 DocumentFile.exists()DocumentFile.canRead()DocumentFile.canWrite() 返回肯定结果,也是检查使用系统 File.exists() 已经完成。例如,我通过 DocumentFile.getUri() 获得的 URI 如下所示:

content://com.android.externalstorage.documents/tree/486E-2542%3A/document/486E-2542%3ADownload%2FFildoDownloads%2FLed%20Zeppelin%2FLed%20Zeppelin%20-%20Kashmir.mp3

好的。但是如果我想打开它进行写入,我不能,这是唯一可用的写入文件的方法,该文件的权限是通过存储访问框架授予的:

OutputStream outStream = getContentResolver().openOutputStream(DocumentFile.getUri());

一些设备(我无法重现)抛出一个 FileNotFoundExcpetion 并带有以下堆栈跟踪:

java.io.FileNotFoundException: Failed opening content provider: content://com.android.externalstorage.documents/tree/486E-2542%3A/document/486E-2542%3ADownload%2FFildoDownloads%2FLed%20Zeppelin%2FLed%20Zeppelin%20-%20Kashmir.mp3
at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:1032)
at android.content.ContentResolver.openOutputStream(ContentResolver.java:718)
at android.content.ContentResolver.openOutputStream(ContentResolver.java:694)
at helpers.c.b(SourceFile:405)

一些其他的:

java.io.FileNotFoundException: Failed to open for writing: java.io.FileNotFoundException: Read-only file system
at android.database.DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(DatabaseUtils.java:144)
at android.content.ContentProviderProxy.openAssetFile(ContentProviderNative.java:621)
at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:1011)
at android.content.ContentResolver.openOutputStream(ContentResolver.java:753)
at android.content.ContentResolver.openOutputStream(ContentResolver.java:729)
at helpers.c.b(SourceFile:405)

这种情况不经常发生,比方说 200 台设备中大约有 1 台设备,但它仍然是一个相关问题,因为它破坏了应用程序的主要用途,因此用户可以将其卸载。 p>

StackOverflow 上所有过去的问题看起来都与此类似,但那里的解决方案是不写入存储的根目录,这显然不是这里的问题。在这种特定情况下,我真的不知道这些异常,所以我可能会问是否有人知道可能无法获得具有文件写访问权限的文件描述符的情况。

最佳答案

异常中的消息显示“只读文件系统”。该消息通常与 native 错误号 "EROFS" 相关联,当 Linux 进程试图打开只读存储上的文件进行写入时,就会发生这种情况。

存储可以以只读方式挂载的原因有多种。例如,在严重数据损坏的情况下,大多数文件系统会被内核自动重新挂载为只读(Android 系统甚至可能没有意识到,设备 SD 卡已切换到只读模式)。

也有可能是因为Android系统代码的bug。在这种情况下,了解设备供应商和型号可能有助于调试。

最简单的解决方法:如果写入失败,尝试以只读模式打开文件。如果只读打开成功,问题可能可以通过弹出并重新插入 SD 卡来解决(这应该会导致 Android 自动在其上运行 fsck)。

Uri uri = file.getUri();

try (OutputStream o = context.getContentResolver().openOutputStream(uri))
{
// I/O operations
} (catch FileNotFoundException e) {
try (OutputStream s = context.getContentResolver().openInputStream(uri)) {
// the file can be opened for reading, but not for writing
// ask user to reinsert SD card and/or disable
// write protection toggle on it
Toast.makeText(context, "Please reinsert SD card", LENGTH_SHORT);
} catch (FileNotFoundException err) {
// This is hopeless, just report error to user
Toast.makeText(context, err.toString(), LENGTH_SHORT);
}
}

如果你想确定一个文件系统是否真的以只读方式挂载,考虑从特殊文件 /proc/self/mountinfo 中读取。您可以将它的内容发送给 Crashlytics 进行调试,甚至 parse them in your code .您可以从 Linux kernel documentation 了解有关每个进程 mountinfo 文件的更多信息.

关于java - ContentResolver.openOutputStream() 抛出 FileNotFoundException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48560028/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com