在我的应用程序中,我使用以下意图获得SD卡写入权限。如果用户从系统文件资源管理器中选择sd卡文件夹,那么我有SD卡写访问权限。
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
intent.putExtra("android.content.extra.SHOW_ADVANCED", true);
startActivityForResult(intent, 42);
之后我可以使用DocumentFile类修改SD卡中的文件。但是我在为随机文件路径获取DocumentFile时遇到了问题。
Document.fromFile(new File(path));
Document.fromSingleUri(Uri.fromFile(new File(path)));
都返回一个在.canWrite()上返回false的DocumentFile对象。即使我已经获得SD卡许可。
所以我编写了在我的问题末尾发布的方法,以获得一个在.canWrite()上返回true的DocumentFile。但这很慢......而且感觉非常错误!必须有更好的方法来做到这一点。我还写了一个返回与
相同的字符串的方法String docFileUriString = docFile.getUri().toString();
对于任何文件,其中docFile是由下面的方法返回的DocumentFile。但是
DocumentFile.fromTreeUri(Uri.parse(docFileUriString ));
返回一个DocumentFile,它指向sd卡的根,而不是DocumentFile路径。这很奇怪。有人可以提出更优雅的解决方案吗?
public static DocumentFile getDocumentFileIfAllowedToWrite(File file, Context con){
List<UriPermission> permissionUris = con.getContentResolver().getPersistedUriPermissions();
for(UriPermission permissionUri:permissionUris){
Uri treeUri = permissionUri.getUri();
DocumentFile rootDocFile = DocumentFile.fromTreeUri(con, treeUri);
String rootDocFilePath = FileUtil.getFullPathFromTreeUri(treeUri, con);
if(file.getAbsolutePath().startsWith(rootDocFilePath)){
ArrayList<String> pathInRootDocParts = new ArrayList<String>();
while(!rootDocFilePath.equals(file.getAbsolutePath())){
pathInRootDocParts.add(file.getName());
file = file.getParentFile();
}
DocumentFile docFile = null;
if(pathInRootDocParts.size()==0){
docFile = DocumentFile.fromTreeUri(con, rootDocFile.getUri());
}
else{
for(int i=pathInRootDocParts.size()-1;i>=0;i--){
if(docFile==null){docFile = rootDocFile.findFile(pathInRootDocParts.get(i));}
else{docFile = docFile.findFile(pathInRootDocParts.get(i)); }
}
}
if(docFile!=null && docFile.canWrite()){
return docFile;
}else{
return null;
}
}
}
return null;
}
答案 0 :(得分:1)
Document.fromFile(File)
在最近的设备上似乎无法为此目的正常工作
这是答案的链接,我获得了有关该问题的最多信息 https://stackoverflow.com/a/26765884/971355
关键步骤是:
获得对 SD 卡的写访问权限,并使其在手机重启后保持不变
public void onActivityResult(int requestCode, int resultCode, Intent resultData) {
...
getContentResolver().takePersistableUriPermission(treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
}
之后,无论文件和文件夹嵌套多深,您都可以访问它们,但您必须了解您必须处理的复杂 URL。
如果你像我一样是一个 linux 人,并且曾经认为一切都是一个文件,一切都很简单。这次不是。
SD 卡上的文件,例如 /storage/13E5-2604/testDir/test.txt
其中 13E5-2604
是您的 SD 卡根文件夹:
content://com.android.externalstorage.documents/tree/13E5-2604%3A/document/13E5-2604%3A%2FtestDir%2Ftest.txt
在新现实中。为什么他们做得这么复杂 - 是另一个问题......
我不知道有一种 API 方法可以透明且轻松地将普通的 linux 路径转换为这个新现实路径。但是在您完成之后(%3A
是 : 和 %2F
是/参见 https://www.w3schools.com/tags/ref_urlencode.ASP 以供参考)您可以轻松创建 DocumentFile
的实例:
DocumentFile txtFile = DocumentFile.fromSingleUri(context,
Uri.parse("content://com.android.externalstorage.documents/tree/13E5-2604%3A/document/13E5-2604%3A%2FtestDir%2Ftest.txt"));
并写信给它。
答案 1 :(得分:0)
回应@AndiMar(3月21日),我只是检查它是否存在于内部存储器上,如果它不需要担心。
try {
if (sourcefile.toString().contains(Environment.getExternalStorageDirectory().toString())) {
if (sourcefile.exists()) {
sourcefile.delete();
}
} else {
FileUtilities fio = new FileUtilities();
DocumentFile filetodelete = fio.getDocumentFileIfAllowedToWrite(sourcefile, context);
if (filetodelete.exists()) {
filetodelete.delete();
}
}
} catch (Exception e) {
e.printStackTrace();
}