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

use*_*696 56 android filenotfoundexception

我在某些设备上访问存储时遇到了一个非常奇怪的问题.该应用程序适用于我的测试设备(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();
}
Run Code Online (Sandbox Code Playgroud)

它在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
Run Code Online (Sandbox Code Playgroud)

在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"/> 
Run Code Online (Sandbox Code Playgroud)

我已经确认用户在SD卡上使用了正确的应用程序专用.而更奇怪的是,它也无法写入内部存储.如果我同时具有读写权限,怎么会发生这种情况?用户表示他们当时没有将他们的设备连接到PC.

更新

事实证明我调用open并且过于频繁地关闭FileOutputStream,这会在某些时候抛出FileNotFoundException.听起来更像是一个线程问题.

Jus*_*ler 124

对于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
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

AndroidManifest.xml中

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Run Code Online (Sandbox Code Playgroud)

  • 确实如此,解决了我的问题。更多信息:http://developer.android.com/training/permissions/requesting.html (2认同)
  • 这是正确的答案,而不是当前标记的答案。 (2认同)

Gar*_*ret 32

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

您的问题可能出在两个不同的领域.这是你要创建要写入的文件的方式,或者你的写作方法可能存在缺陷,因为它依赖于手机.

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

java.io.File xmlFile = new java.io.File(Environment
    .getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
     + "/Filename.xml");
Run Code Online (Sandbox Code Playgroud)

如果您正在将文件写入应用程序的内部存储.试试这个例子:

java.io.File xmlFile = new java.io.File((getActivity()
   .getApplicationContext().getFileStreamPath("FileName.xml")
   .getPath()));
Run Code Online (Sandbox Code Playgroud)

我个人依靠外部库来处理流式文件.这个还没有让我失望.

org.apache.commons.io.FileUtils.copyInputStreamToFile(is, file);
Run Code Online (Sandbox Code Playgroud)

我在失败的写命令上丢失了太多次数据,因此我依靠着名且经过测试的库来解决我的IO繁重问题.

如果文件很大,您可能还想查看在后台运行IO,或使用回调.

如果您已经在使用环境变量,则可能是权限问题.查看Justin Fiedler的答案如下.


Uri*_*kel 19

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

<manifest ... >
    <!-- This attribute is "false" by default on apps targeting Android Q. -->
    <application android:requestLegacyExternalStorage="true" ... >
     ...
    </application>
</manifest>
Run Code Online (Sandbox Code Playgroud)

在此处了解更多信息:https : //developer.android.com/preview/privacy/scoped-storage

  • 你救了我的日子。我坚持使用android Q,发现了答案。非常感谢! (3认同)
  • 很高兴我能帮上忙 (2认同)

Gra*_*rks 6

在我的情况下,我有错误的案例

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Run Code Online (Sandbox Code Playgroud)

android.permission 必须是小写的,不知何故整个字符串在我们的源代码中是大写的.


小智 6

添加这两个读写权限,解决这个问题

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Run Code Online (Sandbox Code Playgroud)

在应用程序标签中添加以下行

android:requestLegacyExternalStorage="true"
Run Code Online (Sandbox Code Playgroud)


小智 5

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

在Android设备上访问文件系统时,切记:

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

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