java.io.FileNotFoundException 打开失败:EEXIST(文件存在)Android 11

java.io.FileNotFoundException open failed: EEXIST (File exists) Android 11

我试图从服务器下载图像并将其保存在外部存储器中,但是在 Android11 中,当我尝试创建文件时出现错误。 我已授予访问外部存储的权限。

我在网上搜索了一下,他们建议我把这段代码放在清单中,但它对 android 11

不起作用
android:requestLegacyExternalStorage="true"

清单

<uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:requestLegacyExternalStorage="true"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.TestDwonloadImgApp"
        android:usesCleartextTraffic="true">
        <activity android:name=".MainActivity2">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".MainActivity">
        </activity>
    </application>

主要活动

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ImageView img = findViewById(R.id.img);

        ImmagineInterface ii = RetrofitManager.retrofit.create(ImmagineInterface.class);
        Call<ResponseBody> call = ii.downloadFile("/immaginimusei/arte-scienza.jpg");
        call.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                if (response.code() == 200) {
                    boolean result = writeResponseBody(response.body(), "/immaginimusei/arte-scienza.jpg");
                    if(result) {
                        Bitmap bitmap = BitmapFactory.decodeFile(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString() + "/ArtHunter/immaginimusei/arte-scienza.jpg");
                        img.setImageBitmap(bitmap);
                    }
                }
            }

            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {
                Bitmap bitmap = BitmapFactory.decodeFile(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString() + "/ArtHunter/immaginimusei/arte-scienza.jpg");
                img.setImageBitmap(bitmap);
            }
        });
    }
}

写响应体

public static boolean writeResponseBody(ResponseBody body, String dir1) {
        try {
            String state = Environment.getExternalStorageState();
            if (Environment.MEDIA_MOUNTED.equals(state)) {
                // todo change the file location/name according to your needs

                String path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString() + "/ArtHunter";

                String path1 = path + dir1;
                File f = new File(path1);
                String path2 = f.getPath();
                String nome = f.getName();
                path2 = path2.replaceAll("/" + nome, "");

                File directory = new File(path2);
                if (!directory.exists())
                    directory.mkdirs();

                File img = new File(path2, nome);
                if (img.exists())
                    return true;
                img.createNewFile();

                InputStream inputStream = null;
                FileOutputStream outputStream = null;

                try {
                    byte[] fileReader = new byte[4096];

                    inputStream = body.byteStream();
                    outputStream = new FileOutputStream(img); //error here!

                    while (true) {
                        int read = inputStream.read(fileReader);

                        if (read == -1) {
                            break;
                        }

                        outputStream.write(fileReader, 0, read);

                    }

                    outputStream.flush();

                    return true;
                } catch (IOException e) {
                    e.printStackTrace();
                    return false;
                } finally {
                    if (inputStream != null) {
                        inputStream.close();
                    }

                    if (outputStream != null) {
                        outputStream.close();
                    }
                }
            }
            return false;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

错误

/System.err: java.io.FileNotFoundException: /storage/emulated/0/Download/ArtHunter/immaginimusei/arte-scienza.jpg: open failed: EEXIST (File exists)
W/System.err:     at libcore.io.IoBridge.open(IoBridge.java:492)
        at java.io.FileOutputStream.<init>(FileOutputStream.java:236)
        at java.io.FileOutputStream.<init>(FileOutputStream.java:186)
        at com.theapplegeek.testdwonloadimgapp.MainActivity.writeResponseBody(MainActivity.java:93)
        at com.theapplegeek.testdwonloadimgapp.MainActivity.onResponse(MainActivity.java:47)
        at retrofit2.DefaultCallAdapterFactory$ExecutorCallbackCall.lambda$onResponse[=16=]$DefaultCallAdapterFactory$ExecutorCallbackCall(DefaultCallAdapterFactory.java:89)
        at retrofit2.-$$Lambda$DefaultCallAdapterFactory$ExecutorCallbackCall$hVGjmafRi6VitDIrPNdoFizVAdk.run(Unknown Source:6)
        at android.os.Handler.handleCallback(Handler.java:938)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:245)
        at android.app.ActivityThread.main(ActivityThread.java:8004)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:631)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:978)
    Caused by: android.system.ErrnoException: open failed: EEXIST (File exists)
        at libcore.io.Linux.open(Native Method)
        at libcore.io.ForwardingOs.open(ForwardingOs.java:166)
        at libcore.io.BlockGuardOs.open(BlockGuardOs.java:254)
W/System.err:     at libcore.io.ForwardingOs.open(ForwardingOs.java:166)
        at android.app.ActivityThread$AndroidOs.open(ActivityThread.java:7865)
        at libcore.io.IoBridge.open(IoBridge.java:478)
        ... 13 more

In Android 11 android:requestLegacyExternalStorage="true" 将被简单地忽略,因为它是 Android < 11 不破坏旧应用程序的临时解决方案。 现在,您必须使用

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

您也可以只使用 SAF 来避免所有这些 'permissions' 麻烦。这是 Google 对不需要管理大部分内部存储数据的应用程序的建议。参考: https://developer.android.com/guide/topics/providers/document-provider

但是,如果您不想破坏您的应用程序并失去所有的辛勤工作,请考虑

if(Environment.isExternalStorageManager())
{
    internal = new File("/sdcard");
    internalContents = internal.listFiles();
}
else
{
    Intent permissionIntent = new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
    startActivity(permissionIntent);
}

这将打开一个设置页面,您可以在其中为您的应用授予存储访问权限。如果该应用程序已经具有权限,那么您将能够访问该目录。将它放在 onCreate() 方法 之后 设置布局资源的最开始。

最好不要为您以后构建的任何应用程序执行此操作。

转到您的移动设置 -> 应用 -> select 您的应用 -> 权限 -> 存储 -> select 允许管理所有文件

对我有用。