安卓系统.ErrnoException错误

8
我正在尝试使用以下代码获取内部存储详细信息(用作内部存储器的存储器)。
public void getinternalstorage() {
        StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());
        double bytesavalible = (double) stat.getBlockSizeLong() * (double) stat.getAvailableBlocksLong();
        final double gb = bytesavalible / (1024 * 1024 * 1024);
        double total = (double) stat.getBlockSizeLong() * stat.getBlockCountLong();
        final double totalgb = total / (1024 * 1024 * 1024);
        final double per = (100 - (gb / totalgb) * 100);
        update_inte((int) (per * 1), round(totalgb, 2), round((gb), 2));
        TextView text2written = (TextView) findViewById(R.id.inter);
        text2written.setText(String.valueOf(round((totalgb - gb), 2)) + " GB " + "/ " + String.valueOf(round(totalgb, 2)) + " GB");
    }

我已经取得了必要的许可。
对于Android 5.0及以下版本 -
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

对于Android 6.0及以上版本,我正在请求运行时权限。

但是我收到了大约10个用户的android.system.ErrnoException错误。 完整的堆栈跟踪:

Fatal Exception: java.lang.RuntimeException: Unable to resume activity {com.package.app.Main_Screen}: java.lang.IllegalArgumentException: Invalid path: /sdcard
       at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3121)
       at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3152)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1398)
       at android.os.Handler.dispatchMessage(Handler.java:102)
       at android.os.Looper.loop(Looper.java:148)
       at android.app.ActivityThread.main(ActivityThread.java:5443)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:728)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
Caused by java.lang.IllegalArgumentException: Invalid path: /sdcard
       at android.os.StatFs.doStat(StatFs.java:46)
       at android.os.StatFs.(StatFs.java)
       at com.package.app.Main_Screen.getinternalstorage(Main_Screen.java:565)
       at com.package.app.Main_Screen.on_resume(Main_Screen.java:785)
       at com.package.app.Main_Screen.checkPermission(Main_Screen.java:1070)
       at com.package.app.Main_Screen.onResume(Main_Screen.java:779)
       at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1281)
       at android.app.Activity.performResume(Activity.java:6320)
       at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3110)
       at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3152)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1398)
       at android.os.Handler.dispatchMessage(Handler.java:102)
       at android.os.Looper.loop(Looper.java:148)
       at android.app.ActivityThread.main(ActivityThread.java:5443)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:728)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
Caused by android.system.ErrnoException: statvfs failed: ENOENT (No such file or directory)
       at libcore.io.Posix.statvfs(Posix.java)
       at libcore.io.BlockGuardOs.statvfs(BlockGuardOs.java:298)
       at android.system.Os.statvfs(Os.java:500)
       at android.os.StatFs.doStat(StatFs.java:44)
       at android.os.StatFs.(StatFs.java)
       at com.package.app.Main_Screen.getinternalstorage(Main_Screen.java:565)
       at com.package.app.Main_Screen.on_resume(Main_Screen.java:785)
       at com.package.app.Main_Screen.checkPermission(Main_Screen.java:1070)
       at com.package.app.Main_Screen.onResume(Main_Screen.java:779)
       at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1281)
       at android.app.Activity.performResume(Activity.java:6320)
       at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3110)
       at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3152)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1398)
       at android.os.Handler.dispatchMessage(Handler.java:102)
       at android.os.Looper.loop(Looper.java:148)
       at android.app.ActivityThread.main(ActivityThread.java:5443)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:728)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)

我在5.0到7.0版本的安卓系统中遇到了这个错误。


你好 John,使用 Environment.getExternalStorageDirectory().getPath() 会得到什么结果?你是在使用模拟器吗? - Jorgesys
@JonGoodwin 是的,您是正确的。但是如何可能两个用户使用完全相同的模型,但一个有问题而另一个没有呢? - user8921228
这个问题之所以如此复杂,是因为它涉及到设备的每一个方面,包括硬件、可移动媒体、ROM、手机上的Android版本以及应用程序(您的应用)。Android从来没有喜欢外部存储中固有的安全性缺失。手机制造商具有内核访问权限,因此可以随心所欲地处理存储,而我们这些凡人程序员则无法做到。 - Jon Goodwin
我认为Environment.getExternalStorageDirectory().getPath()不能够可靠地获取外部存储路径。这个链接可以为您提供如何防止丢失SD卡路径的参考。 - aLIEz
@aLIEz 谢谢。我会尽快尝试并带来更新的结果。 - user8921228
显示剩余10条评论
2个回答

5

I) 使用外部存储目录获取路径

Environment.getExternalStorageDirectory().getPath()

你将会得到类似这样的结果:
 /storage/emulated/0
 /mnt/sdcard 
 /mnt/sdcard-ext 

但是错误指出你只得到了/sdcard

由于java.lang.IllegalArgumentException引起:无效路径:/sdcard at android.os.StatFs.doStat(StatFs.java:46) at android.os.StatFs.(StatFs.java)

如果我们检查引发此错误的SDK方法:

private static StructStatVfs doStat(String path) {
    try {
        return Os.statvfs(path);
    } catch (ErrnoException e) {
        throw new IllegalArgumentException("Invalid path: " + path, e);
    }
}

函数statvfs()返回已挂载文件系统的信息。path是已挂载文件系统中任何文件的路径名。

因此,为避免此问题,您必须确保SD卡已挂载!在所有生产用户中保证这一点是困难的,选项将是进行验证。

顺便说一下,我建议使用getAbsolutePath()

Environment.getExternalStorageDirectory().getAbsolutePath();

替代

Environment.getExternalStorageDirectory().getPath();

为了获取绝对路径,需要将相对路径解析为当前目录下的路径,从而获得“完全合格的路径”。

II) 显示的另一个错误信息是:

由 android.system.ErrnoException 引起:statvfs 失败:ENOENT(没有这个文件或目录) 在 libcore.io.Posix.statvfs(Posix.java)

记住,您的应用程序无法读取内部存储器,必须手动在6.0+设备中请求WRITE_EXTERNAL_STORAGE(默认包含 READ_EXTERNAL_STORAGE)权限。

这将导致:

ENOENT(没有这个文件或目录)

因为用户必须接受该权限。


有关于 -1 的解释吗?如果我有错误,我想改进我的答案。 - Jorgesys

0

你好,请按照以下步骤检查。

1)请首先在代码中检查最新设备的运行时权限,有关此内容请参见下面的链接。

https://developer.android.com/training/permissions/requesting.html

2) 你需要使用环境变量。 Environment.getExternalStorageDirectory(); 。在Environment.java中有许多方法。这取决于您需要什么信息。例如,要获取外部存储名称,您可以使用Environment.getExternalStorageDirectory().getName(); 还有其他方法可供使用。对于内部存储,API可能不会公开提供。

StatFs stat = new StatFs(type.getPath());
long bytesAvailable = (long)stat.getBlockSize()*(long)stat.getAvailableBlocks();  
long megAvailable = bytesAvailable / (1024 * 1024);  
Log.i("TAG","Available size in MB : "+megAvailable); 

请查看以下两个链接,它们也会对您有所帮助。 希望这能帮到您。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接