如何使用 Scoped Storage 访问特定文件夹并将文件写入其中
How to gain access to a specific folder and write a file into it using Scoped Storage
我的应用程序具有将 txt 格式的 GPS 数据导出到共享文件夹(现在可以通过 getExternalStorageDirectory
访问)的功能,我必须将其切换到分区存储 (API 30)。
(作为信息,该应用程序是 Android 的开源 GPS Logger。)
以后我会让用户选择用于导出的文件夹,使用:
public void openDirectory(Uri uriToLoad) {
// Choose a directory using the system's file picker.
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
startActivityForResult(intent, your-request-code);
}
public void onActivityResult(int requestCode, int resultCode,
Intent resultData) {
if (requestCode == your-request-code && resultCode == Activity.RESULT_OK) {
// The result data contains a URI for the directory that the user selected.
Uri uri = null;
if (resultData != null) {
uri = resultData.getData();
// Perform operations on the document using its URI.
}
}
}
这样我的应用程序将获得对所选文件夹的访问权限。
如何在该文件夹中创建文本文件并使用 BufferedWriter
写入数据?
我知道也许我可以使用类似的东西:
...
Uri fileUri = // Something related to the previous uri, but I cannot find the solution
OutputStream outputStream = getContentResolver().openOutputStream(fileUri, "rw");
txtBW = new BufferedWriter(new OutputStreamWriter(outputStream));
...
但我发现没有任何效果。
DocumentFile
是 Google 在文档树中导航的有点笨拙的解决方案。你想要的食谱应该是:
- 把你为你的树得到的
Uri
用 DocumentFile.fromTreeUri()
包裹在 DocumentFile
中
- 在
DocumentFile
上调用 createFile()
,提供文件名或其他显示名称,这将为您提供代表该文档的 DocumentFile
- 在文档的
DocumentFile
上调用 getUri()
以获得代表文档的 Uri
- 在
ContentResolver
上使用 openOutputStream()
将您想要的内容写入 Uri
请注意,如果您需要长期访问此树,请务必call takePersistableUriPermission()
on a ContentResolver
,为文档树传入Uri
。这应该可以让您访问树及其中的所有文档。
1-你可以像这样创建一个目标路径(我的目标是“Android/media”文件夹)
private const val ROOT_FOLDER = "primary:"
private const val ANDROID_MEDIA = "${ROOT_FOLDER}Android/media"
private const val EXTERNAL_STORAGE_PROVIDER_AUTHORITY = "com.android.externalstorage.documents"
2- 创建 URI 和意图对象
val storageManager = getSystemService(Context.STORAGE_SERVICE) as StorageManager
val uri =DocumentsContract.buildDocumentUri(EXTERNAL_STORAGE_PROVIDER_AUTHORITY,
ANDROID_MEDIA)
val intent = storageManager.primaryStorageVolume.createOpenDocumentTreeIntent()
.putExtra(DocumentsContract.EXTRA_INITIAL_URI,uri)
3- 注册 activity 以获得结果
例如
private val openDocumentTreeLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
if (it.resultCode == RESULT_OK) {
val data: Uri = it.data?.data!!
contentResolver.takePersistableUriPermission(
data,
Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
)}
最终启动 Activity 结果
openDocumentTreeLauncher.launch(intent)
我的应用程序具有将 txt 格式的 GPS 数据导出到共享文件夹(现在可以通过 getExternalStorageDirectory
访问)的功能,我必须将其切换到分区存储 (API 30)。
(作为信息,该应用程序是 Android 的开源 GPS Logger。)
以后我会让用户选择用于导出的文件夹,使用:
public void openDirectory(Uri uriToLoad) {
// Choose a directory using the system's file picker.
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
startActivityForResult(intent, your-request-code);
}
public void onActivityResult(int requestCode, int resultCode,
Intent resultData) {
if (requestCode == your-request-code && resultCode == Activity.RESULT_OK) {
// The result data contains a URI for the directory that the user selected.
Uri uri = null;
if (resultData != null) {
uri = resultData.getData();
// Perform operations on the document using its URI.
}
}
}
这样我的应用程序将获得对所选文件夹的访问权限。
如何在该文件夹中创建文本文件并使用 BufferedWriter
写入数据?
我知道也许我可以使用类似的东西:
...
Uri fileUri = // Something related to the previous uri, but I cannot find the solution
OutputStream outputStream = getContentResolver().openOutputStream(fileUri, "rw");
txtBW = new BufferedWriter(new OutputStreamWriter(outputStream));
...
但我发现没有任何效果。
DocumentFile
是 Google 在文档树中导航的有点笨拙的解决方案。你想要的食谱应该是:
- 把你为你的树得到的
Uri
用DocumentFile.fromTreeUri()
包裹在 - 在
DocumentFile
上调用createFile()
,提供文件名或其他显示名称,这将为您提供代表该文档的DocumentFile
- 在文档的
DocumentFile
上调用getUri()
以获得代表文档的Uri
- 在
ContentResolver
上使用openOutputStream()
将您想要的内容写入Uri
DocumentFile
中
请注意,如果您需要长期访问此树,请务必call takePersistableUriPermission()
on a ContentResolver
,为文档树传入Uri
。这应该可以让您访问树及其中的所有文档。
1-你可以像这样创建一个目标路径(我的目标是“Android/media”文件夹)
private const val ROOT_FOLDER = "primary:"
private const val ANDROID_MEDIA = "${ROOT_FOLDER}Android/media"
private const val EXTERNAL_STORAGE_PROVIDER_AUTHORITY = "com.android.externalstorage.documents"
2- 创建 URI 和意图对象
val storageManager = getSystemService(Context.STORAGE_SERVICE) as StorageManager
val uri =DocumentsContract.buildDocumentUri(EXTERNAL_STORAGE_PROVIDER_AUTHORITY,
ANDROID_MEDIA)
val intent = storageManager.primaryStorageVolume.createOpenDocumentTreeIntent()
.putExtra(DocumentsContract.EXTRA_INITIAL_URI,uri)
3- 注册 activity 以获得结果
例如
private val openDocumentTreeLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
if (it.resultCode == RESULT_OK) {
val data: Uri = it.data?.data!!
contentResolver.takePersistableUriPermission(
data,
Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
)}
最终启动 Activity 结果
openDocumentTreeLauncher.launch(intent)