最近学习了android关于文件存储的一些知识,这里记录一下。
ps:本人是android初学者,文中若有说的不对,欢迎各位大神指出。
android提供了三种简单的数据保存技术,本篇主要记录有关文件存储的方式
文件字节输出流对文件写操作
/**文件字节输出流对文件写操作
* @param filename 需要写入的文件名字,如果没有会自动创建一个
* @param saveText 需要保存的字符串
* filename是文件的名字,不需要加入路径,eg.
* String filename = "login"
* openFileOutput方法,指定且不能修改的路径:
* /data/data/<包名>/files
* 调用此方法,仅需要传入文件名而不用指定路径
* 通过FileOutputStream.write写数据的时候,数据首先是存放在缓冲区的,当缓冲区满的时候向文件
* 写入数据,在调用close()之前需要调用flush()方法,作用是把当前缓冲区的数据全部写入到文件中
* 如果没有flush(),会有部分少量数据在缓冲区里面没有写入文件,直接close就会导致这些数据丢失
* 此方法是覆盖式写法
*/
public void write_of_FileOutputStream(String filename,String saveText){
FileOutputStream fos = null;
try {
fos = openFileOutput(
filename,
MODE_PRIVATE //
); //返回一个FileOutputStream 对象
fos.write(saveText.getBytes());
fos.flush(); //清空缓冲区,把缓冲区里面的数据写入文件,此句必须加
}catch (IOException e){
e.printStackTrace();
}finally {
if (fos!=null){
try{
fos.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
}
在这里,首先通过openFileOutput()方法,获取一个FileOutputStream对象,然后通过这个对象,调用write()方法写入数据。注意,利用FileOutputStream来写入数据,数据先是放在缓冲区里面,当缓冲区满了,才会写入到文件里面,所以这里必须调用flush()方法,用来清空缓冲区,把缓冲区里面的数据全部写入文件,然后才可以close(),否则可能会出现部分数据没有写入文件。由于是字节写入,在write的时候需要把字符串转换成字节,通过字符串的getBytes方法。
文件字节输入流对文件读操作
/**文件字节输入流对文件读操作
* @param filename 需要读取的文件名字
* @return content 以字符串形式得到文件中的内容
*/
public String read_of_FileInputStream(String filename){
FileInputStream fis = null;
byte[] buffer = null;
String content="";
try {
// File file = new File(pathfile);
// fis = new FileInputStream(file);
fis = openFileInput(filename); //获得文件输入流,也可以使用上面两句指定路径
buffer = new byte[fis.available()]; //通过avilable方法得到文件大小
fis.read(buffer); //从输入流中读取数据
content = new String(buffer);
}catch (IOException e){
e.printStackTrace();
}finally {
if (fis!=null){
try {
fis.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
return content;
}
与字节输出流的FileOutputStream对应的字节输入流FileInputStream方法, 也是有默认的路径,所以这里只需要给出文件名而不能给出具体的路径。这一段代码,利用字节数组byte[] buffer来保存读到的数据,为了不浪费内存空间,在读取操作之前,调用available()方法,可以获得文件的大小,注意:此方法只有在一开始文件没有读写,光标在开头的时候调用才可以返回文件的大小。用得到的具体大小来构造一个字节数组,节省内存空间。最后通过字符串的构造函数把字节数组转换成为字符串返回。
文件字符输出流对文件写操作
/**文件字符输出流对文件写操作
* @param pathfile 需要写入的文件名字(带路径),如果没有会自动创建一个
* @param saveText 需要保存的字符串
* pathfile是一个完整的文件路径,eg.
* String pathfile = "/data/data/com.example.asus.savedata/files/login"
* 此方法是覆盖式写法
*/
public void write_of_FileWriter(String pathfile,String saveText){
FileWriter writer=null;
try {
File file = new File(pathfile);
writer = new FileWriter(file);
writer.write(saveText);
writer.flush();
}catch (IOException e){
e.printStackTrace();
}finally {
if (writer!=null){
try{
writer.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
}
这一段代码,通过字符输出流的方式写入文件。首先创建一个File对象,这里用的是具体的路径+文件名来实例化这个File对象,然后利用这个File对象构造出一个FileWriter对象,通过这个File Writer对象来进行读写
文件字符输入流对文件读操作
/**文件字符输入流对文件读操作
* @param pathfile 需要读入的文件名字(带路径)
* @return content.toString 以字符串形式得到文件中的内容
*/
public String read_of_FileReader(String pathfile){
StringBuilder content = new StringBuilder();
FileReader reader=null;
try {
File file = new File(pathfile); //通过路径打开文件
reader = new FileReader(file); //利用File对象创建reader对象
//进行读取操作 每次读取单个字符
// int read_char =reader.read();
// //如果读取完毕,返回-1
// while (read_char!=-1){
// //使用StringBuilder拼接字符串,比使用String相加可以节省内存浪费
// //必须要把read_char转换成char类型
// content.append((char)read_char);
// //读取下一个字符
// read_char = reader.read();
// }
//进行读取操作 读取一个字符数组然后转换成字符串
char[] chs =new char[(int)file.length()]; //使用file的length方法获取文件的大小,为了节省空间
reader.read(chs);
content.append(String.valueOf(chs));
}catch (IOException e){
Toast.makeText(this, "error", Toast.LENGTH_SHORT).show();
e.printStackTrace();
}finally {
if (reader!=null){
try {
reader.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
return content.toString();
}
这部分代码与上面的类似,在里面我写了两种读的方式,一个是按照单字符读入(注释部分),一个是读取字符数组的方式。这里说一下,按照单个字符读入的方式,首先创建一个StringBuilder 对象,通过append的方法来拼接字符串,这里不使用String对象的相加,因为我们都知道如果用String字符串的相加会造成内存空间的大量浪费。而第二种方法,是创建一个字符数组,然后一次性读取到这个字符数组中。这里面字符数组的大小很关键,如果你构建一个100大小的字符数组,即使你读取的文件是空的,你返回的字符串实际上也是占用了100大小的空间,用length看一下你就知道。所以这里在构建字符数组的使用,通过File的length方法,得到文件的大小,用这个大小来创建字符数组。
缓冲输出流对文件写操作
/**缓冲输出流对文件写操作
* @param filename 需要写入的文件名字,如果没有会自动创建一个
* @param saveText 需要保存的字符串
* filename是文件的名字,不需要加入路径,eg.
* String filename = "login"
* openFileOutput方法,指定且不能修改的路径:
* /data/data/<包名>/files
* 调用此方法,仅需要传入文件名而不用指定路径
* 此方法是覆盖式写法
*/
public void write_of_BufferedWriter(String filename,String saveText){
FileOutputStream outputStream;
BufferedWriter writer = null;
try {
outputStream = openFileOutput(
filename,
MODE_PRIVATE
);
writer = new BufferedWriter(new OutputStreamWriter(outputStream));
writer.write(saveText);
}catch (IOException e){
e.printStackTrace();
}finally {
try {
if (writer!=null){
writer.close();
}
}catch (IOException e){
e.printStackTrace();
}
}
}
这一段代码也很好理解,首先是通过openFileOutput返回一个FileOutputStream对象,用这个对象构建一个OutputStreamWriter对象,再通过OutputStreamWriter对象构建出BufferedWriter对象,然后通过BufferedWriter的方法来操作文件。
缓冲输入流对文件读操作
/**缓冲输入流对文件读操作
* @param filename 需要读取的文件名字
* @return content.toString 以字符串形式得到文件中的内容
*/
public String read_of_BufferedReader(String filename){
FileInputStream inputStream =null;
BufferedReader reader = null;
StringBuilder content = new StringBuilder(); //使用字符串拼接,节省内存
try {
inputStream = openFileInput(filename);
reader = new BufferedReader(new InputStreamReader(inputStream));
String line = "";
while ((line=reader.readLine())!=null){
content.append(line);
}
}catch (IOException e){
e.printStackTrace();
}finally {
if (reader!=null){
try {
reader.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
return content.toString();
}
和上面的写入差不多,这里不再多说。