一. 前言

1. 分类

  • 内部存储:Internal storage
  • 外部存储:External storage

2. 区别

  • 内部存储不需要用在manifest文件中声明权限,也不需要考虑android6.0的运行时权限。
  • 内部存储的空间很小,Sqlite3和SharedPreferences产生的文件都存放在内部存储里面。
  • 真正的内部存储在位置是data/data/包名处,其他位置都是外部存储。
  • 外部存储需要在manifest文件中声明权限,有时候需要考虑android6.0的运行时权限。
1
2
3
//在AndroidManifest.xml中申明权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//如果需要动态申请权限 参考:https://blog.csdn.net/s_qiuf/article/details/94173864
//在onCreate中添加如下代码,弹出申请权限
if (Build.VERSION.SDK_INT >= 23) {
int REQUEST_CODE_CONTACT = 101;
String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE};
//验证是否许可权限
for (String str : permissions) {
if (this.checkSelfPermission(str) != PackageManager.PERMISSION_GRANTED) {
//申请权限
this.requestPermissions(permissions, REQUEST_CODE_CONTACT);
return;
}
}
}

//官方推荐使用getExternalFilesDir或者getExternalCacheDir,不需要申请权限

二. 内部存储

1. files文件夹

① 获取files文件夹路径

1
2
3
4
5
6
7
8
9
10
//一帮情况下是:data/data/包名/files
public File getFilesDir()

//小米8手机测试:
File filesDir = getFilesDir();
System.out.println(filesDir.getAbsolutePath());
//打印结果:
2020-05-26 15:03:25.653 9986-9986/? I/System.out: /data/user/0/swu.xl.internal_storage/files

//根据结果,我们应该具体情况具体对待

② 在files文件夹下创建文件

1
2
3
4
5
//name:写入的文件名
//mode:写入的模式
// MODE_PRIVATE:默认方式,如果文件不存在就会创建这个文件,如果文件存在,那么会写入的数据会覆盖之前的数据
// MODE_APPEND:追加模式,如果文件不存在就会创建这个文件,如果文件存在,那么会接着写入数据
public FileOutputStream openFileOutput(String name, int mode)

③ 读取files文件夹下文件

1
2
//name:读取的文件名
public FileInputStream openFileInput(String name)

④ 删除files文件夹下文件

1
2
//name:删除的文件名
public boolean deleteFile(String name)

⑤ 获取files文件夹下文件信息

1
public String[] fileList()

⑥ 实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
public class MainActivity extends AppCompatActivity {
public static final String TAG = MainActivity.class.getSimpleName();

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

String fileName = "xl.txt";

File filesDir = getFilesDir();
System.out.println(filesDir.getAbsolutePath());

//writeMessageToFile(fileName);
//addMessageToFile(fileName);
//readMessageFromFile(fileName);
//deleteFromFile(fileName);
//getFileList();
//addDirInFiles();
}

/**
* data/data/包名/file/fileName 向文件中写入信息
* @param fileName
*/
public void writeMessageToFile(String fileName){
try {
//1.使用MODE_PRIVATE模式创建xl.txt文件
FileOutputStream fos = openFileOutput(fileName, MODE_PRIVATE);
//2.创建一个实现了Serializable接口的User对象,实现Serializable接口才可以通过流写入
User user = new User("xl", 21);
//3.写入并冲刷
fos.write(user.toString().getBytes());
fos.flush();
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
Log.d(TAG,e.getMessage());
} catch (IOException e) {
Log.d(TAG,e.getMessage());
e.printStackTrace();
}
}

/**
* data/data/包名/file/fileName 向文件中追加信息
* @param fileName
*/
public void addMessageToFile(String fileName){
try {
//1.使用MODE_PRIVATE模式创建xl.txt文件
FileOutputStream fos = openFileOutput(fileName, MODE_APPEND);
//2.创建一个实现了Serializable接口的User对象,实现Serializable接口才可以通过流写入
User user = new User("xl", 22);
//3.写入并冲刷
fos.write(user.toString().getBytes());
fos.flush();
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
Log.d(TAG,e.getMessage());
} catch (IOException e) {
Log.d(TAG,e.getMessage());
e.printStackTrace();
}
}

/**
* data/data/包名/file/fileName 读取文件中的信息
* @param fileName
*/
public void readMessageFromFile(String fileName){

try {
//1.存储读取的数据
StringBuilder message = new StringBuilder();

//2.存储每次读取的数据
byte[] bytes = new byte[1024];

//3.打开文件
FileInputStream fis = openFileInput(fileName);

//4.读取内容
int len = 0;
while ((len = fis.read(bytes)) != -1){
message.append(new String(bytes,0,len));
}
fis.close;

//5.测试
Log.d(TAG,message.toString());
} catch (FileNotFoundException e) {
e.printStackTrace();
Log.d(TAG,e.getMessage());
} catch (IOException e) {
e.printStackTrace();
Log.d(TAG,e.getMessage());
}
}

/**
* data/data/包名/file/fileName 删除文件
* @param fileName
*/
public void deleteFromFile(String fileName){
deleteFile(fileName);
}

/**
* data/data/包名/file/ 文件信息
*/
public void getFileList(){
String[] files = fileList();
for (String file : files) {
Log.d(TAG,file);
}
}

/**
* data/data/包名/file/ 创建文件夹text
*/
public void addDirInFiles(){
File file = new File(getFilesDir().getAbsolutePath(), "/text");
if (!file.exists()){
file.mkdir();
}
}
}

1> 使用writeMessageToFile创建xl.txt文件并写入信息的结果

2> 使用readMessageFromFile读取xl.txt文件信息结果

1
2020-05-26 14:37:40.856 5753-5753/swu.xl.internal_storage D/MainActivity: User{name='xl', age=21}

3> 使用addMessageToFile向xl.txt文件追加信息的结果

4> 使用deleteFromFile删除xl.txt文件,右键同步files文件夹,发现xl.txt文件的确被删除了

5> 使用getFileList获取files文件夹下的文件信息(提前创建好了xl_1.txt和xl_2.txt文件)

1
2
2020-05-26 14:50:52.155 7061-7061/swu.xl.internal_storage D/MainActivity: xl_1.txt
2020-05-26 14:50:52.155 7061-7061/swu.xl.internal_storage D/MainActivity: xl_2.txt

6> 使用addDirInFiles在files文件夹下创建文件夹text

2. cache文件夹

① 获取cache文件夹路径

1
2
3
4
5
6
7
8
9
10
//一般情况下:data/data/包名/cache
public File getCacheDir()

//小米8手机测试:
File cacheDir = getCacheDir();
System.out.println(cacheDir.getAbsolutePath());
//打印结果:
2020-05-26 15:29:47.462 12365-12365/? I/System.out: /data/user/0/swu.xl.internal_storage/cache

//根据结果,我们应该具体情况具体对待

② 其他操作

没有files文件夹提供的类似操作。

1
2
3
//先创建一个文件
File file = new File();
//然后再利用FileOutputStream往文件里写入数据

③ 注意

系统内存不足时,会把cache整个目录删掉吧。

3. 自定义文件夹

① 直接在内部存储空间创建文件夹

1
2
3
//name:创建的文件夹的名称,系统会自动的添加“app_”前缀,不影响访问
//mode:创建文件夹的模式
public File getDir(String name, int mode)

② 写入文件

没有files文件夹提供的类似操作。

1
2
3
//先创建一个文件
File file = new File();
//然后再利用FileOutputStream往文件里写入数据

③ 实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
try {
//1.在内部存储空间创建self_dir文件夹
File self_dir = getDir("self_dir", MODE_PRIVATE);
//2.获取输出流
File file = new File(self_dir, "xl.txt");
FileOutputStream fos = new FileOutputStream(file);
//FileOutputStream fos = new FileOutputStream(file,true); 追加写入
//3.写入信息
User user = new User("xl", 21);
fos.write(user.toString().getBytes());
fos.flush();
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

3. 源代码

Github地址-internal_storage模块

三. 外部存储

文件操作-外部存储

四. 其他位置

文件操作-其他位置

参考文章

Android文件存储(一)内部存储

内部存储 使用详解

Android中的存储路径之内部存储