![Android Studio开发实战:从零基础到App上线(第2版)](https://wfqqreader-1252317822.image.myqcloud.com/cover/515/26793515/b_26793515.jpg)
4.3 SD卡文件操作
本节介绍Android的文件存储方式—— SD卡的用法,包括如何获取SD卡目录信息、公有存储空间与私有存储空间的区别、在SD卡上读写文本文件、在SD卡读写图片文件等功能。
4.3.1 SD卡的基本操作
手机的存储空间一般分为两块,一块用于内部存储,另一块用于外部存储(SD卡)。早期的SD卡是可插拔式的存储芯片,不过自己买的SD卡质量参差不齐,经常会影响App的正常运行,所以后来越来越多的手机把SD卡固化到手机内部,虽然拔不出来,但是Android仍然称之为外部存储。
获取手机上的SD卡信息通过Environment类实现,该类是App获取各种目录信息的工具,主要方法有以下7种。
- getRootDirectory:获得系统根目录的路径。
- getDataDirectory:获得系统数据目录的路径。
- getDownloadCacheDirectory:获得下载缓存目录的路径。
- getExternalStorageDirectory:获得外部存储(SD卡)的路径。
- getExternalStorageState:获得SD卡的状态。
SD卡状态的具体取值说明见表4-1。
表4-1 SD卡的存储状态取值说明
![](https://epubservercos.yuewen.com/2EEE11/15253384705226606/epubprivate/OEBPS/Images/Figure-T131_106509.jpg?sign=1739413227-R9SBzv93IzbLF43fGhYLEGtRd5Uv9EMk-0-8cea574f44d731dcf8d474790ceba384)
- getStorageState:获得指定目录的状态。
- getExternalStoragePublicDirectory:获得SD卡指定类型目录的路径。
目录类型的具体取值说明见表4-2。
表4-2 SD卡的目录类型取值说明
![](https://epubservercos.yuewen.com/2EEE11/15253384705226606/epubprivate/OEBPS/Images/Figure-T131_106508.jpg?sign=1739413227-5FeVjbYszOl159m0C1dq72CBJrDB7vwd-0-dd31bd6ce28086560db464f54ec012c3)
为正常操作SD卡,需要在AndroidManifest.xml中声明SD卡的权限,具体代码如下:
![](https://epubservercos.yuewen.com/2EEE11/15253384705226606/epubprivate/OEBPS/Images/Figure-P132_106507.jpg?sign=1739413227-ob2bsvg5e79UEteq9MZ1ZsbspbrfNIBK-0-84a3edd49915c0e68b7f426a9aa07512)
下面演示一下Environment类各方法的使用效果,如图4-10所示。页面上展示了Environment类获取到的系统及SD卡的相关目录信息。
![](https://epubservercos.yuewen.com/2EEE11/15253384705226606/epubprivate/OEBPS/Images/Figure-P132_13675.jpg?sign=1739413227-z1c8bWFtIcVQyeEiLRUa3iYS06i9TR8E-0-1fe967532725c6f6321c2724f2e8d130)
图4-10 某设备上的SD卡目录信息
4.3.2 公有存储空间与私有存储空间
本来在AndroidManifest.xml里面配置了存储空间的权限,代码就能正常读写SD卡的文件。可是Android从7.0开始加强了SD卡的权限管理,即使App声明了完整的SD卡操作权限,系统仍然默认禁止该App访问外部存储。打开7.0系统的设置界面,进入到具体应用的管理页面,会发现应用的存储功能被关闭了(指外部存储),如图4-11所示。
![](https://epubservercos.yuewen.com/2EEE11/15253384705226606/epubprivate/OEBPS/Images/Figure-P132_13686.jpg?sign=1739413227-JmVQ7TEbImYcZooDndgGI1K8ArMR342R-0-788e725a7e8c618931abd2013192f979)
图4-11 系统设置页面里的SD卡读写权限开关
不过系统默认关闭存储其实只是关闭外部存储的公共空间,外部存储的私有空间依然可以正常读写。这是缘于Android把外部存储分成了两块区域,一块是所有应用均可访问的公共空间,另一块是只有应用自己才可访问的专享空间。之前讲过,内部存储保存着每个应用的安装目录,但是安装目录的空间是很紧张的,所以Android在SD卡的“Android/data”目录下给每个应用又单独建了一个文件目录,用于给应用保存自己需要处理的临时文件。这个给每个应用单独建立的文件目录,只有当前应用才能够读写文件,其他应用是不允许进行读写的,故而“Android/data”目录算是外部存储上的私有空间。这个私有空间本身已经做了访问权限控制,因此它不受系统禁止访问的影响,应用操作自己的文件目录就不成问题了。当然,因为私有的文件目录只有属主应用才能访问,所以一旦属主应用被用户卸载,那么对应的文件目录也会一起被清理掉。
既然外部存储分成了公共空间和私有空间两部分,这两部分空间的路径获取也就有所不同。获取公共空间的存储路径,调用的是Environment.getExternalStoragePublicDirectory方法;获取应用私有空间的存储路径,调用的是getExternalFilesDir方法。下面是分别获取两个空间路径的代码例子:
![](https://epubservercos.yuewen.com/2EEE11/15253384705226606/epubprivate/OEBPS/Images/Figure-P133_106506.jpg?sign=1739413227-xtHeQLog0w2LdO16Q6CxhSCh04A8Rq7Y-0-9d94dd1ad95dddbfdd8603617c1df0a4)
该例子运行之后获得的路径信息如图4-12所示,可见应用的私有空间路径位于“外部存储根目录/Android/data/应用包名/files/Download”这个目录之下。
![](https://epubservercos.yuewen.com/2EEE11/15253384705226606/epubprivate/OEBPS/Images/Figure-P133_13760.jpg?sign=1739413227-g3450MyLaipdDtPeKXSEpsKlzGF666oV-0-a12cd6d60ed8bdca887b1cb1b2d941bb)
图4-12 公共存储与私有存储的各自目录路径
4.3.3 文本文件读写
文本文件的读写一般借助于FileOutputStream和FileInputStream。其中,FileOutputStream用于写文件,FileInputStream用于读文件。文件输出输入流是Java语言的基础工具,这里不再赘述,直接给出具体的实现代码:
![](https://epubservercos.yuewen.com/2EEE11/15253384705226606/epubprivate/OEBPS/Images/Figure-P133_106505.jpg?sign=1739413227-OWxkIkhF4n2wag7ggutzpmP3JQ2brRB9-0-579e8cb2af3b7320192bd629ecabc656)
文本文件的读写效果如图4-13所示,此时App把注册信息保存到SD卡的文本文件中。接着进入文件列表读取页面,选中某个文件,页面就展示该文件的文本内容,如图4-14所示。
![](https://epubservercos.yuewen.com/2EEE11/15253384705226606/epubprivate/OEBPS/Images/Figure-P134_13923.jpg?sign=1739413227-Ke9h0TkE3aEUH7LnL2ADm7NP7EbReRux-0-82231e44c83cb19ddd22035f32bd8458)
图4-13 将注册信息保存到文本文件
![](https://epubservercos.yuewen.com/2EEE11/15253384705226606/epubprivate/OEBPS/Images/Figure-P134_13924.jpg?sign=1739413227-UNqTZNT2wkRC0V75l0gyznasnMK8QNki-0-57291d4c47fcdda327b238ca695d5ab0)
图4-14 从文本文件读取注册信息
4.3.4 图片文件读写
Android的图片处理类是Bitmap,App读写Bitmap可以使用FileOutputStream和FileInputStream。不过在实际开发中,读写图片文件一般用性能更好的BufferedOutputStream和BufferedInputStream。
保存图片文件时用到Bitmap的compress方法,可指定图片类型和压缩质量;打开图片文件时使用BitmapFactory的decodeStream方法。读写图片的具体代码如下:
![](https://epubservercos.yuewen.com/2EEE11/15253384705226606/epubprivate/OEBPS/Images/Figure-P135_106501.jpg?sign=1739413227-hIS8ndASfayjc8Sh4WxT6yXLB4pvc6YN-0-6d6a3f1f19db04b62cf6a93eb8471201)
接下来是演示时间,如图4-15所示,用户在注册页面录入注册信息,App调用getDrawingCache方法把整个注册界面截图并保存到SD卡;然后在另一个页面的图片列表选择SD卡上的指定图片文件,页面就会展示上次保存的注册界面图片,如图4-16所示。
![](https://epubservercos.yuewen.com/2EEE11/15253384705226606/epubprivate/OEBPS/Images/Figure-P136_14129.jpg?sign=1739413227-E4u4DZ9pTWHK1QuDLYgVnQ9LbwYO3U8K-0-163c109389acb0f0ca82ffda588c7e5a)
图4-15 保存注册信息图片
![](https://epubservercos.yuewen.com/2EEE11/15253384705226606/epubprivate/OEBPS/Images/Figure-P136_14130.jpg?sign=1739413227-o1F7LSeC5ubO1lcuQLDghB77cglti2jc-0-247a4a411102c198719dd83bf657afac)
图4-16 读取注册信息图片
刚才从SD卡读取图片文件用到了BitmapFactory的decodeStream方法,其实BitmapFactory还提供了其他方法,用起来更简单、方便,说明如下:
- decodeFile:该方法直接传文件路径的字符串,即可将指定路径的图片读取到Bitmap对象。
- decodeResource:该方法可从资源文件中读取图片信息。第一个参数一般传getResources(),第二个参数传drawable图片的资源id,如R.drawable.phone。