Android 打开失败:EACCES(权限被拒绝)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/23527767/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
open failed: EACCES (Permission denied)
提问by user3613696
I am having a very weird problem with storage accessing on some devices. The app works on my testing devices (Nexus 4 & 7, Samsung GS5). All my devices running Android 4.4.2. But I received many emails from users saying that the app can not write to the storage (neither the internal storage nor the sd card). From the log file received from user feedback, I can see the problem is the following code:
我在某些设备上访问存储时遇到了一个非常奇怪的问题。该应用程序适用于我的测试设备(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();
}
It throws exception at the line fStream = new FileOutputStream(filename, true); when creating FileOutputStream.
它在 fStream = new FileOutputStream(filename, true); 行抛出异常。创建 FileOutputStream 时。
The stack log is:
堆栈日志是:
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
In the AndroidManifest.xml I have the following permissions declared:
在 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"/>
I've confirmed that the users are using the correct app's private on the SD card. And what's more weird is that it fails to write to internal storage as well. How can this happen if I have both read & write permissions? The users say they are not connecting their devices to the PC at that time.
我已经确认用户在 SD 卡上使用了正确的应用程序私有。更奇怪的是它也无法写入内部存储。如果我同时拥有读写权限,怎么会发生这种情况?用户说他们当时没有将他们的设备连接到 PC。
Update
更新
It turns out I am calling open and close FileOutputStream too frequently, which throws the FileNotFoundException at some point. Sounds more like a threading issue.
事实证明,我过于频繁地调用 open 和 close FileOutputStream,这会在某些时候抛出 FileNotFoundException。听起来更像是线程问题。
采纳答案by Garret
I ran into a similar issue a while back.
不久前我遇到了类似的问题。
Your problem could be in two different areas. It's either how you're creating the file to write to, or your method of writing could be flawed in that it is phone dependent.
您的问题可能在两个不同的领域。这要么是您创建要写入的文件的方式,要么是您的写入方法可能存在缺陷,因为它依赖于电话。
If you're writing the file to a specific location on the SD card, try using Environment variables. They should always point to a valid location. Here's an example to write to the downloads folder:
如果您要将文件写入 SD 卡上的特定位置,请尝试使用环境变量。它们应该始终指向一个有效的位置。这是写入下载文件夹的示例:
java.io.File xmlFile = new java.io.File(Environment
.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
+ "/Filename.xml");
If you're writing the file to the application's internal storage. Try this example:
如果您将文件写入应用程序的内部存储。试试这个例子:
java.io.File xmlFile = new java.io.File((getActivity()
.getApplicationContext().getFileStreamPath("FileName.xml")
.getPath()));
Personally I rely on external libraries to handle the streaming to file. This one hasn't failed me yet.
我个人依靠外部库来处理流式传输到文件。这个还没有让我失望。
org.apache.commons.io.FileUtils.copyInputStreamToFile(is, file);
I've lost data one too many times on a failed write command, so I rely on well-known and tested libraries for my IO heavy lifting.
由于写入命令失败,我已经多次丢失数据,因此我依靠知名且经过测试的库来完成 IO 繁重的工作。
If the files are large, you may also want to look into running the IO in the background, or use callbacks.
如果文件很大,您可能还需要考虑在后台运行 IO,或使用回调。
If you're already using environment variables, it could be a permissions issue. Check out Justin Fiedler's answer below.
如果您已经在使用环境变量,则可能是权限问题。在下面查看贾斯汀·菲德勒 (Justin Fiedler) 的回答。
回答by Justin Fiedler
For API 23+ you need to request the read/write permissions even if they are already in your manifest.
对于 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
AndroidManifest.xml
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
回答by Uriel Frankel
Apps targeting Android Q - API 29by default are given a filtered view into external storage. A quick fix for that is to add this code in the AndroidManifest.xml:
默认情况下,面向Android Q - API 29的应用会获得外部存储的过滤视图。对此的快速解决方法是在 AndroidManifest.xml 中添加以下代码:
<manifest ... >
<!-- This attribute is "false" by default on apps targeting Android Q. -->
<application android:requestLegacyExternalStorage="true" ... >
...
</application>
</manifest>
Read more about it here: https://developer.android.com/training/data-storage/compatibility
在此处阅读更多相关信息:https: //developer.android.com/training/data-storage/compatibility
回答by Graham Perks
In my case I had the wrong case in
就我而言,我有错误的案例
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
android.permission
must be lowercase, and somehow the entire string was uppercase in our source.
android.permission
必须是小写的,并且不知何故整个字符串在我们的源代码中都是大写的。
回答by ninad.sonje
I also faced the same issue. After lot of hard work, I found what was wrong in my case. My device was connected to computer via USB cable. There are types for USB connections like Mass Storage, Media Device(MTP), Camera(PTP) etc. My connection type was - 'Mass Storage', and this was causing the problems. When I changed the connection type, the issue was solved.
我也面临同样的问题。经过大量的努力,我发现我的情况出了什么问题。我的设备通过 USB 电缆连接到计算机。USB 连接有多种类型,如大容量存储、媒体设备 (MTP)、相机 (PTP) 等。我的连接类型是 - '大容量存储',这导致了问题。当我更改连接类型时,问题就解决了。
Always remember while accessing filesystem on android device :-
在 android 设备上访问文件系统时永远记住:-
DON'T CONNECT AS MASS STORAGE to the computer/pc.
不要将大容量存储连接到计算机/PC。
回答by Anton Vaysberg
In my case it was permissions issue. The catch is that on device with Android 4.0.4 I got access to file without any error or exception. And on device with Android 5.1 it failed with ACCESS exception (open failed: EACCES (Permission denied)). Handled it with adding follow permission to manifest file:
就我而言,这是权限问题。问题是,在装有 Android 4.0.4 的设备上,我可以访问文件而没有任何错误或异常。在装有 Android 5.1 的设备上,它因 ACCESS 异常而失败(打开失败:EACCES(权限被拒绝))。通过向清单文件添加关注权限来处理它:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
So I guess that it's the difference between permissions management in OS versions that causes to failures.
所以我想这是导致失败的操作系统版本中权限管理之间的差异。
回答by Rahul
First give or check permissions like
首先给予或检查权限,如
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
If these two permissions are OK, then check your output streams are in correct format.
如果这两个权限都没有问题,请检查您的输出流格式是否正确。
Example:
例子:
FileOutputStream fos=new FileOutputStream(Environment.getExternalStorageDirectory()+"/rahul1.jpg");
回答by Alex Bin Zhao
I ran into the same problem and found that I have to request the permissions at run time, even if I have declared it in the manifest. Just as stated as Justin Fiedler's answer.
我遇到了同样的问题,发现我必须在运行时请求权限,即使我已经在清单中声明了它。就像贾斯汀·菲德勒的回答一样。
The official documentation about this are here: https://developer.android.com/training/permissions/requesting.html
关于这个的官方文档在这里:https: //developer.android.com/training/permissions/requesting.html
My implementation is slightly different from Justin Fiedler's answer that it also implement v4 fragment's onRequestPermissionsResult method to handle the permissions request response.
我的实现与 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
}
}
}
}
回答by San Juan
I got the same issue but Sometimes, the most dificult issue get simple answer.
我遇到了同样的问题,但有时,最困难的问题会得到简单的答案。
I recheck the manifest permisions and there WAS_NOT write permision shame of me!!!
我重新检查了清单权限,并且没有写权限让我感到羞耻!!!
回答by Rainmaker
@Uriel Frankel is correct that the Android 10 storage access has changed. But the right way is not to use legacy storage flag but to request the storage of your app like so:
@Uriel Frankel 是正确的,Android 10 存储访问已更改。但正确的方法不是使用旧存储标志,而是像这样请求应用程序的存储:
val screenShotDirPath = getApplication<Application>().getExternalFilesDir(Environment.DIRECTORY_PICTURES)?.path
getExternalFilesDiris what you need.
getExternalFilesDir正是您所需要的。