Android 应用提供内部和外部存储,分别用于存放应用自身数据以及应用产生的用户数据。可以通过相关 API 接口获取对应的目录,进行文件操作
Environment.getExternalStorageDirectory()
Environment.getExternalStoragePublicDirectory()
//路径:data/data/包名/file
Context.getFilesDir()
//路径:data/data/包名/cache
Context.getCacheDir
只有您的应用可以访问此处保存的文件,当用户卸载您的应用时,系统会从内部存储中移除您的应用的所有文件。
在内部存储中保存文件时,您可以通过调用以下两种方法之一获取作为 File 的相应目录:
1.getFilesDir()
返回表示您的应用的内部目录的 File 。我们在使用内部存储的方法存储数据的时候,不需要用在manifest文件中声明权限,也不需要考虑android6.0的运行时权限的
2.getCacheDir()
获取内部存储空间的缓存路径。他并没有类似openFileOutput和openFileInput的方法也没偶遇delete和fileList的方法。所以如果要往这个文件夹下写入文件就要用一般用到的File file = new File(); 先创建一个文件,然后再利用FileOutputStream往文件里写入数据
务必删除所有不再需要的文件并对在指定时间您使用的内存量实现合理大小限制,
3. getDir()
这个方法其实是直接在内部存储空间创建文件夹的方法。
File dir = getDir("xavier", MODE_PRIVATE);
这个xavier文件夹是和上面所说的file和cache是同级的,路径为data/data/包名。而且我们发现他会自动往我们的“xavier”参数前,加一个app_,
File file = newFile(context.getFilesDir(), filename);
安卓还为我们提供了一个简便方法 openFileOutput()
来读写应用在内部存储空间上的文件
String filename = "myfile";
String string = "Hello world!";
FileOutputStream outputStream;
try{
outputStream = openFileOutput(filename, Context.MODE_PRIVATE);
outputStream.write(string.getBytes());
outputStream.close();
} catch(Exception e) {
e.printStackTrace();
}
1、内部存储空间的路径为data/data/包名
2、内部存储空间只有file文件夹下的读,写,删,操作系统给我们提供了。
3、内部存储空间的文件都是只能本程序访问,其他程序没有权限访问。
4、内部存储空间的文件 在应用被卸载的时候会被一并删除,更新的时候不会。
5、访问内部存储空间,并不需要任何的权限。
6、内部存储空间其实就是手机的内存,所以不能往这里面存入太大的文件,不然手机没有内存就无法正常使用了。
7、cache与files的差别在于,如果手机的内部存储空间不够了,会自行选择cache目录进行删除,因此,不要把重要的文件放在cache文件里面,可以放置在files里面
当使用外部存储时,必须检查外部存储的可用性,当用Environment.getExternalStorageState()查询外部存储状态,当其等于Environment.MEDIA_MOUNTED时,可以对您的文件进行读写;
* Checks if external storage is available for read and write */
public boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
return true;
}
return false;
}
只读检查:
// 只读检查
public boolean isExternalStorageReadable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
return true;
}
return false;
}
外部存储中的文件是可以被用户或者其他应用程序修改的,有两种类型的文件(或者目录),
文件是可以被自由访问,且文件的数据对其他应用或者用户来说都是由意义的,当应用被卸载之后,其卸载前创建的文件仍然保留;
如果你想在外存储上放公共文件你可以使用getExternalStoragePublicDirectory()
public File getAlbumStorageDir(String albumName) {
// Get the directory for the user's public pictures directory.
File file = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), albumName);
if(!file.mkdirs()) {
Log.e(LOG_TAG, "Directory not created");
}
returnfile;
}
在上面的代码中我们创建获得了存放picture的目录,并且新创建一个albumName文件。
如果你的api 版本低于8,那么不能使用getExternalStoragePublicDirectory(),而是使用Environment
.getExternalStorageDirectory(),他不带参数,也就不能自己创建一个目录,只是返回外部存储的根路径。
其实由于是外部存储的原因即是是这种类型的文件也能被其他程序访问,只不过一个应用私有的文件对其他应用其实是没有访问价值的(恶意程序除外)。外部存储上,应用私有文件的价值在于卸载之后,这些文件也会被删除。类似于内部存储。
创建应用私有文件的方法是Context.getExternalFilesDir(),如下:
public File getAlbumStorageDir(Context context, String albumName) {
// Get the directory for the app's private pictures directory.
File file = newFile(context.getExternalFilesDir(
Environment.DIRECTORY_PICTURES), albumName);
if(!file.mkdirs()) {
Log.e(LOG_TAG, "Directory not created");
}
returnfile;
}
上面的代码创建了一个picture目录,并在这个目录下创建了一个名为albumName
的文件,Environment.DIRECTORY_PICTURES
其实就是字符串picture。
所有应用程序的外部存储的私有文件都放在根目录的Android/data/下,目录形式为/android/data/
如果你的api 版本低于8,那么不能使用getExternalFilesDir()
,而是使用Environment
.getExternalStorageDirectory()获得根路径之后,自己再想办法操作/Android/data/
也就是说api 8以下的版本在操作文件的时候没有专门为私有文件和公共文件的操作提供api支持。你只能先获取根目录,然后自行想办法。
getFilesDir,getExternalFilesDir,getExternalStorageDirectory,getExternalStoragePublicDirectory的路径:
Log.i("codecraeer", "getFilesDir = " + getFilesDir());
Log.i("codecraeer", "getExternalFilesDir = " + getExternalFilesDir("exter_test").getAbsolutePath());
Log.i("codecraeer", "getDownloadCacheDirectory = " + Environment.getDownloadCacheDirectory().getAbsolutePath());
Log.i("codecraeer", "getDataDirectory = " + Environment.getDataDirectory().getAbsolutePath());
Log.i("codecraeer", "getExternalStorageDirectory = " + Environment.getExternalStorageDirectory().getAbsolutePath());
Log.i("codecraeer", "getExternalStoragePublicDirectory = " + Environment.getExternalStoragePublicDirectory("pub_test"));
打印结果:
应用间共享文件时,不要通过放宽文件系统权限的方式去实现,而应使用FileProvider。
void getAlbumImage(String imagePath) {
File image = new File(imagePath);
Intent getAlbumImageIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
Uri imageUri = FileProvider.getUriForFile(this,
"com.example.fileprovider",
image);
getAlbumImageIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(takePhotoIntent, REQUEST_GET_ALBUMIMAGE);
}
res/xml/provider_paths.xml
AndroidManifest.xml
openFileOutput:(写入文件,如果没有文件名可以创建,这里不需要判断是否有这个文件)---> FileOutputStream
openFileInput:(读取文件,没有文件名会保存,debug的时候会看到,不影响ui)---> FileInputStream
保存文件:(FileOutputStream 保存地址;data/data/包名/files/, 下面是写入的四种模式)
MODE_APPEND:即向文件尾写入数据
MODE_PRIVATE:即仅打开文件可写入数据
MODE_WORLD_READABLE:所有程序均可读该文件数据
MODE_WORLD_WRITABLE:即所有程序均可写入数据。
private void savePackageFile() {
String msg = tvSaveMessage.getText().toString() + " \n";
FileOutputStream outputStream;
try {
outputStream = openFileOutput(filename, Context.MODE_APPEND);
outputStream.write(msg.getBytes());
outputStream.flush();
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
读取文件:(FileInputStream 读取包名下files文件夹下的文件)
private void readSaveFile() {
FileInputStream inputStream;
try {
inputStream = openFileInput(filename);
byte temp[] = new byte[1024];
StringBuilder sb = new StringBuilder("");
int len = 0;
while ((len = inputStream.read(temp)) > 0){
sb.append(new String(temp, 0, len));
}
Log.d("msg", "readSaveFile: \n" + sb.toString());
inputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
文件的初始化:(创建需要的文件)
File logFile = new File(context.getFilesDir(), MainActivity.filename);
// Make sure log file is exists
if (!logFile.exists()) {
boolean result; // 文件是否创建成功
try {
result = logFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
return;
}
if (!result) {
return;
}
}
提示:
尽管应用默认安装在内部存储中,但您可在您的清单文件中指定 android:installLocation 属性,这样您的应用便可安装在在外部存储中。当 APK 非常大且它们的外部存储空间大于内部存储时,用户更青睐这个选择。