c++ 类数组_输入输出流IO体系及常用类关系结构(精要收藏)

1、IO体系

Java IO 体系看起来类很多,感觉很复杂,但其实是 IO 涉及的因素太多了。在设计 IO 相关的类时,编写者也不是从同一个方面考虑的,所以会给人一种很乱的感觉,并且还有设计模式的使用,更加难以使用这些 IO 类,所以特地对 Java 的 IO 做一个总结。

IO 类设计出来,肯定是为了解决 IO 相关的操作的,想一想哪里会有 IO 操作?网络、磁盘。网络操作相关的类是在 java.net 包下,不在本文的总结范围内。提到磁盘,你可能会想到文件,文件操作在 IO 中是比较典型的操作。在 Java 中引入了 “流” 的概念,它表示任何有能力产生数据源或有能力接收数据源的对象。数据源可以想象成水源,海水、河水、湖水、一杯水等等。数据传输可以想象为水的运输,古代有用桶运水,用竹管运水的,现在有钢管运水,不同的运输方式对应不同的运输特性。

总体来讲,体系结果大体如下:

基于字节的IO操作

8f817906433859370ac82d486364058f.png
eda817635305933f11f09ba2d5cd86b0.png

基于字符的IO操作

87a03ed2cfb181e836eb387fd032969e.png
c33a684b1d9bad718b42036d964b798c.png

从数据来源或者说是操作对象角度看,IO 类可以分为:

  • 1、文件(file):FileInputStream、FileOutputStream、FileReader、FileWriter
  • 2、数组([]):
  • 2.1、字节数组(byte[]):ByteArrayInputStream、ByteArrayOutputStream
  • 2.2、字符数组(char[]):CharArrayReader、CharArrayWriter
  • 3、管道操作:PipedInputStream、PipedOutputStream、PipedReader、PipedWriter
  • 4、基本数据类型:DataInputStream、DataOutputStream
  • 5、缓冲操作:BufferedInputStream、BufferedOutputStream、BufferedReader、BufferedWriter
  • 6、打印:PrintStream、PrintWriter
  • 7、对象序列化反序列化:ObjectInputStream、ObjectOutputStream
  • 8、转换:InputStreamReader、OutputStreWriter
  • 9、字符串(String)Java8中已废弃:StringBufferInputStream、StringBufferOutputStream、StringReader、StringWriter

数据源节点也可以再进行二次处理,使数据更加容易使用,所以还可以划分成节点流和处理流,这里涉及到设计模式,后面会有专门的文章说。

  • 从数据传输方式或者说是运输方式角度看,可以将 IO 类分为:
  • 1、字节流
  • 2、字符流

字节流是以一个字节单位来运输的,比如一杯一杯的取水。而字符流是以多个字节来运输的,比如一桶一桶的取水,一桶水又可以分为几杯水。

字节流和字符流的区别:

字节流读取单个字节,字符流读取单个字符(一个字符根据编码的不同,对应的字节也不同,如 UTF-8 编码是 3 个字节,中文编码是 2 个字节。)字节流用来处理二进制文件(图片、MP3、视频文件),字符流用来处理文本文件(可以看做是特殊的二进制文件,使用了某种编码,人可以阅读)。简而言之,字节是个计算机看的,字符才是给人看的。

字节流和字符流的划分可以看下面这张图。

dffc1b850a43451fdfd3fc461162514c.png

按字节和字符划分.png

不可否认,Java IO 相关的类确实很多,但我们并不是所有的类都会用到,我们常用的也就是文件相关的几个类,如文件最基本的读写类 File 开头的、文件读写带缓冲区的类 Buffered 开头的类,对象序列化反序列化相关的类 Object 开头的类。

2、IO类和相关方法

IO 类虽然很多,但最基本的是 4 个抽象类:InputStream、OutputStream、Reader、Writer。最基本的方法也就是一个读 read() 方法、一个写 write() 方法。方法具体的实现还是要看继承这 4 个抽象类的子类,毕竟我们平时使用的也是子类对象。这些类中的一些方法都是(Native)本地方法、所以并没有 Java 源代码,这里给出笔者觉得不错的 Java IO 源码分析 传送门,按照上面这个思路看,先看子类基本方法,然后在看看子类中还新增了那些方法,相信你也可以看懂的,我这里就只对上后面说的常用的类进行总结。

先来看 InputStream 和 OutStream 中的方法简介,因为都是抽象类、大都是抽象方法、所以就不贴源码喽!注意这里的读取和写入,其实就是获取(输入)数据和输出数据。

InputStream 类

913f9db495b7ad6e3e0b5f23db13a878.png

InputStream 类

方法简介

public abstract int read() 读取数据;

public int read(byte b[]) 将读取到的数据放在 byte 数组中,该方法实际上是根据下面的方法实现的,off 为 0,len 为数组的长度;

public int read(byte b[], int off, int len) 从第 off 位置读取 len 长度字节的数据放到 byte 数组中,流是以 -1 来判断是否读取结束的(注意这里读取的虽然是一个字节,但是返回的却是 int 类型 4 个字节,这里当然是有原因,这里就不再细说了);

public long skip(long n) 跳过指定个数的字节不读取,想想看电影跳过片头片尾;

public int available() 返回可读的字节数量;

public void close() 读取完,关闭流,释放资源 ;

public synchronized void mark(int readlimit)标记读取位置,下次还可以从这里开始读取,使用前要看当前流是否支持,可以使用 markSupport() 方法判断 ;

public synchronized void reset() 重置读取位置为上次 mark 标记的位置;

public boolean markSupported()判断当前流是否支持标记流,和上面两个方法配套使用;

OutputStream 类

f084529554be366116399816daadcfff.png

OutputStream类

再来看 Reader 和 Writer 类中的方法,你会发现和上面两个抽象基类中的方法很像。

Reader 类

e2dcf0568539d3e57e7b2356abfcee90.png

Reader类API

Writer 类

d129e4190ddc06bc63fd67cb4f52046c.png

Writer类API

下面我们就直接使用他们的子类,在使用中再介绍下面没有的新方法。

1、读取控制台中的输入

import java.io.*;public class IOTest { public static void main(String[] args) throws IOException { // 三个测试方法// test01();// test02(); test03(); } public static void test01() throws IOException { BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in)); System.out.println("请输入一个字符"); char c; c = (char) bufferedReader.read(); System.out.println("你输入的字符为"+c); } public static void test02() throws IOException { BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in)); System.out.println("请输入一个字符,按 q 键结束"); char c; do { c = (char) bufferedReader.read(); System.out.println("你输入的字符为"+c); } while (c != 'q'); } public static void test03() throws IOException { BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in)); System.out.println("请输入一行字符"); String str = bufferedReader.readLine(); System.out.println("你输入的字符为" + str); }}

至于控制台的输出,我们其实一直都在使用呢,System.out.println() ,out 其实是 PrintStream 类对象的引用,PrintStream 类中当然也有 write() 方法,但是我们更常用 print() 方法和 println() 方法,因为这两个方法可以输出的内容种类更多,比如一个打印一个对象,实际调用的对象的 toString() 方法。

2、二进制文件的写入和读取

注意这里文件的路径,可以根据自己情况改一下,虽然这里的文件后缀是txt,但该文件却是一个二进制文件,并不能直接查看。

@Test public void test04() throws IOException { byte[] bytes = {12,21,34,11,21}; FileOutputStream fileOutputStream = new FileOutputStream(new File("").getAbsolutePath()+"/io/test.txt"); // 写入二进制文件,直接打开会出现乱码 fileOutputStream.write(bytes); fileOutputStream.close(); } @Test public void test05() throws IOException { FileInputStream fileInputStream = new FileInputStream(new File("").getAbsolutePath()+"/io/test.txt"); int c; // 读取写入的二进制文件,输出字节数组 while ((c = fileInputStream.read()) != -1) { System.out.print(c); } }

3、文本文件的写入和读取

write() 方法和 append() 方法并不是像方法名那样,一个是覆盖内容,一个是追加内容,append() 内部也是 write() 方法实现的,也非说区别,也就是 append() 方法可以直接写 null,而 write() 方法需要把 null 当成一个字符串写入,所以两者并无本质的区别。需要注意的是这里并没有指定文件编码,可能会出现乱码的问题。

@Test public void test06() throws IOException { FileWriter fileWriter = new FileWriter(new File("").getAbsolutePath()+"/io/test.txt"); fileWriter.write("Hello,world!欢迎来到 java 世界"); fileWriter.write("不会覆盖文件原本的内容");// fileWriter.write(null); 不能直接写入 null fileWriter.append("并不是追加一行内容,不要被方法名迷惑"); fileWriter.append(null); fileWriter.flush(); System.out.println("文件的默认编码为" + fileWriter.getEncoding()); fileWriter.close(); } @Test public void test07() throws IOException { FileWriter fileWriter = new FileWriter(new File("").getAbsolutePath()+"/io/test.txt
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值