Keywords: Android Permissions | Runtime Permissions | File Operations | EACCES Error | External Storage
Abstract: This technical article provides an in-depth analysis of the common java.io.FileNotFoundException: EACCES (Permission denied) error in Android development. Focusing on the runtime permissions mechanism introduced in Android 6.0 and above, it offers detailed code examples and permission request workflows to help developers properly handle external storage read/write permissions in modern Android systems.
Problem Background and Error Analysis
File operations are common requirements in Android application development. However, many developers encounter the java.io.FileNotFoundException: /storage/emulated/0/New file.txt: open failed: EACCES (Permission denied) error when attempting to read or write to external storage. This error indicates that the application lacks sufficient permissions to access the specified file path.
Evolution of Android Permission Mechanism
The permission management system in Android has undergone significant changes. Before Android 6.0 Marshmallow (API 23), applications requested all declared permissions during installation. Starting from Android 6.0, the system introduced runtime permissions, requiring dynamic user authorization for dangerous permissions such as storage read/write operations.
Runtime Permissions Implementation
To resolve the EACCES error, developers need to implement runtime permission requests in their code. Here's a comprehensive permission request example:
public class MainActivity extends AppCompatActivity {
private static final int REQUEST_STORAGE_PERMISSION = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Check permission status
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
// Request permission
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
REQUEST_STORAGE_PERMISSION);
} else {
// Permission already granted, perform file operation
performFileOperation();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_STORAGE_PERMISSION) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission granted, perform file operation
performFileOperation();
} else {
// Permission denied, notify user
Toast.makeText(this, "Storage permission denied, cannot perform file operation", Toast.LENGTH_LONG).show();
}
}
}
private void performFileOperation() {
// Execute specific file encryption operation
String filePath = editText.getText().toString();
EncAndDec.encrypt(aesKey, filePath);
}
}
Best Practices for Permission Requests
When implementing runtime permissions, consider the following best practices:
- Check current permission status using
ContextCompat.checkSelfPermission()before requesting permissions - Use the
ActivityCompat.requestPermissions()method to request permissions - Handle permission grant or denial scenarios in the
onRequestPermissionsResult()callback - For critical permissions, explain to users why the permission is needed when they deny it
Storage Restrictions in Android 10 and Above
Starting from Android 10 (API 29), Google introduced Scoped Storage, further restricting application access to external storage. While runtime permissions remain necessary, applications can only access their own dedicated directories and specific types of media files by default.
Compatibility Considerations
For applications requiring backward compatibility, you can temporarily disable scoped storage by adding the android:requestLegacyExternalStorage="true" attribute in AndroidManifest.xml:
<application
android:allowBackup="true"
android:requestLegacyExternalStorage="true"
...>
However, note that starting from Android 11, the effectiveness of this flag is limited, and developers should gradually migrate to using Scoped Storage APIs.
Conclusion
The key to resolving the java.io.FileNotFoundException: EACCES (Permission denied) error lies in properly implementing Android's runtime permissions mechanism. Developers need to understand the evolution of Android's permission system, dynamically request necessary permissions in their code, and appropriately handle various permission grant and denial scenarios. As Android systems continue to evolve, timely adaptation to new storage access strategies is crucial for ensuring smooth application operation.