如何使用 ACTION_OPEN_DOCUMENT_TREE 将临时文件保存到外部存储?
How to save Tempfile to External storage using ACTION_OPEN_DOCUMENT_TREE?
使用 ACTION_OPEN_DOCUMENT_TREE 选择文件夹后无法将 zip 文件保存到外部存储器。
我正在创建一个创建和操作文件和文档的项目,在该任务中我想将这些东西保存在外部存储中,但我无法使用 android 开发人员文档来做到这一点,所以请解释另外。
我要保存这个文件
/data/user/0/com.mobilix.docscanner/cache/abc.zip
到
content://com.android.externalstorage.documents/tree/primary%3ADocument
我该怎么办?
这是我的代码,
- 选择用于保存文件的目录的代码。
saveBinding.btnInternalStorage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
startActivityForResult(intent, PICKER_RESULT);
}
});
-选择目录后执行的代码,
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
if (requestCode == PICKER_RESULT) {
if (data != null) {
Uri uri = data.getData();
String path = uri.getPath();
Log.d(TAG, "onActivityResult: uri -> " + uri);
Log.d(TAG, "onActivityResult: path -> " + path);
getContentResolver().takePersistableUriPermission(
uri,
Intent.FLAG_GRANT_READ_URI_PERMISSION
);
new BgExecuter().execute(new Runnable() {
@Override
public void run() {
FileManager.saveFile(PDFTools.this,selectedFile, Uri); //selectedFile is that file that is saved by default in the Temp directory
}
});
}
}else {
Toast.makeText(PDFTools.this, "dome thing happen great", Toast.LENGTH_SHORT).show();
}
}
}
方法保存文件
public static void saveFile(Activity context, File selectedFile, Uri uri) {
context.getContentResolver().getPersistedUriPermissions();
try {
InputStream inputStream = context.getContentResolver().openInputStream(Uri.fromFile(selectedFile));
OutputStream outputStream = context.getContentResolver().openOutputStream(uri);
// get the content in bytes
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream);
byte[] byteArray = new byte[1024];
BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
try {
byte bytes = (byte) bufferedInputStream.read(byteArray);
if (bytes >= 0) {
bufferedOutputStream.write(byteArray, 0, bytes);
bufferedOutputStream.flush();
}
inputStream.close();
outputStream.close();
bufferedOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
String path = uri.getPath();
不不不
你的 uri 不错。使用它。
为此树 uri 创建一个 DocumentFile 实例。
然后使用DocumentFile.createFile()。
所以要求文件而不是目录对用户更好并减少覆盖问题。
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
// Create a file with the requested MIME type.
intent.setType(mimeType);
// Suggest a filename
intent.putExtra(Intent.EXTRA_TITLE, "abc.zip");
// You can suggest a starting directory here see note about this later
//intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, pickerInitialUri);
// OK, this is deprecated and user probably has set their own request code
startActivityForResult(intent, 601);
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent resultData) {
super.onActivityResult(requestCode, resultCode, resultData);
if (requestCode == 601 && resultCode == RESULT_OK) {
// The document selected by the user won't be returned in the intent.
// Instead, a URI to that document will be contained in the return intent
// provided to this method as a parameter.
// Pull that URI using resultData.getData().
Uri uri;
if (resultData != null) {
uri = resultData.getData();
new BgExecuter().execute(new Runnable() {
@Override
public void run() {
// Now that the Uri returned is for a file not a directory, your exist "saveFile" method should work
copyFileOut(PDFTools.this, selectedFile, Uri);
//selectedFile is that file that is saved by default in the Temp directory
}
});
}
}
}
private Boolean copyFileOut(Context context,File copyFile, Uri uri){
BufferedInputStream bis;
BufferedOutputStream bos = null;
// Now read the file
try{
InputStream input = new FileInputStream(copyFile);
int originalSize = input.available();
bis = new BufferedInputStream(input);
bos = new BufferedOutputStream(context.getContentResolver().openOutputStream(uri));
byte[] buf = new byte[originalSize];
//noinspection ResultOfMethodCallIgnored
bis.read(buf);
do {
bos.write(buf);
} while (bis.read(buf) != -1);
bis.close();
} catch (Exception e) {
if (BuildConfig.LOG) {
Log.e(Constants.TAG, "copyFileOut:" + e);
}
// Notify User of fail
return false;
} finally {
try {
if (bos != null) {
bos.flush();
bos.close();
}
} catch (Exception ignored) {
}
}
return true;
}
有关初始启动目录的说明,请参阅
另请注意,在您的“saveFile”方法中
InputStream inputStream = context.getContentResolver().openInputStream(Uri.fromFile(selectedFile));
可以替换为
InputStream inputStream = new FileInputStream(selectedFile);
正如你说的这个文件在你的Apps私有缓存目录中,所以不会有任何权限问题。
使用 ACTION_OPEN_DOCUMENT_TREE 选择文件夹后无法将 zip 文件保存到外部存储器。
我正在创建一个创建和操作文件和文档的项目,在该任务中我想将这些东西保存在外部存储中,但我无法使用 android 开发人员文档来做到这一点,所以请解释另外。
我要保存这个文件
/data/user/0/com.mobilix.docscanner/cache/abc.zip
到
content://com.android.externalstorage.documents/tree/primary%3ADocument
我该怎么办?
这是我的代码,
- 选择用于保存文件的目录的代码。
saveBinding.btnInternalStorage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
startActivityForResult(intent, PICKER_RESULT);
}
});
-选择目录后执行的代码,
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
if (requestCode == PICKER_RESULT) {
if (data != null) {
Uri uri = data.getData();
String path = uri.getPath();
Log.d(TAG, "onActivityResult: uri -> " + uri);
Log.d(TAG, "onActivityResult: path -> " + path);
getContentResolver().takePersistableUriPermission(
uri,
Intent.FLAG_GRANT_READ_URI_PERMISSION
);
new BgExecuter().execute(new Runnable() {
@Override
public void run() {
FileManager.saveFile(PDFTools.this,selectedFile, Uri); //selectedFile is that file that is saved by default in the Temp directory
}
});
}
}else {
Toast.makeText(PDFTools.this, "dome thing happen great", Toast.LENGTH_SHORT).show();
}
}
}
方法保存文件
public static void saveFile(Activity context, File selectedFile, Uri uri) {
context.getContentResolver().getPersistedUriPermissions();
try {
InputStream inputStream = context.getContentResolver().openInputStream(Uri.fromFile(selectedFile));
OutputStream outputStream = context.getContentResolver().openOutputStream(uri);
// get the content in bytes
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream);
byte[] byteArray = new byte[1024];
BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
try {
byte bytes = (byte) bufferedInputStream.read(byteArray);
if (bytes >= 0) {
bufferedOutputStream.write(byteArray, 0, bytes);
bufferedOutputStream.flush();
}
inputStream.close();
outputStream.close();
bufferedOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
String path = uri.getPath();
不不不
你的 uri 不错。使用它。
为此树 uri 创建一个 DocumentFile 实例。
然后使用DocumentFile.createFile()。
所以要求文件而不是目录对用户更好并减少覆盖问题。
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
// Create a file with the requested MIME type.
intent.setType(mimeType);
// Suggest a filename
intent.putExtra(Intent.EXTRA_TITLE, "abc.zip");
// You can suggest a starting directory here see note about this later
//intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, pickerInitialUri);
// OK, this is deprecated and user probably has set their own request code
startActivityForResult(intent, 601);
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent resultData) {
super.onActivityResult(requestCode, resultCode, resultData);
if (requestCode == 601 && resultCode == RESULT_OK) {
// The document selected by the user won't be returned in the intent.
// Instead, a URI to that document will be contained in the return intent
// provided to this method as a parameter.
// Pull that URI using resultData.getData().
Uri uri;
if (resultData != null) {
uri = resultData.getData();
new BgExecuter().execute(new Runnable() {
@Override
public void run() {
// Now that the Uri returned is for a file not a directory, your exist "saveFile" method should work
copyFileOut(PDFTools.this, selectedFile, Uri);
//selectedFile is that file that is saved by default in the Temp directory
}
});
}
}
}
private Boolean copyFileOut(Context context,File copyFile, Uri uri){
BufferedInputStream bis;
BufferedOutputStream bos = null;
// Now read the file
try{
InputStream input = new FileInputStream(copyFile);
int originalSize = input.available();
bis = new BufferedInputStream(input);
bos = new BufferedOutputStream(context.getContentResolver().openOutputStream(uri));
byte[] buf = new byte[originalSize];
//noinspection ResultOfMethodCallIgnored
bis.read(buf);
do {
bos.write(buf);
} while (bis.read(buf) != -1);
bis.close();
} catch (Exception e) {
if (BuildConfig.LOG) {
Log.e(Constants.TAG, "copyFileOut:" + e);
}
// Notify User of fail
return false;
} finally {
try {
if (bos != null) {
bos.flush();
bos.close();
}
} catch (Exception ignored) {
}
}
return true;
}
有关初始启动目录的说明,请参阅
另请注意,在您的“saveFile”方法中
InputStream inputStream = context.getContentResolver().openInputStream(Uri.fromFile(selectedFile));
可以替换为
InputStream inputStream = new FileInputStream(selectedFile);
正如你说的这个文件在你的Apps私有缓存目录中,所以不会有任何权限问题。