打开失败:EACCES(权限被拒绝)


70

我在某些设备上的存储访问遇到了一个非常奇怪的问题。该应用程序可以在我的测试设备(Nexus 4和7,三星GS5)上运行。我所有运行Android 4.4.2的设备。但是我收到了许多用户的电子邮件,称该应用程序无法写入存储设备(内部存储设备或SD卡均无法写入)。从收到用户反馈的日志文件中,我可以看到问题是以下代码:

try {
    if (fStream == null) {
    fStream = new FileOutputStream(filename, true);
}
    fStream.write(data, 0, bytes);
    return;
} catch (IOException ex) {
    ex.printStackTrace();
}

它在fStream = new FileOutputStream(filename,true)行处引发异常。创建FileOutputStream时。

堆栈日志为:

W/System.err( 8147): Caused by: java.io.FileNotFoundException: /storage/emulated/0/my_folder/test_file_name.png: open failed: EACCES (Permission denied)
w/System.err( 8147):    at libcore.io.IoBridge.open(IoBridge.java:409)
W/System.err( 8147):    at java.io.FileOutputStream.<init>(FileOutputStream.java:88)
W/System.err( 8147):    at java.io.FileOutputStream.<init>(FileOutputStream.java:128)
W/System.err( 8147):    at myapp.save(SourceFile:515)
W/System.err( 8147):    ... 8 more
W/System.err( 8147): Caused by: libcore.io.ErrnoException: open failed: EACCES (Permission denied)
W/System.err( 8147):    at libcore.io.Posix.open(Native Method)
W/System.err( 8147):    at libcore.io.BlockGuardOs.open(BlockGuardOs.java:110)
W/System.err( 8147):    at libcore.io.IoBridge.open(IoBridge.java:393)
W/System.err( 8147):    ... 11 more

在AndroidManifest.xml中,我声明了以下权限:

 <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="19"/>
    <uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 

我已确认用户正在SD卡上使用正确的应用程序专用。而且更奇怪的是,它也无法写入内部存储。如果我同时拥有读写权限,怎么办?用户说他们当时没有将设备连接到PC。

更新资料

事实证明,我过于频繁地调用打开和关闭FileOutputStream,这有时会引发FileNotFoundException。听起来更像是线程问题。


事实证明,我过于频繁地调用打开和关闭FileOutputStream,这有时会引发FileNotFoundException。听起来更像是线程问题。
user3613696 2014年

在这里检查我的答案。希望能帮助到你。stackoverflow.com/a/58797938/11696949
Zeeshan票价为公元

Answers:


35

不久前,我遇到了类似的问题。

您的问题可能在两个不同的领域。要么是您创建要写入的文件的方式,要么是您的写入方法存在缺陷,因为它取决于电话。

如果要将文件写入SD卡上的特定位置,请尝试使用环境变量。他们应始终指向有效位置。这是一个写入downloads文件夹的示例:

java.io.File xmlFile = new java.io.File(Environment
    .getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
     + "/Filename.xml");

如果要将文件写入应用程序的内部存储。试试这个例子:

java.io.File xmlFile = new java.io.File((getActivity()
   .getApplicationContext().getFileStreamPath("FileName.xml")
   .getPath()));

我个人依靠外部库来处理流向文件。这还没有使我失望。

org.apache.commons.io.FileUtils.copyInputStreamToFile(is, file);

我在一次失败的写入命令中丢失了太多次数据,因此我依靠繁重且经过测试的库来处理IO。

如果文件很大,则可能还需要考虑在后台运行IO或使用回调。

如果您已经在使用环境变量,则可能是权限问题。在下面查看贾斯汀·菲德勒的答案。


我将尝试使用org.apache.commons.io.FileUtils,看看是否有帮助。稍后将发布更新。顺便说一下,经过更多测试,事实证明fStream = new FileOutputStream(filename,true); 并非总是每次都无法打开流,看起来它是第一次工作,而下次却失败。
user3613696 2014年

1
事实证明,我过于频繁地调用打开和关闭FileOutputStream,这有时会引发FileNotFoundException。听起来更像是线程问题。自从您接受正确指出可能的错误后,我们便标记了您的答案。
user3613696 2014年

谢谢。是的,由于我们看不到您的完整代码,我们只需要对可能导致您的问题的原因做出一些猜测即可。感谢你的接纳!
Garret 2014年

129

对于API 23+,即使清单中已经存在读/写权限,也需要请求读/写权限。

// Storage Permissions
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
        Manifest.permission.READ_EXTERNAL_STORAGE,
        Manifest.permission.WRITE_EXTERNAL_STORAGE
};

/**
 * Checks if the app has permission to write to device storage
 *
 * If the app does not has permission then the user will be prompted to grant permissions
 *
 * @param activity
 */
public static void verifyStoragePermissions(Activity activity) {
    // Check if we have write permission
    int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);

    if (permission != PackageManager.PERMISSION_GRANTED) {
        // We don't have permission so prompt the user
        ActivityCompat.requestPermissions(
                activity,
                PERMISSIONS_STORAGE,
                REQUEST_EXTERNAL_STORAGE
        );
    }
}

AndroidManifest.xml

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

1
是的,解决了我的问题。更多信息:developer.android.com/training/permissions/requesting.html
joaobarbosa

确实,我的问题是类似的。如果我在低于v6的Android版本中测试了该应用程序。该应用程序的工作原理很吸引人,但对于> = 6,则出了点问题。正如@easyspeak所说,只需添加权限请求即可。
Shudy '16

在仪器测试中该如何做?
艾哈迈德·穆扎克

我已授予许可,但无法在sdcard中制作.zip文件
Bhanu Sharma

2
这是正确的答案,而不是当前标记的答案。
hdante

128

默认情况下,针对Android Q-API 29的应用将获得过滤后的外部存储视图。快速解决方案是在AndroidManifest.xml中添加以下代码:

<manifest ... >
    <!-- This attribute is "false" by default on apps targeting Android Q. -->
    <application android:requestLegacyExternalStorage="true" ... >
     ...
    </application>
</manifest>

在这里阅读更多有关它的信息:https : //developer.android.com/training/data-storage/compatibility


拯救了我的一天。搜索了很多,但在任何地方都找不到此答案。这是对的。
Tejas Pandya

1
由于此解决方案是临时的,因此以下是如何查询媒体文件的完整实现:developer.android.com/training/data-storage/shared/media。如果是图像,则在获取uri后,需要调用ContentResolver.loadThumbnail(uri,size,cancelSignal)来接收包含该图像的位图。
sunlover3'4

1
男人,你应该得到奖金
Daniel Beltrami

编译错误:找不到属性android:requestLegacyExternalStorage。
普里扬卡·辛哈尔

@Priyanka请查看我添加的链接
Uriel Frankel

6

就我而言,我有一个错误的案例

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

android.permission 必须是小写,并且在我们的源代码中整个字符串都以大写形式存在。


5

我也面临同样的问题。经过大量的努力,我发现我的问题出在哪里。我的设备通过USB电缆连接到计算机。USB连接类型有大容量存储,媒体设备(MTP),相机(PTP)等。我的连接类型为-“大容量存储”,这引起了问题。当我更改连接类型时,问题已解决。

在Android设备上访问文件系统时,请务必记住:

请勿将大容量存储连接到计算机/ pc。


4
改成什么?我只有PTP和MTP作为我的选择,但都无法正常工作。即使将应用程序加载到我的设备上并在未连接到计算机的情况下从该设备启动也无法解决该问题。
G_V 2014年

或使用Wifi进行调试。
戴维(David

3

就我而言,这是权限问题。问题是在使用Android 4.0.4的设备上,我可以无任何错误或例外地访问文件。在装有Android 5.1的设备上,它失败并出现ACCESS异常(打开失败:EACCES(权限被拒绝))。通过向清单文件添加关注权限来处理它:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

因此,我猜想是导致版本失败的OS版本中的权限管理之间的差异。


2

首先给予或检查权限,例如

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

如果这两个权限都正确,请检查您的输出流格式是否正确。

例:

FileOutputStream fos=new FileOutputStream(Environment.getExternalStorageDirectory()+"/rahul1.jpg");

2

我遇到了同样的问题,发现即使在清单中声明了权限,我也必须在运行时请求权限。就像贾斯汀·菲德勒(Justin Fiedler)的回答一样。

关于此的官方文档在这里:https : //developer.android.com/training/permissions/requesting.html

我的实现与Justin Fiedler的回答稍有不同,该回答还实现了v4片段的onRequestPermissionsResult方法来处理权限请求响应。

public static final int REQUEST_EXTERNAL_PERMISSION_CODE = 666;

@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
public static final String[] PERMISSIONS_EXTERNAL_STORAGE = {
        READ_EXTERNAL_STORAGE,
        WRITE_EXTERNAL_STORAGE
};

public boolean checkExternalStoragePermission(Activity activity) {
    if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN) {
        return true;
    }

    int readStoragePermissionState = ContextCompat.checkSelfPermission(activity, READ_EXTERNAL_STORAGE);
    int writeStoragePermissionState = ContextCompat.checkSelfPermission(activity, WRITE_EXTERNAL_STORAGE);
    boolean externalStoragePermissionGranted = readStoragePermissionState == PackageManager.PERMISSION_GRANTED &&
            writeStoragePermissionState == PackageManager.PERMISSION_GRANTED;
    if (!externalStoragePermissionGranted) {
        requestPermissions(PERMISSIONS_EXTERNAL_STORAGE, REQUEST_EXTERNAL_PERMISSION_CODE);
    }

    return externalStoragePermissionGranted;
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
        if (requestCode == REQUEST_EXTERNAL_PERMISSION_CODE) {
            if (checkExternalStoragePermission(getActivity())) {
                // Continue with your action after permission request succeed
            }
        }
    }
}

很好的例证。拯救了我的一天。:-)
TechBee '17

1

在我来说,我使用的选项android:isolatedProcess="true"serviceAndroidManifest.xml

一旦我删除它,错误就消失了...


1

我也找到了解决之道。

在启动应用程序之前,我已将root授予file-explorer,并且在从应用程序退出时未禁用对写入/读取的权限。

我使用restrat设备重置所有权限时,我的应用无法使用外部存储器。


1

我遇到了同样的问题,但有时,最困难的问题得到的答案很简单。

我重新检查了清单的渗透,然后WAS_NOT没写下我的渗透耻辱!!!


耶稣基督,这只是发生在我身上,谢谢你
Juanca

1

@Uriel Frankel认为Android 10存储访问权限已更改是正确的。但是正确的方法不是使用旧存储标志,而是请求存储应用程序,如下所示:

val screenShotDirPath = getApplication<Application>().getExternalFilesDir(Environment.DIRECTORY_PICTURES)?.path

getExternalFilesDir是您所需要的。


0

如果客户端使用的是Android 6.0,则Android为(棉花糖)添加了新的权限模型

招:如果您定位到版本22或更低版本,您的应用程序将在安装时请求所有权限,就像在运行低于棉花糖的操作系统的任何设备上一样


0

就我而言,问题是静态的WIFI配置与使用相同IP地址的另一台设备存在冲突。


0

同时添加这些读写权限,以解决此问题

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

将此添加到“应用程序”标签的下面

android:requestLegacyExternalStorage="true"

0

我与应用共享文件的另一个应用引发了此错误(使用 Intent.FLAG_GRANT_READ_URI_PERMISSION

事实证明,该文件Uri必须通过提供FileProvider一流如图所示这里


-3

就我而言,我忘了在添加文件名后添加/来摆脱它

bitmap.compress(Bitmap.CompressFormat.PNG,100,new FileOutputStream(Environment.getExternalStorageDirectory()+"/arjunreddy.png"));
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.