▊ 输入与输出简述
输入流(Inout Stream)与输出流(Output Stream)合称为数据流(Data Stream)
输入输出流的来源和接收者可以是文件、内存、网络连接等 写入数据的原理:Java程序→JVM→OS→OS调用写入数据的方法→写入成功→手动释放OS资源
读取数据的原理:Java程序→JVM→OS→OS调用读取数据的方法→读取成功→手动释放OS资源
▊ Java流顶层父类
它们都是抽象类,是所有相关类的超类。 定义了输入流的一些共性方法:read(), close();以及输出流的一些共性方法:write(), flush(), close()
输入流输出流字节流InputStreamOutputStream字符流ReaderWriter
io包中的类可分为两种:字节流(Byte Stream)和字符流(Character Stream) 字节流是最底层的,因而可以处理任何类型的文件。
▊ 文件字节流
一切皆为字节(文本、图片、视频),即皆为二进制数据。 字节输出流
// FileOutputStream有两种构造方法(第二个参数设为true,则不会【覆盖】而是【续写】)
FileOutputStream fos = new FileOutputStream("D:\\Demo\\loli.txt");
FileOutputStream fos = new FileOutputStream(new File("D:\\Demo\\loli.txt"));
// write有三种重载:
write(int b) ——— 如果0-127,则查询ASCII表;否则,查询GBK表
write(byte[] b) ——— 数组的值被byte类型限制在了-128-127.如果遇到负数,则与接下来的字节组成两个字节,并查询GBK中文显示
write(byte[] b, int off, int len) ——— 指定数组的某个范围
// 写入字符串
可以利用getBytes()方法将字符串转化为字节数组
// demo:
fos.write(97); // a
byte[] bytes = {65, 66, 67}; fos.write(bytes); // ABC
byte[] bytes = {-65, 66, 67}; fos.write(bytes); // 緽C
byte[] bytes = {65, -66, 67}; fos.write(bytes); // A綜
fos.write("萝莉".getBytes()); // 萝莉
fos.write("\r\n".getBytes()); // 换行(linux是/n, mac是/r)
字节输入流
// 同样的两种构造方法
FileInputStream fis = new FileInputStream("D:\\Demo\\loli.txt");
FileInputStream fis = new FileInputStream(new File("D:\\Demo\\loli.txt"));
// 一次读一个字节
int content = 0;
while((content = fis.read()) != -1) {
System.out.println(char(content)); // 将 A, B, C, D, E 依次读取出来
}
// 一次读取多个字节
byte[] bytes = new byte[2];
int len = 0;
while ((len = fis.read(bytes)) != -1) {
System.out.println(new String(bytes, 0, len)); // 打印 AB, CD, E
}
// 注
1.读取字节时(每次read一次),指针会自动向后移动
2.read()方法的返回值就是读取的字节内容;read(byte[])方法的返回值是"有效字节的长度",读取的内容在byte[]数组中
3.byte[]数组的作用是"缓存"————我们可以控制每次读取字节的数量,并将读取的字节缓存在数组中。并根据"有效字节的长度"读取出来
比如上面的ABCDE,如果一直读下去,这个缓冲数组的内容是:[A, B], [C, D], [E, D], [E, D]...对应的"有效字节的长度"是2, 2, 1, -1...
其实,随着指针的移动,每次新读取的字节都会"不完全覆盖"之前的内容————[C, D]->[E, D]时的D就是未被覆盖掉的。
4.对于一个字节,用char()转换类型就好;如果是个byte[]数组,可以用利用String()构造方法
▶ 练习——复制文件
FileInputStream fis = new FileInputStream(new File("D:\\Demo\\loli.jpg")); // 读
FileOutputStream fos = new FileOutputStream(new File("D:\\Demo\\suki.jpg")); // 写
int len = 0;
byte[] bytes = new byte[1024]; // 使用缓冲数组
while((len = fis.read(bytes)) != -1){ // 经典写法,必须背会
fos.write(bytes, 0, len); // write()方法正好可以用到读出的字节数组与有效长度len
}
fos.close(); // 先关闭写
fis.close(); // 再关闭读
▊ 文件字符流
字节流更适合底层的输入输出,字符流则更适合处理一个文本文件。 字符输出流
// 同样(第二个参数设为true,则不会【覆盖】而是【续写】)
FileWriter fw = new FileWriter("D:\\Demo\\suki.txt");
FileWriter fw = new FileWriter(new File("D:\\Demo\\suki.txt"));
fw.write(int c)
fw.write(char[] cbuf) // 字符串还需要toCharArray()
fw.write(char[] cbuf, int off, int len)
fw.write(String str) // 字符串也可以直接写!
fw.write(String str, int off, int len)
fw.flush();
fw.close();
flush与close的区别:
首先要明白,FileWriter和OutputStream的write()方法是不同的———后者是直接写到文件中(因为是字节);后者是写到内存缓冲区,之后再刷新到文件中(因为是字符)
而flush和close都有立即把缓冲区的数据刷新到文件中的作用————而close还会释放资源,流对象无法再使用了
字符输入流
// 还是一样的两种构造方法
FileReader fr = new FileReader("D:\\Demo\\loli.txt");
FileReader fr = new FileReader(new File("D:\\Demo\\loli.txt"));
// 一次读一个字符
int content = 0;
while((content = fr.read()) != -1) {
System.out.println(char(content)); // 萝 莉 s u k i
}
// 一次读取多个字符
char[] chars = new char[2];
int len = 0;
while ((len = fr.read(chars)) != -1) {
System.out.println(new String(chars, 0, len)); // 萝莉s uki
}
▊ 缓冲流
利用缓冲区实现。上面的四个文件节点流,就分别对应四个缓冲处理流。
---------------------- Demo: 字符输出缓冲流 -------------------------
BufferedWriter bw = new BufferedWriter(new FileWriter(new File("D:\\Demo\\loli.txt")));
bw.write("萝莉赛高");
bw.close();
---------------------- Demo: 字符输入缓冲流 -------------------------
BufferedReader br = new BufferedReader(new FileReader(new File("D:\\Demo\\loli.txt")));
String line = null;
while((line = br.readLine()) != null){ // 多了一个好用的readLine()方法
System.out.println(line);
}
br.close();
不再赘述 "字节缓冲流" 完整demo,只给出连接流的过程:
BufferedInputStream bi = new BufferedInputStream(new FileInputStream(new File("D:\\Demo\\loli.txt")));
BufferedOutputStream bo = new BufferedOutputStream(new FileOutputStream(new File("D:\\Demo\\loli.txt")));
注:write(),read()方法的多种重载,与上面所讲的完全一致
▊ 转换流
转换流是字节流流向字符流的单向桥梁。是Reader的子类。
------------------ Demo: System.in是输入字节流,下面把它转化成字符流再用BufferedReader包装 -----------------------
BufferedReader bufferReader = new BufferedReader(new InputStreamReader(System.in));
String line = null;
while((line = bReader.readLine()) != null){
if(line.equals("exit")){ // 如果输入"exit"就退出
System.exit(1);
}
System.out.println("输入内容:" + line); // 每次"回车"后,读取一行内容
}
bufferReader.close();
▊ 对象流
即序列化,作用是对象实例变量的状态保持。
---------------------------------------- 序列化对象 ----------------------------------------------
Person person = new Person("Chino", 10); // 这个对象必须是实现Serializable接口的
ObjectOutputStream objWriter = new ObjectOutputStream(new FileOutputStream(new File("D:\\Demo\\person.txt")));
objWriter.writeObject(person);
objWriter.close();
---------------------------------------- 反序列化对象 ----------------------------------------------
ObjectInputStream objReader = new ObjectInputStream(new FileInputStream(new File("D:\\Demo\\person.txt")));
Person person = (Object)objReader.readObject();
objReader.close();
▊ I/O流大家庭
分类 字节输入流 字节输出流字符输入流字符输出流抽象基类InputStreamOutputStreamReaderWriter访问文件FileInputStreamFileOutputStreamFileReaderFileWriter访问数组ByteArrayInputStreamByteArrayOutputStreamCharArrayReaderCharArrayWriter访问管道PipedInputStreamPipedOutputStreamPipedReaderPipedWriter访问字符串StringReaderStringWriter转换流InputStreamReaderOutputStreamWriter对象流ObjectInputStreamObjectOutputStream过滤流FilterInputStreamFilterOutputStreamFilterReaderFilterWriter缓冲流BufferedInputStreamBufferedOutputStreamBufferedReaderBufferedWriter打印流PrintStreamPrintWriter推回输入流PushbackInputStreamPushbackReader数据流DataInputStreamDataOutputStream
注:
紫色 的是抽象基类,是无法new出对象的粗体的流称为节点流,必须直接连接真实的物理节点;其他的称为处理流,作用是连接另一个流对其进行包装
▊ 拾遗
只知道"面相字节的流在处理汉字文本时很容易出现乱码问题,因此引入了字符流"是不够的,我们需要对【编码】有一个大致的了解: 戳这里:《【图文】有趣、通俗、严谨地解释ASCII、DBK、unicode、utf-8的区别(建议收藏)》Java中的字符使用utf-16(unicode的一种实现方式)编码,在第0平面内,所有字符都是严格的2字节,即码元为2字节网络流Socket是java.net虽然不是java.io包中的,但也是字节流。这篇文章简单有趣的介绍了Socket流:《《Head First Java》读书笔记(肆)》本文只是简单介绍了对象流,并未展开来说对象的序列化与反序列化。这篇文章同样是图解,并罗列了序列化的相关知识点:《《Head First Java》读书笔记(叁)》
♪ End
♬ By a Lolicon