java 输出流_【Java】输入输出流(I/O流)的全面总结+图解

▊ 输入与输出简述

输入流(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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值