前言
当我们将手机连接到电脑上时,我们发现在SD卡的根目录下生成了成百上千的由各种应用程序创建的文件夹,导致我们也不知道哪个文件夹是用来干嘛的,这正因为这样安卓开发人员经常受到用户的吐槽。
的确作为一个安卓开发者,我们的确不应该将我们应用的数据直接存到SD卡的根目录下,这样当手机安装了大量的app时,SD卡根目录会迅速变得杂乱不堪。
获取SD卡的根目录(/storage/sdcard0):
File file = Environment.getExternalStorageDirectory();
为了方便管理,我们一般将app中的文件分为两种:app私有文件和app公共文件
接下来我们将针对这两类文件分别应该存放在什么样的路径下做具体的讲解。
app公共文件
app公共文件指的是那些不依赖于某特定app的文件,例如照片等。
这类文件当我们删除应用之后,还应该保留在手机上的,不应该随着删除应用而被删除掉。
对于这类文件,Android给我们提供了特定的目录,即SD卡的九大公有目录,我们可以通过Environment.getExternalStoragePublicDirectory(String type)来进行获取,这些目录的type都是以DIRECTORY开头的,例如:DIRECTORY_MUSIC , DIRECTORY_PICTURES.
使用如下代码访问:
File file = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
SD卡内置的九大公有目录一览表:
方法 | 路径 | 用途 |
---|---|---|
Environment.DIRECTORY_ALARMS | /storage/sdcard0/Alarms | 警报的铃声 |
Environment.DIRECTORY_DCIM | /storage/sdcard0/DCIM | 相机拍摄的图片和视频保存的位置 |
Environment.DIRECTORY_DOWNLOADS | /storage/sdcard0/Download | 下载文件保存的位置 |
Environment.DIRECTORY_MOVIES | /storage/sdcard0/Movies | 电影保存的位置 |
Environment.DIRECTORY_MUSIC | /storage/sdcard0/Music | 音乐保存的位置 |
Environment.DIRECTORY_NOTIFICATIONS | /storage/sdcard0/Notifications | 通知音保存的位置 |
Environment.DIRECTORY_PICTURES | /storage/sdcard0/Pictures | 下载的图片保存的位置 |
Environment.DIRECTORY_PODCASTS | /storage/sdcard0/Podcasts | 用于保存podcast(博客)的音频文件 |
Environment.DIRECTORY_RINGTONES | /storage/sdcard0/Ringtones | 保存铃声的位置 |
APP私有文件
这类文件应该是随着app删除而一起删除的,它们可以被存储在两个地方:internal storage 和 external storage 。 internal storage就是手机自带的一块存储区域,通常很小;external storage就是通常所说的SD卡,通常很大,有16GB,32GB等。
internal storage很小,所以你就应该很正确的使用它,因为SD卡有可能会被用户卸下,换成新的,所以SD卡不是任何时间都可用的,因此我们必须将一些重要的数据库文件以及一些用户配置文件存放在internal storage中。将一些大的图片或文件等缓存放到external storage中。
存储在internal storage
目录为data/data/< package name >/files/
访问方法为:
File filesDir = getFilesDir();
Log.i(TAG,"file_dir="+filesDir);
众所周知我们app中创建的SharedPreference配置文件默认就是保存在该目录下的。
Android提供了两种方法来快捷的访问内部存储目录:getCacheDir()和getFilesDir()方法:
1,getCacheDir()方法用于获取/data/data/< package name>/cache目录
2,getFilesDir()方法用于获取/data/data/< package name>/file目录
存储在external storage
对于需要存储在SD卡上的私有文件我们不应该直接存在SD卡的根目录下,而应该存在mnt/sdcard/Android/data/< package name >/files/…这个目录下。这类文件应该随着App的删除而一起删除。例如一种格式的电子书,只有该app才可以打开,如果用户删除了该app,那么留下来的电子书就成为了一种无法打开的垃圾文件,所以应该随着该app一起删除掉。
获得这个路径的方法:
File externalFilesDir = getExternalFilesDir(null);
Log.i(TAG, "externalFileDir = "+externalFilesDir);
我们注意到上面的getExternalFilesDir(null)参数传入的为null,这样默认访问的是files文件夹,我们可以指定子文件夹:
File externalFilesDir = getExternalFilesDir("Caches");
Log.i(TAG, "externalFileDir = "+externalFilesDir);
SD卡操作时必须添加权限
① SDCard中创建与删除文件权限
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
② 从SDCard中读取文件的权限
< uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
③ 向SDCard中写入文件的权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
判断SD卡是否可用
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
// SD卡可用
} else {
Toast.makeText(MainActivity.this,"SD卡不可用,请检查SD卡",Toast.LENGTH_LONG).show();
}
创建File对象的三种方式:
File对象代表一个具体的文件或者一个文件夹,其构造方法有三个:
// 通过将给定路径名字符串转换成抽象路径名来创建一个新 File 实例
File(String pathname)
// 根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例
File(String parent, String child)
// 通过给定的父抽象路径名和子路径名字符串创建一个新的File实例
File(File parent, String child);
如:
// 创建一个文件夹
new File(Environment.getExternalStorageDirectory(),"test");
// 创建一个文件
new File(Environment.getExternalStorageDirectory(),"test.apk");
获取SD卡的可用空间并显示在界面上
public void getSize(){
myTextView.setText("");
myBar.setProgress(0);
//判断是否有插入存储卡
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
File path =Environment.getExternalStorageDirectory();
//取得sdcard文件路径
StatFs statfs=new StatFs(path.getPath());
//获取block的SIZE
long blocSize=statfs.getBlockSize();
//获取BLOCK数量
long totalBlocks=statfs.getBlockCount();
//己使用的Block的数量
long availaBlock=statfs.getAvailableBlocks();
String[] total=filesize(totalBlocks*blocSize);
String[] availale=filesize(availaBlock*blocSize);
//设置进度条的最大值
int maxValue=Integer.parseInt(availale[0]);
myBar.getMax()/Integer.parseInt(total[0]);
myBar.setProgress(maxValue);
String Text="总共:"+total[0]+total[1]+"/n"
+"可用:"+availale[0]+availale[1];
myTextView.setText(Text);
}else
if(Environment.getExternalStorageState().equals(Environment.MEDIA_REMOVED)){
Toast.makeText(getStorageActivity.this, "没有sdCard",1000).show();
}
}
//返回数组,下标1代表大小,下标2代表单位 KB/MB
String[] filesize(long size){
String str="";
if(size>=1024){
str="KB";
size/=1024;
if(size>=1024){
str="MB";
size/=1024;
}
}
DecimalFormat formatter=new DecimalFormat();
formatter.setGroupingSize(3);
String result[] =new String[2];
result[0]=formatter.format(size);
result[1]=str;
return result;
}