Android 无法对 sd 卡进行写入和删除操作

Posted

技术标签:

【中文标题】Android 无法对 sd 卡进行写入和删除操作【英文标题】:Android couldn't able to write and delete operation on sd card 【发布时间】:2019-01-29 14:03:49 【问题描述】:

我现在正在开发 ImageCompressor 应用程序。

我需要deletewrite(更新)图像文件。在内部存储中完美运行,但 **SD​​ 卡无法让我访问删除和写入文件。

我的应用如何在 sd 卡上进行writedelete 操作(可移动存储)?

没有这个我已经完成了整个项目,所以我必须想办法。

更新:

我已经在研究和讨论这个问题。并且明白我必须使用storage access framework 但我是 SAF 的新手。

我使用来压缩需要File not Uri的照片。为此,我使用Uri -> File 并使用Intent.ACTION_OPEN_DOCUMENT 并从可移动存储中选择图像。

但对于可移动存储,我无法从 uri 中找到 Image Real Path。

我不知道这是否正确。如果有任何方法在 SAF 中我可以使用 uri 压缩图像,请告诉我。或者如何从Removable Storage Photo的uri获取图片真实路径

更新代码 SAF:

//  -----------  Intent  -------------
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*/*");

//  ------------  On Activity Result  --------------
Uri uri = data.getData();
try 
    ParcelFileDescriptor fileDescriptor = getContentResolver().openFileDescriptor(uri, "w");
    FileOutputStream fos = new FileOutputStream(fileDescriptor.getFileDescriptor());

    FileInputStream fis = new FileInputStream(getImageFilePath(uri));

    FileChannel source = fis.getChannel();
    FileChannel destination = fos.getChannel();
    destination.transferFrom(source, 0, source.size());

    fis.close();
    fos.close();
    fileDescriptor.close();
    Toast.makeText(this, "File save successfully.", Toast.LENGTH_SHORT).show();

Uri 到文件路径,我完成了从媒体应用程序(如图库、照片)中选择图像的位置,但是从 sd 卡中选择什么而不是 MediaStore.Images.Media.DATA 我不知道。代码:

private File getImageFilePath(Uri uri) throws IOException 
    String image_id = null, imagePath = null;

    Cursor cursor = getContentResolver().query(uri, null, null, null, null);
    if (cursor != null) 
        cursor.moveToFirst();
        image_id = cursor.getString(0);
        image_id = image_id.substring(image_id.lastIndexOf(":") + 1);
        cursor.close();
    
    cursor = getContentResolver().query(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, MediaStore.Images.Media._ID + " = ? ", new String[]image_id, null);
    if (cursor!=null) 
        cursor.moveToFirst();
        imagePath = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
        cursor.close();
    

    File file = new File(imagePath);
    return new Compressor(this).setQuality(50).compressToFile(file);

【问题讨论】:

您是否尝试过搜索? ***.com/questions/2121833/… @MikeM。是的,我说的是可移动存储。 @BackSlash 问题和答案已经很老了。并且在 5.0 Lolipop android 之后更改了他们的 sd 卡访问策略。 @B001ᛦ 是的,我提供了正确的许可,这就是为什么在手机内存中所有东西都能完美运行的原因。但是 SD 卡有问题。 看看developer.android.com/guide/topics/providers/document-provider 【参考方案1】:

如果您使用 File 和 FileOutputStream 类,可移动 SD 卡只能在现代 Android 设备上写入。

如果你很幸运,那么使用getExternalFilesDirs() 的设备会作为第二项返回卡上的应用特定目录,您仍然可以在其中写入。

对于其余部分,请改用Storage Access Framework。

首先让用户选择带有Intent.ACTION_OPEN_DOCUMENT_TREE 的sd 卡或带有Intent.ACTION_OPEN_DOCUMENT 的文件。

【讨论】:

【参考方案2】:

我挖掘了我的一个旧的 Android 应用程序并检索到这个:

此方法将 sdcard uri 的根目录转换为 File 路径。

public File getRootPath(Context context, Uri sdcardRootUri)

    List<String> pathSegments =  sdcardRootUri.getPathSegments();
    String[] tokens = pathSegments.get(pathSegments.size()-1).split(":");
    for (File f : ContextCompat.getExternalFilesDirs(context, null))
    
        String path = f.getAbsolutePath().substring(0, f.getAbsolutePath().indexOf("/Android/"));
        if (path.contains(tokens[0]))
        
            return new File(path);
        
    
    return null;

为了检索 sdcard 根目录的 uri,我使用了它:

Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
startActivityForResult(intent, SDCARD_ROOT_CODE);

然后用户会选择 sdcard 的根目录,然后我处理结果如下:

protected void onActivityResult(int requestCode, int resultCode, Intent data) 

    if (resultCode == RESULT_OK && requestCode == SDCARD_ROOT_CODE)
    
        // Persist access permissions
        Uri sdcdardRootUri = data.getData();
        grantUriPermission(getPackageName(), sdcdardRootUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        final int takeFlags = data.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        getContentResolver().takePersistableUriPermission(sdcdardRootUri, takeFlags);

        // Do whatever you want with sdcdardRootUri
    

我希望它是您正在寻找的。有了它,您可以读取/写入/删除 sdcard 上所需的任何文件。

【讨论】:

首先很抱歉耽搁了,我很忙。这是我正在寻找的答案。但现在我无法测试这段代码,很明显我会在运行这段代码后通知你。谢谢! 您好,您的getRootPath(Context context, Uri sdcardRootUri) 无法正常工作。这里path 可验证返回/storage/3034-6134 这个字符串是SD 卡路径而不是文件夹文件路径。 是的 sdcard 根路径,只需在下一个文件的相对路径附加 我不专业,你可以说是初学者。我不明白这对我有什么帮助。对于ACTION_OPEN_DOCUMENT_TREE,我需要特定的文件夹文件。我怎么能得到这个?你能为我添加一些代码吗? 例如:File yourFile = new File(getRootPath(context, sdcdardRootUri), "path/to/file/in/sd/card");【参考方案3】:

你试过了

    try 
        Runtime runtime = Runtime.getRuntime();
        Process proc = runtime.exec("mount");
        InputStream is = proc.getInputStream();
        InputStreamReader isr = new InputStreamReader(is);
        String line;
        BufferedReader br = new BufferedReader(isr);
        while ((line = br.readLine()) != null) 
            //Filter common Linux partitions
            if (line.contains("secure"))
                continue;
            if (line.contains("asec"))
                continue;
            if (line.contains("media"))
                continue;
            if (line.contains("system") || line.contains("cache")
                || line.contains("sys") || line.contains("data")
                || line.contains("tmpfs") || line.contains("shell")
                || line.contains("root") || line.contains("acct")
                || line.contains("proc") || line.contains("misc")
                || line.contains("obb")) 
                continue;
            

            if (line.contains("fat") || line.contains("fuse") || (line
                .contains("ntfs"))) 

                String columns[] = line.split(" ");
                if (columns != null && columns.length > 1) 
                    String path = columns[1];
                    if (path!=null&&!SdList.contains(path)&&path.contains("sd"))
                        SdList.add(columns[1]);
                
            
        
     catch (Exception e) 
        // TODO Auto-generated catch block
        e.printStackTrace();
    

【讨论】:

抱歉,我不是在寻找 sd 卡路径。我必须获得对 sd 卡(可移动存储)的删除访问权限。

以上是关于Android 无法对 sd 卡进行写入和删除操作的主要内容,如果未能解决你的问题,请参考以下文章

android中实现向sd卡中续写文件的问题:

安卓手机外置sd卡的权限怎么打开?

安卓 6.0 棉花糖。无法写入 SD 卡

Android 外置SDCard读写权限总结

使用 SAF(存储访问框架)的 Android SD 卡写入权限

Python Kivy 将文件写入/读取到 SD 卡