W/System.err: java.io.FileNotFoundException: /storage/emulated/0/XRichText/1654560767490-: open failed: EPERM (Operation not permitted)
at libcore.io.IoBridge.open(IoBridge.java:575)
at java.io.FileOutputStream.(FileOutputStream.java:236)
at java.io.FileOutputStream.(FileOutputStream.java:186)
at com.example.wifibreaker.util.SDCardUtil.saveToSdCard(SDCardUtil.java:55)
at com.example.wifibreaker.activity.EditDiaryActivity4.subscribe(EditDiaryActivity.java:264)atio.reactivex.internal.operators.observable.ObservableCreate.subscribeActual(ObservableCreate.java:40)atio.reactivex.Observable.subscribe(Observable.java:12090)atio.reactivex.internal.operators.observable.ObservableSubscribeOn4.subscribe(EditDiaryActivity.java:264) at io.reactivex.internal.operators.observable.ObservableCreate.subscribeActual(ObservableCreate.java:40) at io.reactivex.Observable.subscribe(Observable.java:12090) at io.reactivex.internal.operators.observable.ObservableSubscribeOn4.subscribe(EditDiaryActivity.java:264)atio.reactivex.internal.operators.observable.ObservableCreate.subscribeActual(ObservableCreate.java:40)atio.reactivex.Observable.subscribe(Observable.java:12090)atio.reactivex.internal.operators.observable.ObservableSubscribeOnSubscribeTask.run(ObservableSubscribeOn.java:96)
at io.reactivex.SchedulerDisposeTask.run(Scheduler.java:578)atio.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:66)atio.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57)atjava.util.concurrent.FutureTask.run(FutureTask.java:266)atjava.util.concurrent.ScheduledThreadPoolExecutorDisposeTask.run(Scheduler.java:578) at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:66) at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ScheduledThreadPoolExecutorDisposeTask.run(Scheduler.java:578)atio.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:66)atio.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57)atjava.util.concurrent.FutureTask.run(FutureTask.java:266)atjava.util.concurrent.ScheduledThreadPoolExecutorScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutorWorker.run(ThreadPoolExecutor.java:641)atjava.lang.Thread.run(Thread.java:920)W/System.err:Causedby:android.system.ErrnoException:openfailed:EPERM(Operationnotpermitted)atlibcore.io.Linux.open(NativeMethod)atlibcore.io.ForwardingOs.open(ForwardingOs.java:567)atlibcore.io.BlockGuardOs.open(BlockGuardOs.java:273)atlibcore.io.ForwardingOs.open(ForwardingOs.java:567)atandroid.app.ActivityThreadWorker.run(ThreadPoolExecutor.java:641) at java.lang.Thread.run(Thread.java:920) W/System.err: Caused by: android.system.ErrnoException: open failed: EPERM (Operation not permitted) at libcore.io.Linux.open(Native Method) at libcore.io.ForwardingOs.open(ForwardingOs.java:567) at libcore.io.BlockGuardOs.open(BlockGuardOs.java:273) at libcore.io.ForwardingOs.open(ForwardingOs.java:567) at android.app.ActivityThreadWorker.run(ThreadPoolExecutor.java:641)atjava.lang.Thread.run(Thread.java:920)W/System.err:Causedby:android.system.ErrnoException:openfailed:EPERM(Operationnotpermitted)atlibcore.io.Linux.open(NativeMethod)atlibcore.io.ForwardingOs.open(ForwardingOs.java:567)atlibcore.io.BlockGuardOs.open(BlockGuardOs.java:273)atlibcore.io.ForwardingOs.open(ForwardingOs.java:567)atandroid.app.ActivityThreadAndroidOs.open(ActivityThread.java:8080)
at libcore.io.IoBridge.open(IoBridge.java:561)
… 15 more
原因
注意:在 Android 11(API 级别 30)及更高版本中,应用无法在外部存储设备上创建自己的应用专用目录。
解决办法(3种方案):
- 降低SDK至29或以下(可实现随意改写目录创建文件)
- SDK保留30那么加入:
requestLegacyExternalStorage= "true"
但是目标路径仅局限于内部存储路径下的
public static String DIRECTORY_ALARMS = "Alarms";
public static String DIRECTORY_DCIM = "DCIM";
public static String DIRECTORY_DOCUMENTS = "Documents";
public static String DIRECTORY_DOWNLOADS = "Download";
public static String DIRECTORY_MOVIES = "Movies";
public static String DIRECTORY_MUSIC = "Music";
public static String DIRECTORY_NOTIFICATIONS = "Notifications";
public static String DIRECTORY_PICTURES = "Pictures";
public static String DIRECTORY_PODCASTS = "Podcasts";
public static String DIRECTORY_RINGTONES = "Ringtones";
这几个公有文件夹下创建
3. sdk>=31,方案二会失效,官方给出的方案:
创建缓存文件
如需将应用专属文件添加到外部存储空间中的缓存,请获取对 externalCacheDir 的引用:
File externalCacheFile = new File(context.getExternalCacheDir(), filename);