项目中用到的存储方式:
2、朋友圈里的消息体——SingleMessage的存储:每个消息体用sqlite(各个表项值,图片存本地路径)、消息体里的用户头像、用户上传的图片同时下载后同时存入本地文件、缓存(防止内存溢出):
3、用户消息界面——上传、修改用户头像的存储:本地文件
我们可以将一些数据直接以文件的形式保存在设备中。例如,一些文本文件、PDF文件、音频文件和图片等。Android提供了文件读写的方法。
通过Context.openFileInput()方法获得标准Java文件输入流(FileInputStream),通过Context.openFileOutput()方法获得标准Java文件输出流(FileOutputStream)。使用Rescources.openRawResource(R.raw.my.DataFile)方法返回InputStream。
java对文件的读取操作用到了IO流:分为字符流、字节流。字节流 InputStream OutputStream
、字符流 Reader Writer ,他们都是抽象类 。
具体实现
:
字节流 FileInputStream FileOutputStream
字符流
FileReader FileWriter
字符流处理的单元为2个字节的Unicode字符,分别操作字符、字符数组或字符串,而字节流处理单元为1个字节,操作字节和字节数组。所以字符流是由Java虚拟机将字节转化为2个字节的Unicode字符为单位的字符而成的,所以它对多国语言支持性比较好!如果是音频文件、图片、歌曲,就用字节流好点,如果是关系到中文(文本)的,用字符流好点。
所有文件的储存是都是字节(byte)的储存,在磁盘上保留的并不是文件的字符而是先把字符编码成字节,再储存这些字节到磁盘。在读取文件(特别是文本文件)时,也是一个字节一个字节地读取以形成字节序列.
字节流可用于任何类型的对象,包括二进制对象,而字符流只能处理字符或者字符串; 2.
字节流提供了处理任何类型的IO操作的功能,但它不能直接处理Unicode字符,而字符流就可以。
下面是字节流的详解:
1. 如何理解输入输出流?
这是我当初在学习Java IO这一块很难理解的一块,输入输出流我们可必须以一个为参照物:我们以内存为参照物,凡是写入内存的我们叫输入流,从内存中写出的我们叫输出流。看下面的示例图
有了这样的一个概念对于我们再学习Java中的IO流我相信就会变得特别简单了。
2. 再看流的分类
流的分类,Java的流分类比较丰富,刚接触的人看了后会感觉很晕。流分类的方式很多:
1、按照输入的方向分,输入流和输出流,输入输出的参照对象是Java程序。(InputStream OutPutStream)
2、按照处理数据的单位不同分,字节流和字符流,字节流读取的最小单位是一个字节(1byte=8bit),而字符流一次可以读取一个字符(1char = 2byte = 16bit)。(InputStream Reader)
3、按照功能的不同分,分节点流和处理流,节点流是直接从一个源读写数据的流(这个流没有经过包装和修饰),处理流是在对节点流封装的基础上的 一种流,FileInputStream是一个接点流,可以直接从文件读取数据,但是BufferedInputStream可以包装 FileInputStream,使得其有缓冲功能。(FileInputStream BufferedInputStream)
其实除了以上三种分类外,还有一些常常听到的一些分类比如:对象流、缓冲流、压缩流、文件流等等。其实都是节点流和处理流的子分类。当然你也可以创建新的流类型,只要你需要。
3. 字节流:
字节流主要操作byte类型数据,以byte数组为准,主要操作类有InputStream(字节输入流)、OutputSteam(字节输出流)由于IputStream和OutputStream都是抽象类,所要要用这两个类的话,则首先要通过子类实例化对象。下面就是这两个类的一些子类结构图
1) 字节输出流:OutputStream
OutputStream是一个抽象类,要想使用它,必须通过子类来实例化它。
OutputStream类的常用方法
方法名称 |
描述 |
public void close() throws IOException |
关闭输出流 |
public void flush() throws IOException |
刷新缓冲区 |
public void write(byte[] b) throws IOException |
将一个byte数组写入数据流 |
public void write(byte[] b,int off,int len) throws IOException |
将一个指定范围的byte数组写入数据流 |
public abstract void write(int b) throws IOException |
将一个字节数据写入数据流 |
实例1:Helloworld从HelloWorld开始
功能:(向一个名为”hello.txt”的文本文件中写一个“HelloWorld”)
public static void main(String[] args) throws Exception {
// 创建一个以当前工程目录下的名为“helloworld.txt”的文本文件
File file = new File("hellowolrd.txt");
OutputStream outputStream = null;
// 通过FileOutPutStream的子类实例化OutputStream对象
outputStream = new FileOutputStream(file);
// 声明一个字符串
String str = "hello,world";
// 将字符串转换成字节数组
byte[] b = str.getBytes();
// 写入数据
outputStream.write(b);
// 关闭输出流
outputStream.close();
outputStream.flush();
}
我们可以看到当前工程目录下已经有一个helloworld.txt且里面已经有数据,如果我们把str的值改变的话,文本文件里的数据也会改变,所以我们想是不是可以不删除原来的数据,在追尾上追加上。
我们只要在构造FileOutputStream对象的时候选择另一种构造方法就可以了
FileOutputStream(File file,boolean append)
第二个参数就是是否采用追加的方式写入到文本文件中
把上面的代码修改下就可以了
outputStream = new FileOutputStream(file,true);
再从例子1我们理解我们对输入输出流的理解,在这个例子里,我们声明的字符串肯定是在内存中的,现在我们要从内存中把数据写到文本中,所以我们用到输出流。这也正符合了我对输入输出流的理解,当然大家肯定还有其他的理解方式。
2) 字节输入流:InputStream
InputStream类的常用方法
方法名称 |
描述 |
public void avaliable() throws IOException |
可以取得输入文件的大小 |
public void close() throws IOException |
关闭输入流 |
public abstract int read() throws IOException |
读取内容,以数字的方式读取 |
public int read (byte b) throws IOException |
将内容读到byte数组,同时返回读入的个数 |
与OutputStream类一样,InputStream本身也是一个抽象类,要想使用它,也必须依靠其子类。
实例2:还是HelloWorld
在上一个例子的基础上我们从文本中读取数据并且把它显示在控制台上
public static void main(String[] args) throws Exception {
// 创建一个以当前工程目录下的名为“helloworld.txt”的文本文件
// 这个文件在上一个例子里已经创建,并且里面已有数据
File file = new File("hellowolrd.txt");
// 声明InputStream对象
InputStream inputStream = null;
// 通过FileInputStream子类实例化InputStream对象
inputStream = new FileInputStream(file);
// 声明一个字节数组用以接收读入的数据
byte[] b = new byte[1024];
// 开始读入数据,将数据内容读到此数组中
inputStream.read(b);
// 关闭输入流
inputStream.close();
// 在控制台打印
System.out.println(new String(b));
}
如果以这种方式打印,我们可以看到虽然控制台里是打印出了文本文件中的内容,但是后面跟了很多空格,这是我们不需要的,对于这种情况我们有两种解决方式
方式一:声明字节数组的时候指定字节数组的长度为文本内容的长度
byte[] b=new byte[(int)file.length()];
方式二:在将字节数组转换成字符串的调用String(byte b,int off,int len)这个构造函数
System.out.println(new String(b,0,(int)file.length()));
下面是字符流:
1. 字符流
在程序中一个字符等于两个字节,Java为我们提供了Reader和Writer两个专门操作字符流的类
1) 字符输出流:Writer
Writer是一个字符流,它是一个抽象类,所以要使用它,也必须通过其子类来实例化它后才能使用它。
Writer类的常用方法
方法名称 |
描述 |
public abstract void close() throws IOException |
关闭输出流 |
public void write(String str) throws IOException |
将字符串输出 |
public void write(char cbuf) throws IOException |
将字符数组输出 |
public abstract void flush() throws IOException |
强制性清空缓存 |
示例1:HelloWorld
向一个文本文件中通过字符输出流写入数据
public static void main(String[] args) throws Exception { // 声明一个File对象 File file = new File("hellowolrd.txt"); // 声明一个Write对象 Writer writer = null; // 通过FileWriter类来实例化Writer类的对象并以追加的形式写入 writer = new FileWriter(file, true); // 声明一个要写入的字符串 String str = "字符串形式写入Helloworld"; // 写入文本文件中 writer.write(str); // 刷新 writer.flush(); // 关闭字符输出流 writer.close(); }
2) 字符输入流:Reader
Reader本身也是一个抽象类,同样,如果使用它,我们需要通过其子类来实例化它才可以使用它。
Reader类的常用方法
方法名称 |
描述 |
public abstract void close() throws IOException |
|
public int read() throws IOException |
|
public int read(char cbuf) throws IOException |
|
通过方法我们看到Reader类只提供了一个读入字符的方法
示例2:还是Helloworld
在上面的基础上把文本中的内容读出来,并且显示在控制台上
public static void main(String[] args) throws Exception { // 声明一个File对象 File file = new File("hellowolrd.txt"); // 声明一个Reader类的对象 Reader reader = null; // 通过FileReader子类来实例化Reader对象 reader = new FileReader(file); // 声明一个字符数组 char[] c = new char[1024]; // // 将内容输出 // int len = reader.read(c); //循环方式一个一个读 int len=0; int temp=0; while((temp=reader.read())!=-1){ c[len]=(char)temp; len++; } // 关闭输入流 reader.close(); // 把char数组转换成字符串输出 System.out.println(new String(c, 0, len)); }
2. 字符流与字节流的区别
操作字节流操作时本身不会用到缓冲区,是文件本身直接操作,而字节流在操作时就使用到了缓冲区。
如果我们在操作字符流的时候,不关闭流,我们写入的数据是无法保存的。所以在操作字符流的时候一定要记得关闭流