将文件 PATH 转换为 TreeUri(存储访问框架)
Convert file PATH to TreeUri (Storage Access Framework)
在我的图片库应用程序中,我使用媒体内容提供商图片来扩充回收站视图。长按图像时,我会为用户提供重命名该图像文件的选项。所以我在回收站视图中为每个图像提供了完整的文件路径(例如:- /storage/sdcard1/DCIM/100ANDRO/ak.jpg )。然后我想重命名那个文件。
现在的问题是,由于提供的文件路径是外部 SD 卡的路径,对于 Android 5 及更高版本,需要 SAF(存储访问框架)才能写入文件。
所以通常我们使用此代码使用 SAF 重命名文件:-
public void onActivityResult(int requestCode, int resultCode, Intent resultData){
if (resultCode == RESULT_OK) {
Uri treeUri = resultData.getData();
getContentResolver().takePersistableUriPermission(treeUri,
Intent.FLAG_GRANT_READ_URI_PERMISSION |
Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
DocumentFile pickedDir = DocumentFile.fromTreeUri(this, treeUri);
DocumentFile newFIle = pickedDir.createFile("text/plain","MyFile")
// or rename as
pickedDir.renameTo("fdtd.jpg");
} else {
Log.d("test","NOt OK RESULT");
}
}
但是当我们知道 TreeUri 时就是这种情况。在我的例子中,我知道文件路径,因此想将其转换为 TreeUri。
您必须在 renameTo 方法中设置完整路径。
使用我的例子来工作。
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == RESULT_LOAD_IMAGE && resultCode == RESULT_OK && null != data) {
Uri selectedImage = data.getData();
String[] filePathColumn = {MediaStore.Images.Media.DATA};
Cursor cursor = getContentResolver().query(selectedImage,
filePathColumn, null, null, null);
if (cursor != null) {
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
String picturePath = cursor.getString(columnIndex);
cursor.close();
ImageView imageView = (ImageView) findViewById(R.id.image);
imageView.setOnClickListener(this);
Bitmap bmp = null;
try {
bmp = getBitmapFromUri(selectedImage);
} catch (IOException e) {
e.printStackTrace();
}
imageView.setImageBitmap(bmp);
//get file
File photo = new File(picturePath);
//file name
String fileName = photo.getName();
//resave file with new name
File newFile = new File(photo.getParent() + "/fdtd." + fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length()) );
photo.renameTo(newFile);
}
}
}
请记住,在我的示例中,我考虑保留原始文件的默认扩展名,因为如果您尝试将 PNG 重命名为 JPG,您可能会遇到问题。
要将文件路径转换为 uri,请使用:-
DocumentFile fileuri = DocumentFile.fromFile(new File(filepath));
然后就可以对这个文件uri进行删除、重命名操作了
如果您不想使用 ACTION_OPEN_DOCUMENT_TREE 或 ACTION_OPEN_DOCUMENT 来获取 Uri,您可以使用以下方法将 FILE 转换为 Uri (SAF) 从 API19(Android4.4-Kitkat) 到 API28(Android8-Oreo)。 returned Uri 与 return 对话框相同,并且它对 API 28 安全限制(SAF 权限)有效,如果您想在应用程序之外访问外部可移动存储...
/**
* Ing.N.Nyerges 2019 V2.0
*
* Storage Access Framework(SAF) Uri's creator from File (java.IO),
* for removable external storages
*
* @param context Application Context
* @param file File path + file name
* @return Uri[]:
* uri[0] = SAF TREE Uri
* uri[1] = SAF DOCUMENT Uri
*/
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public static Uri[] getSafUris (Context context, File file) {
Uri[] uri = new Uri[2];
String scheme = "content";
String authority = "com.android.externalstorage.documents";
// Separate each element of the File path
// File format: "/storage/XXXX-XXXX/sub-folder1/sub-folder2..../filename"
// (XXXX-XXXX is external removable number
String[] ele = file.getPath().split(File.separator);
// ele[0] = not used (empty)
// ele[1] = not used (storage name)
// ele[2] = storage number
// ele[3 to (n-1)] = folders
// ele[n] = file name
// Construct folders strings using SAF format
StringBuilder folders = new StringBuilder();
if (ele.length > 4) {
folders.append(ele[3]);
for (int i = 4; i < ele.length - 1; ++i) folders.append("%2F").append(ele[i]);
}
String common = ele[2] + "%3A" + folders.toString();
// Construct TREE Uri
Uri.Builder builder = new Uri.Builder();
builder.scheme(scheme);
builder.authority(authority);
builder.encodedPath("/tree/" + common);
uri[0] = builder.build();
// Construct DOCUMENT Uri
builder = new Uri.Builder();
builder.scheme(scheme);
builder.authority(authority);
if (ele.length > 4) common = common + "%2F";
builder.encodedPath("/document/" + common + file.getName());
uri[1] = builder.build();
return uri;
}
我有类似的问题,但我想我可能有解决办法。根据我使用 Windows MTP api 的经验。这与 Android SAF 非常相似。
使用 SAF android 不希望您直接访问文件,而是为您提供文件 ID。如果您检查 DocumentsContract.Document,您会注意到没有文件路径列,只有显示名称。
但是我认为通过递归我们可以找到匹配的 Uri。对不起,我不能举个例子,但只是简单地使用 SAF api 遍历文件树,直到你得到文件路径的所有分支。
在我的图片库应用程序中,我使用媒体内容提供商图片来扩充回收站视图。长按图像时,我会为用户提供重命名该图像文件的选项。所以我在回收站视图中为每个图像提供了完整的文件路径(例如:- /storage/sdcard1/DCIM/100ANDRO/ak.jpg )。然后我想重命名那个文件。
现在的问题是,由于提供的文件路径是外部 SD 卡的路径,对于 Android 5 及更高版本,需要 SAF(存储访问框架)才能写入文件。
所以通常我们使用此代码使用 SAF 重命名文件:-
public void onActivityResult(int requestCode, int resultCode, Intent resultData){
if (resultCode == RESULT_OK) {
Uri treeUri = resultData.getData();
getContentResolver().takePersistableUriPermission(treeUri,
Intent.FLAG_GRANT_READ_URI_PERMISSION |
Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
DocumentFile pickedDir = DocumentFile.fromTreeUri(this, treeUri);
DocumentFile newFIle = pickedDir.createFile("text/plain","MyFile")
// or rename as
pickedDir.renameTo("fdtd.jpg");
} else {
Log.d("test","NOt OK RESULT");
}
}
但是当我们知道 TreeUri 时就是这种情况。在我的例子中,我知道文件路径,因此想将其转换为 TreeUri。
您必须在 renameTo 方法中设置完整路径。
使用我的例子来工作。
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == RESULT_LOAD_IMAGE && resultCode == RESULT_OK && null != data) {
Uri selectedImage = data.getData();
String[] filePathColumn = {MediaStore.Images.Media.DATA};
Cursor cursor = getContentResolver().query(selectedImage,
filePathColumn, null, null, null);
if (cursor != null) {
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
String picturePath = cursor.getString(columnIndex);
cursor.close();
ImageView imageView = (ImageView) findViewById(R.id.image);
imageView.setOnClickListener(this);
Bitmap bmp = null;
try {
bmp = getBitmapFromUri(selectedImage);
} catch (IOException e) {
e.printStackTrace();
}
imageView.setImageBitmap(bmp);
//get file
File photo = new File(picturePath);
//file name
String fileName = photo.getName();
//resave file with new name
File newFile = new File(photo.getParent() + "/fdtd." + fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length()) );
photo.renameTo(newFile);
}
}
}
请记住,在我的示例中,我考虑保留原始文件的默认扩展名,因为如果您尝试将 PNG 重命名为 JPG,您可能会遇到问题。
要将文件路径转换为 uri,请使用:-
DocumentFile fileuri = DocumentFile.fromFile(new File(filepath));
然后就可以对这个文件uri进行删除、重命名操作了
如果您不想使用 ACTION_OPEN_DOCUMENT_TREE 或 ACTION_OPEN_DOCUMENT 来获取 Uri,您可以使用以下方法将 FILE 转换为 Uri (SAF) 从 API19(Android4.4-Kitkat) 到 API28(Android8-Oreo)。 returned Uri 与 return 对话框相同,并且它对 API 28 安全限制(SAF 权限)有效,如果您想在应用程序之外访问外部可移动存储...
/**
* Ing.N.Nyerges 2019 V2.0
*
* Storage Access Framework(SAF) Uri's creator from File (java.IO),
* for removable external storages
*
* @param context Application Context
* @param file File path + file name
* @return Uri[]:
* uri[0] = SAF TREE Uri
* uri[1] = SAF DOCUMENT Uri
*/
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public static Uri[] getSafUris (Context context, File file) {
Uri[] uri = new Uri[2];
String scheme = "content";
String authority = "com.android.externalstorage.documents";
// Separate each element of the File path
// File format: "/storage/XXXX-XXXX/sub-folder1/sub-folder2..../filename"
// (XXXX-XXXX is external removable number
String[] ele = file.getPath().split(File.separator);
// ele[0] = not used (empty)
// ele[1] = not used (storage name)
// ele[2] = storage number
// ele[3 to (n-1)] = folders
// ele[n] = file name
// Construct folders strings using SAF format
StringBuilder folders = new StringBuilder();
if (ele.length > 4) {
folders.append(ele[3]);
for (int i = 4; i < ele.length - 1; ++i) folders.append("%2F").append(ele[i]);
}
String common = ele[2] + "%3A" + folders.toString();
// Construct TREE Uri
Uri.Builder builder = new Uri.Builder();
builder.scheme(scheme);
builder.authority(authority);
builder.encodedPath("/tree/" + common);
uri[0] = builder.build();
// Construct DOCUMENT Uri
builder = new Uri.Builder();
builder.scheme(scheme);
builder.authority(authority);
if (ele.length > 4) common = common + "%2F";
builder.encodedPath("/document/" + common + file.getName());
uri[1] = builder.build();
return uri;
}
我有类似的问题,但我想我可能有解决办法。根据我使用 Windows MTP api 的经验。这与 Android SAF 非常相似。
使用 SAF android 不希望您直接访问文件,而是为您提供文件 ID。如果您检查 DocumentsContract.Document,您会注意到没有文件路径列,只有显示名称。
但是我认为通过递归我们可以找到匹配的 Uri。对不起,我不能举个例子,但只是简单地使用 SAF api 遍历文件树,直到你得到文件路径的所有分支。