如何检查授予目录路径的权限并且不会引发 EACCES 错误?

Posted

技术标签:

【中文标题】如何检查授予目录路径的权限并且不会引发 EACCES 错误?【英文标题】:How to check permission is granted for a directory path and won't thorow EACCES error? 【发布时间】:2014-07-21 20:46:52 【问题描述】:

我有一个照片编辑安卓应用程序,用户可以选择结果照片的输出目录。问题是 Google 对 KITKAT 版本的 sdcard 写入权限进行了更改,而具有 android KITKAT 版本的设备将不允许应用程序写入辅助 sdcard。现在我需要检查用户选择的目录是否已授予权限并且不会抛出 EACCES 错误。我已经在检查 canRead 和 canWrite 但这些都无济于事。你能告诉我如何检查选择的目录是否不会抛出 EACCES。我唯一的解决方案是尝试在 try catch 中写入文件,但是我希望有更好的方法来做到这一点。

[更新 k3b 2016-09-19]

我在我的 android-4.4 上尝试过,但没有成功

Uri uri = Uri.fromFile(file);
int permissionCode = 
     context.checkCallingOrSelfUriPermission(uri,
     Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
if (permissionCode == PackageManager.PERMISSION_DENIED) 
   // on my android-4.4 i always get PERMISSION_DENIED even 
   // if i can overwrite the file
   return false;

【问题讨论】:

@k3b:一个更简单、更可靠的解决方案是坚持已知的根源。获得无法使用的目录的唯一方法是尝试遍历已知安全目录(例如,尝试从/ 工作,而不是坚持使用Environment.getExternalStorageDirectory())。如果您想支持可移动存储,请在 Android 5.0+ 上使用带有 ACTION_OPEN_DOCUMENT_TREE 的存储访问框架(奖励:您“免费”获得对其他文档提供程序的支持)。 在没有新答案的情况下提供赏金后,我认为目前没有解决方案:-( 【参考方案1】:
try 
            Process p = new ProcessBuilder("ls", "-l", "-s", dir.getCanonicalPath()).start();

            String line;
            ArrayList<String> lineOut = new ArrayList<>();

            BufferedReader error = new BufferedReader(new InputStreamReader(p.getErrorStream()));
            while ((line = error.readLine()) != null) 
                Log.e(TAG, "ls error = "+line);
            
            error.close();

            BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
            while ((line = input.readLine()) != null) 
                lineOut.add(line);
            

            input.close();

            String[] strings = lineOut.toArray(new String[]);
            List<FilesLS.FileEntry> fileEntries = FilesLS.processNewLines(strings);
            for(FilesLS.FileEntry file : fileEntries)
                Log.d(TAG, file.name +" = " + file.permissions);
            

         catch (IOException e) 
            e.printStackTrace();
        

有些人编辑了这个class

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public final class FilesLS 
/**
 * Entry type: File
 */
public static final int TYPE_FILE = 0;
/**
 * Entry type: Directory
 */
public static final int TYPE_DIRECTORY = 1;
/**
 * Entry type: Directory Link
 */
public static final int TYPE_DIRECTORY_LINK = 2;
/**
 * Entry type: Block
 */
public static final int TYPE_BLOCK = 3;
/**
 * Entry type: Character
 */
public static final int TYPE_CHARACTER = 4;
/**
 * Entry type: Link
 */
public static final int TYPE_LINK = 5;
/**
 * Entry type: Socket
 */
public static final int TYPE_SOCKET = 6;
/**
 * Entry type: FIFO
 */
public static final int TYPE_FIFO = 7;
/**
 * Entry type: Other
 */
public static final int TYPE_OTHER = 8;
/**
 * Device side file separator.
 */
public static final String FILE_SEPARATOR = "/"; //$NON-NLS-1$
/**
 * Regexp pattern to parse the result from ls.
 */
private static Pattern sLsPattern = Pattern
        .compile("^([bcdlsp-][-r][-w][-xsS][-r][-w][-xsS][-r][-w][-xstST])\\s+(\\S+)\\s+   (\\S+)\\s+(\\d4-\\d\\d-\\d\\d)\\s+(\\d\\d:\\d\\d)\\s+(.*)$"); //$NON-NLS-1$  \s+([\d\s,]*)

public static List<FileEntry> processNewLines(String[] lines) 
    List<FileEntry> listOfFiles = new ArrayList<FileEntry>();
    for (String line : lines) 
        // no need to handle empty lines.
        if (line.length() == 0) 
            continue;
        
        // run the line through the regexp
        Matcher m = sLsPattern.matcher(line);
        if (m.matches() == false) 
            continue;
        
        // get the name
        String name = m.group(6);
        // get the rest of the groups
        String permissions = m.group(1);
        String owner = m.group(2);
        String group = m.group(3);
 //            String size = m.group(4);
        String date = m.group(4);
        String time = m.group(5);
        String info = null;
        // and the type
        int objectType = TYPE_OTHER;
        switch (permissions.charAt(0)) 
            case '-':
                objectType = TYPE_FILE;
                break;
            case 'b':
                objectType = TYPE_BLOCK;
                break;
            case 'c':
                objectType = TYPE_CHARACTER;
                break;
            case 'd':
                objectType = TYPE_DIRECTORY;
                break;
            case 'l':
                objectType = TYPE_LINK;
                break;
            case 's':
                objectType = TYPE_SOCKET;
                break;
            case 'p':
                objectType = TYPE_FIFO;
                break;
        
        // now check what we may be linking to
        if (objectType == TYPE_LINK) 
            String[] segments = name.split("\\s->\\s"); //$NON-NLS-1$
            // we should have 2 segments
            if (segments.length == 2) 
                // update the entry name to not contain the link
                name = segments[0];
                // and the link name
                info = segments[1];
                // now get the path to the link
                String[] pathSegments = info.split(FILE_SEPARATOR);
                if (pathSegments.length == 1) 
                    // the link is to something in the same directory,
                    // unless the link is ..
                    if ("..".equals(pathSegments[0]))  //$NON-NLS-1$
                        // set the type and we're done.
                        objectType = TYPE_DIRECTORY_LINK;
                     else 
                        // either we found the object already
                        // or we'll find it later.
                    
                
            
            // add an arrow in front to specify it's a link.
            info = "-> " + info; //$NON-NLS-1$;
        
        FileEntry entry = new FileEntry();
        entry.permissions = permissions;
        entry.name = name;
 //            entry.size = size;
        entry.date = date;
        entry.time = time;
        entry.owner = owner;
        entry.group = group;
        if (objectType == TYPE_LINK) 
            entry.info = info;
        
        listOfFiles.add(entry);
    
    return listOfFiles;


public final static class FileEntry 
    String name;
    String info;
    String permissions;
    String size;
    String date;
    String time;
    String owner;
    String group;
    int type;


【讨论】:

这不是一个很好的解决方案。首先,启动一个不同的流程将比简单地尝试所需的操作并捕获故障效率低得多。接下来,鉴于问题是系统错误地将文件报告为不可访问的方式,尚不完全清楚ls 的输出是否会更准确,也不会报告相同的不正确信息。【参考方案2】:

将您需要的权限添加到数组中: 私有静态最终 int REQUEST_CODE_PERMISSION = 2; String[] mPermission = Manifest.permission.INTERNET, Manifest.permission.CHANGE_WIFI_STATE, Manifest.permission.CHANGE_NETWORK_STATE, Manifest.permission.ACCESS_WIFI_STATE;

将此添加到 onCreate 或您想要的位置:

    try 
        if (ActivityCompat.checkSelfPermission(this, mPermission[0])
                != MockPackageManager.PERMISSION_GRANTED ||
                ActivityCompat.checkSelfPermission(this, mPermission[1])
                        != MockPackageManager.PERMISSION_GRANTED ||
                ActivityCompat.checkSelfPermission(this, mPermission[2])
                        != MockPackageManager.PERMISSION_GRANTED ||
                ActivityCompat.checkSelfPermission(this, mPermission[3])
                        != MockPackageManager.PERMISSION_GRANTED)     Log.e("TAGTAG", "DENIED");


            ActivityCompat.requestPermissions(this,
                    mPermission, REQUEST_CODE_PERMISSION);

            // If any permission aboe not allowed by user, this condition will execute every tim, else your else part will work
        
        else
        
            Log.e("TAGTAG", "GRANTED");
        
     catch (Exception e) 
        e.printStackTrace();
    

` 在 Manifest.xml 中声明使用权限

【讨论】:

问题是“如何询问我的应用程序是否对某个文件或文件夹 url 具有写入权限”。我不知道你的文字是如何回答这个问题的。 我写信给您更改权限数组中您可能需要的权限。阅读。除了 sm 给你写代码。

以上是关于如何检查授予目录路径的权限并且不会引发 EACCES 错误?的主要内容,如果未能解决你的问题,请参考以下文章

如何在运行时检查授予权限?

React Native:如何检查是不是已授予地理定位权限

如何检查用户是不是已在 React Native Android 中授予相机权限?

ReactNative:如何检查用户是不是已授予 gps 权限

如何检查用户是不是已授予我的 PHP 应用程序的特定权限集?

React Native:如何检查用户是否已授予gps权限