我已经实现了一种方法,供用户使用Storage Access Framework将我的应用创建的文件保存/导出到任何位置。架构是:
该文件是包含自定义数据的自定义文件扩展名,因此不是标准文件类型或mime类型。 我正在使用插有SD卡的三星Galaxy S7。所以它不支持Adoptable Storage。对于测试/开发,我使用My Files系统应用程序打开文件和带有MTP的Windows PC从设备中提取文件。
此架构/代码在以下情况下运行良好:
如果SD卡已加密,我开始遇到奇怪的问题。
问题1:“我的文件”系统应用程序将文件视为大小为0字节,不会打开它。
问题2:Windows PC也将该文件视为大小为0字节,不会通过MTP将其复制到我的PC上。
奇怪的是,ES文件资源管理器可以看到该文件并将其打开。 DropBox可以看到该文件并上传它。如果SD卡未加密,则不存在上述问题1和2。
那么这里发生了什么?我已经尝试了很多东西来排除故障。我的理论是,处理MIME类型和内容URI时会出现一些问题,这些URI在加密或关闭时表现不同 - 特别是关于我的文件和MTP。为什么ES文件资源管理器在查看此文件并打开它时没有问题?
以下是相关的代码段:
private void selectStoragePathExtended() {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
startActivityForResult(intent, REQUEST_CODE_OPEN_DIRECTORY);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CODE_OPEN_DIRECTORY) {
if (resultCode == Activity.RESULT_OK) {
mLocalStorageUri = DocumentsContract.buildDocumentUriUsingTree(data.getData(), DocumentsContract.getTreeDocumentId(data.getData()));
}
}
}
// This will get called with mLocalStorageUri and a File stored in the app's "ExternalFilesDir"
public static void copyFile(ContentResolver cr, File sourceFile, Uri destFolderUri) throws IOException {
if (!sourceFile.exists()) {
return;
}
FileChannel source = null;
FileChannel destination = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
try {
source = new FileInputStream(sourceFile).getChannel();
Uri destUri = DocumentsContract.createDocument(cr, destFolderUri, "*/*", sourceFile.getName());
ParcelFileDescriptor pfd = cr.openFileDescriptor(destUri, "w");
destination = new FileOutputStream(pfd.getFileDescriptor()).getChannel();
if (source.size() > FILE_COPY_MAX_BLOCK) {
// Transfer file in 128MB blocks
long position = 0;
while (destination.transferFrom(source, position, FILE_COPY_MAX_BLOCK) > 0) {
position += FILE_COPY_MAX_BLOCK;
}
} else {
long bytesCopied = destination.transferFrom(source, 0, source.size());
if (bytesCopied != source.size()) {
String errorMsg = String.format("Error: only %d out of %d bytes copied", bytesCopied, source.size());
throw new IOException(errorMsg);
}
}
destination.close();
pfd.close();
}
finally {
if(source != null) {
source.close();
}
if(destination != null) {
destination.close();
}
}
}
}
是的我正在使用FileChannel的非标准文件复制方法,但我已经使用基本的FileOutputStreams和其他具有相同结果的方法进行了测试。此外,请记住,行为是正常的,并关闭SD卡加密。它实际上可以使用加密,但My Files和Windows MTP都无法读取文件。仅限第三方工具,如ES文件资源管理器和DropBox。
有什么想法吗?必须是mime类型/ URI问题?