问题
I am trying to find method which can handle create and copy of any file except Media files (Picture/Video/Audio) to copy from one place to other in internal storage in Android Q. In this I have my file created in my app folder and I want those to move to Download Folder or some directory which I can create in Internal storage and then move their.
I searched and found modified below code but missing some thing to make it workable. Can some one help.
ContentResolver contentResolver = getContentResolver();
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, "sam.txt");
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "text/plain");
contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS);
Uri uri = contentResolver.insert(MediaStore.Files.getContentUri("external"), contentValues);
try {
InputStream inputStream = contentResolver.openInputStream(uri);
OutputStream outputStream = new FileOutputStream(Environment.DIRECTORY_DOWNLOADS+"/");
byte[] buffer = new byte[1024];
int length;
//copy the file content in bytes
while ((length = inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, length);
}
inputStream.close();
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
Is above complete code as I'm getting error 'Unknown URL'. What is missing? Please help.
回答1:
As you mentioned Environment.getExternalStoragePublicDirectory
is marked deprecated. So there is no regular way to get the path to Downloads directory to save your file there. Alternatively you can use ACTION_CREATE_DOCUMENT to show path picker and then use returned uri to write file to selected location.
This is how to show picker:
// Request code for creating a document.
const val CREATE_FILE = 1
private fun createFile(pickerInitialUri: Uri) {
val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
type = "text/plain"
putExtra(Intent.EXTRA_TITLE, "sam.txt")
// Optionally, specify a URI for the directory that should be opened in
// the system file picker before your app creates the document.
putExtra(DocumentsContract.EXTRA_INITIAL_URI, pickerInitialUri)
}
startActivityForResult(intent, CREATE_FILE)
}
And this is how to get selected uri and write file:
override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
if (requestCode == CREATE_FILE && resultCode == Activity.RESULT_OK) {
// The result data contains a URI for the document or directory that
// the user selected.
resultData?.data?.also { outputUri ->
// Perform operations on the document using its URI.
FileInputStream(inputFile).use { inputStream ->
context.contentResolver.openFileDescriptor(outputUri, "w")?.use {
FileOutputStream(it.fileDescriptor).use { outputStream ->
FileUtils.copy(inputStream, outputStream)
}
}
}
}
}
}
More information can be found here.
EDIT:
To pick a directory to persist files ACTION_OPEN_DOCUMENT_TREE can be used. Then use takePersistableUriPermission method to take granted persistable permission to be able to use it after device restart. And then use DocumentFile to execute file operations.
Open directory request:
private static final int OPEN_DIRECTORY_REQUEST_CODE = 1;
void openDirectory() {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
startActivityForResult(intent, OPEN_DIRECTORY_REQUEST_CODE);
}
Receive picked directory and take persistable permission:
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == OPEN_DIRECTORY_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
Uri directoryUri = data.getData();
if (directoryUri == null)
return;
requireContext()
.getContentResolver()
.takePersistableUriPermission(directoryUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
// persist picked uri to be able to reuse it later
} else
super.onActivityResult(requestCode, resultCode, data);
}
And at last persist the file:
private void persistFile(@NonNull Uri directoryUri,
@NonNull File fileToPersist,
@NonNull String mimeType,
@NonNull String displayName) {
DocumentFile dirFile = DocumentFile.fromSingleUri(requireContext(), directoryUri);
if (dirFile != null) {
DocumentFile file = dirFile.createFile(mimeType, displayName);
if (file != null) {
Uri outputUri = file.getUri();
try (ParcelFileDescriptor fd = requireContext().getContentResolver().openFileDescriptor(outputUri, "w")) {
if (fd != null) {
try (FileInputStream inputStream = new FileInputStream(fileToPersist)) {
try (FileOutputStream outputStream = new FileOutputStream(fd.getFileDescriptor())) {
FileUtils.copy(inputStream, outputStream);
}
}
}
} catch (Throwable th) {
th.printStackTrace();
}
}
}
}
Review this repo for an example of ACTION_CREATE_DOCUMENT
usage.
来源:https://stackoverflow.com/questions/59511147/create-copy-file-in-android-q-using-mediastore