我正在创建一个Android应用程序,允许用户使用SAF将一些文件从内部存储器传输到外部存储器(SD卡)。
这就是我打算让用户选择SD卡目录的意图。
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
startActivityForResult(intent, 42);
这是我的onActivityResult
public void onActivityResult(int requestCode, int resultCode, Intent data) {
treeUri = data.getData();
final int takeFlags = data.getFlags()
& (Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
getActivity().getContentResolver().takePersistableUriPermission(treeUri, takeFlags);
}
我正在获取整张SD卡的许可,以便我可以随时移动或删除SD卡中的任何文件。问题是即使在获得许可后我也无法移动或删除SD卡中的任何文件。
如何将文件从内部存储移动到外部(SD卡)以用于Android 5.0及更高版本。
编辑:这是我用来移动文件的代码。
public static void MoveFiles(File src, File dst) throws IOException
{
FileChannel inChannel = new FileInputStream(src).getChannel();
FileChannel outChannel = new FileOutputStream(dst).getChannel();
try
{
inChannel.transferTo(0, inChannel.size(), outChannel);
}
finally
{
if (inChannel != null)
inChannel.close();
if (outChannel != null)
outChannel.close();
src.delete();
}
}
答案 0 :(得分:3)
这就是我最终解决问题的方法。
首先调用一个意图让用户授予整个SD卡的写入权限。
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
startActivityForResult(intent, 42);
然后onActivityResult获取写权限。
public void onActivityResult(int requestCode, int resultCode, Intent data) {
treeUri = data.getData();
final int takeFlags = data.getFlags()
& (Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
getActivity().getContentResolver().takePersistableUriPermission(treeUri, takeFlags);
}
这是我用来将文件复制到SD卡的代码。
public static boolean copy(File copy, String directory, Context con) {
static FileInputStream inStream = null;
static OutputStream outStream = null;
DocumentFile dir= getDocumentFileIfAllowedToWrite(new File(directory), con);
String mime = mime(copy.toURI().toString());
DocumentFile copy1= dir.createFile(mime, copy.getName());
try {
inStream = new FileInputStream(copy);
outStream =
con.getContentResolver().openOutputStream(copy1.getUri());
byte[] buffer = new byte[16384];
int bytesRead;
while ((bytesRead = inStream.read(buffer)) != -1) {
outStream.write(buffer, 0, bytesRead);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
inStream.close();
outStream.close();
return true;
} catch (IOException e) {
e.printStackTrace();
}
}
return false;
}
上面的代码使用以下两种方法。
getDocumentFileIfAllowedToWrite方法,如果允许写入,则返回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;
}
返回文件的mime类型的mime方法。
public static String mime(String URI) {
static String type;
String extention = MimeTypeMap.getFileExtensionFromUrl(URI);
if (extention != null) {
type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extention);
}
return type;
}
我已经使用Android Lollipop和Marshmallow测试了上述代码。
编辑:这是指向FileUtils课程的链接。
答案 1 :(得分:2)
我正在获取整张SD卡的许可,以便我可以随时移动或删除SD卡中的任何文件
不,你不是。您正在使用Storage Access Framework API(例如DocumentFile
)获取用户选择的任何文档树的权限,以便能够使用该文档树。
问题是即使获得许可后我也无法移动或删除SD卡中的任何文件
这是因为您正在尝试使用文件系统API。您无权通过这些API在指定供应用程序访问的特定区域之外使用可移动存储(例如getExternalFilesDirs()
)。
如果您想使用文档树:
Use DocumentFile.fromTreeUri()
创建指向该树根目录的DocumentFile
使用DocumentFile
上的方法查看树的级别是什么,在该树的分支上获取DocumentFile
个对象,在该树的内容上获取DocumentFile
个对象等等。
答案 2 :(得分:0)
我会提供一种更简单的方法。您可以使用扩展函数 DocumentFile.moveFileTo()
:
val sourceFile: DocumentFile = ...
val targetFolder: DocumentFile = DocumentFileCompat.fromSimplePath(context, storageId = "AAAA-BBBB", basePath = "Music")
// replace AAAA-BBBB with your SD card's ID
sourceFile.moveFileTo(context, targetFolder, callback = callback = object : FileCallback {
override fun onConflict(destinationFile: DocumentFile, action: FileCallback.FileConflictAction) {
handleFileConflict(action)
}
override fun onFailed(errorCode: FileCallback.ErrorCode) {
// do stuff
}
override fun onCompleted(file: Any) {
// do stuff
}
})