Android Studio - java.io.FileNotFoundException: /abc.csv 打开失败:EACCES(权限被拒绝)

Android Studio - java.io.FileNotFoundException: /abc.csv open failed: EACCES (Permission denied)

我正在尝试读取 CSV 文件,将其内容加载到微调器中。我给了相关权限 MANAGE_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE and READ_EXTERNAL_STORAGE 从外部存储读取文件。我已将 CSV 文件放在运行时请求权限的目录中。另外 file.exists() 函数 return true 但仍然无法读取 csv 文件。我哪里错了?

这是错误日志:

022-02-27 18:03:32.457 13080-13080/com.example.locationfetcher_v2 W/System.err: java.io.FileNotFoundException: /storage/emulated/0/Khidmah/input.csv: open failed: EACCES (Permission denied)
2022-02-27 18:03:32.461 13080-13080/com.example.locationfetcher_v2 W/System.err:     at libcore.io.IoBridge.open(IoBridge.java:492)
2022-02-27 18:03:32.461 13080-13080/com.example.locationfetcher_v2 W/System.err:     at java.io.FileInputStream.<init>(FileInputStream.java:160)
2022-02-27 18:03:32.461 13080-13080/com.example.locationfetcher_v2 W/System.err:     at java.io.FileInputStream.<init>(FileInputStream.java:115)
2022-02-27 18:03:32.461 13080-13080/com.example.locationfetcher_v2 W/System.err:     at java.io.FileReader.<init>(FileReader.java:58)
2022-02-27 18:03:32.461 13080-13080/com.example.locationfetcher_v2 W/System.err:     at com.example.locationfetcher_v2.MainActivity.onCreate(MainActivity.java:157)
2022-02-27 18:03:32.461 13080-13080/com.example.locationfetcher_v2 W/System.err:     at android.app.Activity.performCreate(Activity.java:8157)
2022-02-27 18:03:32.461 13080-13080/com.example.locationfetcher_v2 W/System.err:     at android.app.Activity.performCreate(Activity.java:8129)
2022-02-27 18:03:32.461 13080-13080/com.example.locationfetcher_v2 W/System.err:     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1310)
2022-02-27 18:03:32.461 13080-13080/com.example.locationfetcher_v2 W/System.err:     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3494)
2022-02-27 18:03:32.461 13080-13080/com.example.locationfetcher_v2 W/System.err:     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3693)
2022-02-27 18:03:32.461 13080-13080/com.example.locationfetcher_v2 W/System.err:     at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
2022-02-27 18:03:32.461 13080-13080/com.example.locationfetcher_v2 W/System.err:     at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
2022-02-27 18:03:32.461 13080-13080/com.example.locationfetcher_v2 W/System.err:     at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
2022-02-27 18:03:32.461 13080-13080/com.example.locationfetcher_v2 W/System.err:     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2135)
2022-02-27 18:03:32.461 13080-13080/com.example.locationfetcher_v2 W/System.err:     at android.os.Handler.dispatchMessage(Handler.java:106)
2022-02-27 18:03:32.462 13080-13080/com.example.locationfetcher_v2 W/System.err:     at android.os.Looper.loop(Looper.java:236)
2022-02-27 18:03:32.462 13080-13080/com.example.locationfetcher_v2 W/System.err:     at android.app.ActivityThread.main(ActivityThread.java:8059)
2022-02-27 18:03:32.462 13080-13080/com.example.locationfetcher_v2 W/System.err:     at java.lang.reflect.Method.invoke(Native Method)
2022-02-27 18:03:32.462 13080-13080/com.example.locationfetcher_v2 W/System.err:     at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:656)
2022-02-27 18:03:32.462 13080-13080/com.example.locationfetcher_v2 W/System.err:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:967)
2022-02-27 18:03:32.462 13080-13080/com.example.locationfetcher_v2 W/System.err: Caused by: android.system.ErrnoException: open failed: EACCES (Permission denied)
2022-02-27 18:03:32.462 13080-13080/com.example.locationfetcher_v2 W/System.err:     at libcore.io.Linux.open(Native Method)
2022-02-27 18:03:32.462 13080-13080/com.example.locationfetcher_v2 W/System.err:     at libcore.io.ForwardingOs.open(ForwardingOs.java:166)
2022-02-27 18:03:32.462 13080-13080/com.example.locationfetcher_v2 W/System.err:     at libcore.io.BlockGuardOs.open(BlockGuardOs.java:254)
2022-02-27 18:03:32.462 13080-13080/com.example.locationfetcher_v2 W/System.err:     at libcore.io.ForwardingOs.open(ForwardingOs.java:166)
2022-02-27 18:03:32.462 13080-13080/com.example.locationfetcher_v2 W/System.err:     at android.app.ActivityThread$AndroidOs.open(ActivityThread.java:7932)
2022-02-27 18:03:32.462 13080-13080/com.example.locationfetcher_v2 W/System.err:     at libcore.io.IoBridge.open(IoBridge.java:478)
2022-02-27 18:03:32.462 13080-13080/com.example.locationfetcher_v2 W/System.err:    ... 19 more

下面是我的代码:

            @Override
                protected void onCreate(Bundle savedInstanceState) {
                    super.onCreate(savedInstanceState);
                    setContentView(R.layout.activity_main);
                    //Using Dexter Library
    Dexter.withContext(this)
                    .withPermissions(
                            Manifest.permission.MANAGE_EXTERNAL_STORAGE,
                            Manifest.permission.WRITE_EXTERNAL_STORAGE,
                            Manifest.permission.READ_EXTERNAL_STORAGE,
                            Manifest.permission.ACCESS_COARSE_LOCATION,
                            Manifest.permission.ACCESS_FINE_LOCATION,
                            Manifest.permission.CAMERA
                    ).withListener(new MultiplePermissionsListener() {
                @Override public void onPermissionsChecked(MultiplePermissionsReport report) {/* ... */}
                @Override public void onPermissionRationaleShouldBeShown(List<PermissionRequest> permissions, PermissionToken token) {/* ... */}
            }).check();
    
    
            MultiplePermissionsListener dialogMultiplePermissionsListener =
                    DialogOnAnyDeniedMultiplePermissionsListener.Builder
                            .withContext(this)
                            .withTitle("Camera, Storage and Location permission")
                            .withMessage("All Camera, Storage and Location permission are required for this application")
                            .withButtonText(android.R.string.ok)
                            .build();
    
            
         //// Read data from CSV file
        List<String> addresses = new ArrayList<String>();
        Spinner address_spinner = findViewById(R.id.spinnerAddress);

//        File file = new File(Environment.getExternalStorageDirectory() + "/Khidmah/", "input.csv");
        File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "input.csv");

        show_notification(file.getPath());
        show_notification(new Boolean(file.exists()).toString());
        FileInputStream fis = null;
        try {
            if (file.exists()){

                show_notification("can read - " + new Boolean(file.canRead()).toString());

                CSVReader reader = new CSVReader(new FileReader(file.toURI().toString()));

                show_notification("successfully read file...");
                String[] nextLine;
                while ((nextLine = reader.readNext()) != null) {
                    // nextLine[] is an array of values from the line
//                    System.out.println(nextLine[0] + nextLine[1] + nextLine[2]);
                    addresses.add(nextLine[0] + nextLine[1] + nextLine[2]);
                    show_notification(nextLine[0] + nextLine[1] + nextLine[2]);
                }
                ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.support_simple_spinner_dropdown_item,addresses);
                address_spinner.setAdapter(adapter);
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (CsvValidationException e) {
            e.printStackTrace();
        }   
                }
    

这里是AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.locationfetcher_v2">

    <!-- Always include this permission -->
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

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

    <!-- Include only if your app benefits from precise location access. -->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

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

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.LocationFetcher_v2"
        android:foregroundServiceType="location">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <meta-data
            android:name="preloaded_fonts"
            android:resource="@array/preloaded_fonts" />
    </application>


</manifest>

更新

我现在正在使用 Dexter Library 授予权限。我添加了额外的权限 MANAGE_EXTERNAL_STORAGE 并将 input.csv 文件放在 Public 目录中,即下载文件夹。但是现在它给出了以下错误:

open failed: ENOENT (No such file or directory)

在 File.exists() 之后,在对文件执行操作之前使用 File.canRead()。

此 csv 文件不是由您的应用创建的。

因此,在 Android 11,您不是所有者,尽管您的应用可以检查文件是否存在,但它发现 File.canRead() 文件不可访问。

使用 MANAGE_EXTERNAL_STORAGE 和正确的运行时代码,您的应用可以获得访问权限。

正确的代码将启动 Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION 的意图。