解决android.system.ErrnoException: open failed

open failed: EISDIR (Is a directory)

在做apk的断点续传功能的时候,遇到一个open failed问题,是比较简单的EISDIR (Is a directory),

异常描述:

java.io.FileNotFoundException: /storage/emulated/0/Android/data/com.xxx.xxx/files/Download: open failed: EISDIR (Is a directory)
        at libcore.io.IoBridge.open(IoBridge.java:487)
        at java.io.RandomAccessFile.(RandomAccessFile.java:117)

发生问题的code:
randomAccessFile = new RandomAccessFile(file, "rwd");

查看代码才发现在原来是在xxx/xxx/Download下创建xxx.apk文件的时候,路径写成了该apk文件的文件夹路径(xxx/xxx/Download),后面没有跟apk名字.而该文件夹是存在的,再创建就会报错,加上apk名字就好了(xxx/xxx/Download/xxx.apk).

能引起该错误的另一个情况就是在创建文件的时候,一定要注意存储这个文件的文件夹下时候是否已经有了重名的文件或文件夹(是的,xxx/xxx/Download/xxx.apk也可能是个文件夹),有的话是不能创建成功的.

open failed: EACCES (Permission denied)

在网上查这个问题,无意溜到了另一个相似的问题上(EACCES),这个是权限问题,一并记录一下.

方案一. 请求权限

网上一般都是在代码里添加请求权限的解决方案:

在API23+以上,不止要在AndroidManifest.xml里面添加权限

   
   

还要在JAVA代码中请求权限:

     // 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);
          }
      }

但是如果类里面没有activity只有个context,那就不能通过这种方式添加权限.可以采用第二种方案试试.

方案二. 新建文件

在下载目录先新建文件,然后再去向该目录写入文件就可以了.

        File outputFile = new File(getDownloadPath(mContext, fileName));
        outputFile.getAbsolutePath();

        public static String getDownloadPath(Context context, String fileName) {
            return getDownloadPath(context) + File.separator + fileName;
        }

        public static String getDownloadPath(Context context) {
            return context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath();
        }

stackoverflow中EACCES问题的解答

在stackoverflow中也有EACCES问题的解答.
stackoverflow: open failed: EACCES (Permission denied)

其中的高票答案还是加权限的,方案一就是其标准翻译版 : ) ,略过不表.

第二个高票答案就是方案二new文件的方式:

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:

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.

One more note, if the files are large, you may also want to look into running the IO in the background, or use callbacks.

open failed的问题先记录到这里,后续有新的发现再补充吧.

你可能感兴趣的:(解决android.system.ErrnoException: open failed)