访问SDCard抛出FileNotFoundException

本文探讨了在Android应用中使用JUnit测试访问SDCard时遇到的空指针异常问题,并分享了一种可行的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在应用中访问SDCard时,抛出空指针例外一般是由于访问文件路径出错,或者没有添加访问SDCard的权限。但是文件路径是通过Environment.getExternalStorageDirectory()得到,通过Junit测试该路径能正常获得,不会出现文件路径错误,在主配置文件中配置的访问SDCard也正确。权限配置如下:

<!-- 在SDCard中创建与删除文件的权限 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />

<!-- 往SDCard写入数据权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>可是用Junit测试访问SDCard时还能抛出空指针异常。这个问题太让人纠结了。

/**********************************************************异常信息***************************************************************/

java.io.FileNotFoundException: /mnt/sdcard/www.txt (Permission denied)
at org.apache.harmony.luni.platform.OSFileSystem.openImpl(Native Method)
at org.apache.harmony.luni.platform.OSFileSystem.open(OSFileSystem.java:152)
at java.io.FileOutputStream.<init>(FileOutputStream.java:97)
at java.io.FileOutputStream.<init>(FileOutputStream.java:69)
at cn.itcast.service.FileService.saveToSDCard(FileService.java:24)
at cn.itcast.junit.FileServiceTest.testSaveToSDCard(FileServiceTest.java:23)
at java.lang.reflect.Method.invokeNative(Native Method)
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:169)
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:154)
at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:520)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1447)


/************************************************************************************************************************************/

经过不断检查,确认并非配置或代码有误。原来的程序代码是编写了一个Juint单元测试来测试saveToSDCard()方法,但无论如何测试都不通过。后来仔细研究也没个结果,最后不得不写了一个应用发布在手机上,然后通过手机端进行文件录入,竟然成功了!但是为什么用Junit测试死活不通过?这是Android的一个BUG吗?之前使用单元测试时都没有出现过这种问题,另外,在对手机自带的存储空间的文件访问测试时也能顺利通过。唯独测试访问SDCard时不能通过测试,还在纠结中......

注:以后在对SDCard文件访问测试时,最好是老老实实写一个应用发布到手机上,通过手机录入方式进行测试,而不是使用单元测试。个人比较喜欢单元测试,可能是我对单元测试环境不十分了解,希望能有不同的解答方法。
下面是源码
### 如何在Android访问SD卡 #### 1. 基本权限声明 为了能够在Android设备上访问外部存储(如SD卡),开发者需要在`AndroidManifest.xml`文件中声明相应的权限。对于读取操作,需添加如下权限声明[^1]: ```xml <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> ``` 如果还需要写入数据到SD卡,则还需额外声明写入权限[^4]: ```xml <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> ``` #### 2. 版本兼容性处理 不同版本的Android系统对SD卡访问有不同的限制和要求。 ##### **(a) Android 9.0及以下** 在此类版本中,通过上述基本权限即可完成大部分SD卡的操作需求。然而需要注意的是,在运行动态请求这些权限是非常重要的,因为从Android 6.0 (API Level 23) 开始引入了运行权限机制: ```java if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){ ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE); } ``` ##### **(b) Android 10.0及以上** 自Android 10.0起,Google加强了对外部存储的安全性和隐私保护措施。默认情况下,应用仅能访问其沙盒内的特定区域,而无法自由遍历整个SD卡的内容。针对某些特殊场景(比如媒体文件管理器等),可以通过配置`requestLegacyExternalStorage=true`来暂绕过这一限制[^2]: ```xml <application ... android:requestLegacyExternalStorage="true"> </application> ``` > 注意:此选项将在未来版本被移除,因此建议尽早适配新的Scoped Storage模型。 另外,在更高层次的应用逻辑设计方面,推荐利用MediaStore API替代直接路径操作的方式获取多媒体资源[^5]。 #### 3. Unity中的具体实践 如果是基于Unity引擎开发跨平台项目并希望支持Android端SD卡存取功能的话,除了常规设置外还应注意几个细节问题[^3]: - 如果选择了内部模式(`Write Permission=Internal`)作为目标方案,则即使正确设置了manifest里的权限条目也仍然可能遇到无法正常打开指定位置的情况; - 对于更复杂的业务流程而言,考虑编写原生插件可能是更好的解决方案之一——即借助NDK或者JNI技术封装底层交互过程从而达到预期效果; 以下是简单的C#脚本片段用于检测当前环境是否允许执行相应动作前先验证必要的许可状态: ```csharp using UnityEngine; using System.Collections; public class SDCardAccess : MonoBehaviour { public IEnumerator CheckPermission(){ var perms = new string[] {"android.permission.READ_EXTERNAL_STORAGE", "android.permission.WRITE_EXTERNAL_STORAGE"}; foreach(var perm in perms){ if(!UnityEngine.Android.Permission.HasUserAuthorizedPermission(perm)){ yield return UnityEngine.Android.Permission.RequestUserPermission(perm); } } Debug.Log("All permissions granted."); } void Start () { StartCoroutine(CheckPermission()); } } ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值