永远看不懂的Java IO
有一件非常蛋疼的事情,每次准备面试去看Java IO的时候,心里总是无数只草泥马跑过- -
最近心血来潮在看Java编程思想,我简直越看越😓。
姑且把自己的理解先记下来,有空慢慢补。
基本结构
众所周知,两种:基于字节和基于字符。
字节流:通过8位字节来实现输入输出,处理的是字节(byte)和字节数组。适用于音频文件,图片,歌曲等。
所有的字节流类都继承自InputStream和OutputStream。
字符流:处理的单元为两个字节的Unicode字符,分别操作字符(char),字符数组或者字符串(String)。(字符流由Java虚拟机将字节转化为2个字节地Unicode字符而成,所以对文本的支持比较好)。
所有的字符流都继承自Reader和Writer。
注意:所有文件的储存是都是字节(byte)的储存,在磁盘上保留的并不是文件的字符而是先把字符编码成字节,再储存这些字节到磁盘。在读取文件(特别是文本文件)时,也是一个字节一个字节地读取以形成字节序列。
在两者之间还会有一些转换,这时候可以用InputStreamReader(从InputStream字节流转换为Reader的字符流)。这时候需要制定字符编码,否则会默认采用系统的编码,出现乱码。
字节流
InputStream
其中用的比较多的FileInputStream和BufferedInputStream
- FileInputStream: 以字节方式读取file.
三种构造函数
// construct by file name
FileInputStream in = new FileInputStream("/Users/lulei/Desktop/test.txt");
File file = new File("/Users/lulei/Desktop/test.txt");
// construct by file
in = new FileInputStream(file);
// construct by file descriptor
FileInputStream in2 = new FileInputStream(in.getFD());
使用方式
byte[] bytes = new byte[1024];
int temp, len = 0;
while ((temp = in.read())!= -1) {
bytes[len] = (byte) temp;
len++;
}
fs.close();
System.out.println(new String(bytes, 0, len));
- ByteArrayInputStream 流的来源是一串字节数组
构造函数
ByteArrayInputStream(byte[] buf);
ByteArrayInputStream(byte[] buf, int offset, int len);
- ObjectInputStream 读取对象类型的数据,将一个序列化的对象通过底层字节输入流读取到程序中
可以把inputstream包装到ObjectInputStream中,这样就可以直接读取对象了(这个对象必须要是serializable的)
ObjectInputStream input = new ObjectInputStream(new FileInputStream("object.data"));
MyClass object = (MyClass) input.readObject(); //etc.
input.close();
- DataInputStream 继承自FilterInputStream,算是一个装饰类。可以返回一些基本类型,而不一定要是byte。
FileInputStream fs = new FileInputStream(file);
DataInputStream dataInputStream = new DataInputStream(fs);
dataInputStream.readInt();
- BufferedInputStream 继承自FilterInputStream, 也是装饰类,可以起到一个缓冲的作用,防止每次都真正执行操作。
BufferedInputStream bis = new BufferedInputStream(fs);
bis.read();
OutputStream
OutputStream的结构与InputStream基本类似
字符流
Reader
Reader与InputStream的结构相似,但却有些不同。
比如,BufferedReader并未继承FilterReader。
一些典型的使用方法
- 缓冲输入文件 (BufferedReader)
public class BufferedInputFile {
public static String read(String fileName) throws IOException {
// reading input by lines
BufferedReader in = new BufferedReader(new FileReader(fileName));
StringBuilder sb = new StringBuilder();
String s;
while( ( s = in.readLine()) != null) {
sb.append(s);
}
in.close();
return sb.toString();
}
}
- 从内存输入 (StringReader)
下面的例子读取内存中的String,并且调用read(),每次读取一个字符
public class MemoryInput {
public static void main(String[] args) {
StringReader in = new StringReader(BufferedInputFile.read("test.txt"));
int c;
While ((c = in.read()) != -1) {
System.out.print((char)c);
}
}
}
- 格式化的内存输入
要读取格式化数据,可以使用DataInputStream, 它是一个面向字节的IO类
public class FormattedMemoryInput{
public static void main(String[] args) {
DataInputStream in = new DataInputStream(new ByteInputStream(BufferedInputFile.read("test.txt").getBytes());
in.readByte(); // 返回的就是Byte
in.readInt(); // 返回的就是int
}
}