您的位置 首页 java

「Java」一篇文章让你会用Java的io流

一、什么是 io流

流是指数据的流动,io流就是输入输出的流动。
在java中对数据的操作是用流的方式来实现的,数据不可能一瞬间就全部地从一个设备传到另一个设备,所以只能采用一点一点流动的方式。
输入流 就是 将其他地方的数据读取到程序中 输出流 就是 将程序中的数据写入到其他地方

二、io流的分类

1.四个抽象类

java .io中提供了最重要的四个抽象类, InputStream (字节输入流), OutputStream (字节输出流), reader (字符输入流),Writer(字符输出流)

一字符等于两字节
根据输出的数据单位,可以分为两类,
字节流 字符流

「Java」一篇文章让你会用Java的io流

还可以根据 输入或输出 ,分为 输入流 输出流
根据
实现功能的不同 ,还可以分为 节点流 处理流
节点流 就是, 从一个特定的节点读取或者写入数据 。一看到节点就感觉好深奥,其实说白了就是从一个地方读取或写入数据,而这个地方可以是数据库,控制台,文件等。
处理流 就是, 代理节点流,实现一些其他的功能 。像BufferedWriter,如果是普通的FileWriter,在执行写操作时就就只能一个字符一个字符来写,如果再套上一个BufferedWriter,就会有缓存的功能,写的操作就会更加的快速了。

2.各种实现类

「Java」一篇文章让你会用Java的io流

可能会有所遗漏,更加详细的可以查看java官方的文档。

三、如何使用

以FileInputStream和FileOutputStream为例

1.代码

 package test;
import java.io.File;
import java.io. File InputStream;
import java.io.FileOutputStream;

/**
 * @author xxj
 * io流测试
 */public class IOTest {
    public static void main(String[] args) {
       //先打开一个文件
        File file= new File("C:UsersAdministratorDesktop test .txt");
        try{
            //先写入数据
             fileOutputStream  fileOutputStream=new FileOutputStream( file );
            fileOutputStream.write("ABCD".getBytes());
            fileOutputStream.close();
            //读取数据
             FileInputStream  fileInputStream=new  fileInputStream (file);
            int i= 0;
            while ((i=fileInputStream.read())!=-1){
                System.out.println("通过fileInputStream读取的数据:"+i);
                System.out.println("通过fileInputStream读取的数据:"+(char)i);
                System.out.println("------");
            }
            fileInputStream.close();
        }catch (Exception e){}
    }
}
  

2.输出结果

「Java」一篇文章让你会用Java的io流


因为我加了( char )所以自动做了 ASCII 码表的转换
我的桌面也生成了test.txt文件,有兴趣的拿代码去跑一下吧。

3.解释

可能有人会问,你这不对啊,你不是FileInputStream和FileOutputStream吗,怎么刚好每次读取都是一个字母呢,不是一个字节吗?
一个字节是八位,再看一下 ASCII码表 ,里面已经有上百个符号或字母了,肯定不能只用4bit来表示啦,最少也要用8bit,8bit最高可以表示256,所以这里直接读取就是单个字母来读取的。

再以FileReader和FileWriter为例

4.代码

 public class IOTest {
    public static void main(String[] args) {
        try{
            //先写入
            File file=new File("C:UsersAdministratorDesktopwriter.txt");
            FileWriter fileWriter=new FileWriter(file);
            fileWriter.write("ABC一二三");
            fileWriter.close();
            //读取
            FileReader fileReader=new FileReader(file);
            int i=0;
            while ((i=fileReader.read())!=-1){
                System.out.println("通过reader读取的数据:"+i);
                System.out.println("通过reader读取的数据:"+(char)i);
                System.out.println("------");
            }
            fileReader.close();
        }catch (Exception e){}
    }
}
  

5. 输出结果

「Java」一篇文章让你会用Java的io流

6.解释

我有个疑问,FileReader为什么可以读字母,跟FileInputStream一样,那为什么它会刚好可以只读一个中文又只读到一个字母呢?
19968=0x4e00
writer.txt的16进制文件为

 4142 43 e4b8 80e4 ba8c e4b8 89
  

根本没有4e00,那么我们再转化成 二进制
(一)19968=
100111000000000
(二)20108=
100111010001100
(三)19977=
100111000001001
0xe4b880e4ba8ce4b889=111001001011100010000000111001001011101010001100111001001011100010001001
我使用了String.replace()方法,发现e4b8 80e4 ba8c e4b8 89中并没有包含一二三的二进制。

这里就涉及到 编码 了,常用的支持中文的编码表是UTF-8,于是我将一二三拉进去查看进制转换

「Java」一篇文章让你会用Java的io流


这。真的是一套一套的。
到了这里,也不是很清楚究竟是怎么确认只读一个字节还是读一个字符

四、各种io流的特点

不同的io流使用起来是差不多的,只是细节上有些不同,具体的可以查查 百度 或者直接看每个实现类的源码,毕竟它们都是分别继承了InputStream(字节输入流),OutputStream(字节输出流),Reader(字符输入流),Writer(字符输出流),其中处理流是根据Filter···stream间接继承的。

我稍微看了一下,想FileOutputStream最后的写操作是带有native修饰符的,又要查漏补缺了。

 private native void writeBytes(byte b[], int off, int len, boolean append)
        throws IOException;
  

字节流和字符流的区别

  1. 字节流 一次只能操作 一个字节 字符流 可以操作 两个字节
  2. 字节流 能够处理 任何文件类型 ,而 字符流 只能处理 文本类型 的文件

1.节点流

File流

字节 :FileInputStream,FileOutputStream
字符 :FileReader,FileWriter

特点

这些都是 需要先创建一个File对象 ,然后才能使用的,而读取或写入操作都是在创建的File对象上做的。
只有一个区别,
前两个是字节流 后两个是字符流 ,如果需要 读取或写入中文 ,就需要 使用后两个

Piped流

字节 :PipedInputStream,PipedOutStream,
字符 :PipedReader,PipedWriter
一般是 多线程 之间进行通信时使用的

特点

在使用这些流时,相比于File流,就不用先创建一个File对象,只需要 跟普通的流一样创建 即可,但是在管道(Piped) 相互通信前 ,需要 使用connect方法将两个管道连接起来

Piped流不需要使用文件作为数据的载体。

字节/字符数组流

字节 :ByteArrayInputStream,ByteArrayOutputStream
字符 :CharArrayReader, Char ArrayWriter

这四个流内部都会有一个数组,使用时是 先向数组中存入数据 ,然后再 从数组中读取 将数组的数据写入 到其他地方。

特点

Byte开头的,就是只能读取或写入字节。 ByteArrayInputStream 在创建时需要 向构造方法传递一个参数 (字节数组) ByteArrayOutputStream 则在使用时,需要 调用writeTo (某个流)这两个流可以帮助我们 先将数据存储到缓存区 ,然后读取写入更加快速,开辟的缓存区是用来存储字节数组的
CharArrayReader,CharArrayWriter和ByteArrayInputStream,ByteArrayOutputStream类似,只不过Char开头的是
读写字符 ,而Byte是读写字节,用法都一样的。

2.处理流

处理流在使用的时候,是需要套上一个节点流,然后使用方法跟使用节点流差不多。

Buffered缓冲流

字节 :BufferedInputStream,BufferedOutputStream
字符 :BufferedReader,BufferedWriter

这四个流跟字节/字符流类似,它们内部也 有一个数组作为缓存区 存在。但是, 字节/字符数组流 是将数据都缓存到数组中,并 不会去刷新这个数组 ,想 读取或写入 都是 从这个数组出发的 ;而 Buffered缓冲流 ,这会 有一个不会二次改变的数组 (可以在构造方法中传入size)一旦这个数组存满了,就会将数组的数据全部读出或写入到其他地方,然后 刷新数组

字节/字符数组流 建议 一次性用完就关闭

特点

在套用了其他节点流之后,使用的方法和节点流的使用方式差不多,但是在Buffered缓冲流 写入时 还需要使用一个 flush()方法 ,将缓存内部的数据 全部写入 并且刷新缓存

转化流

字符 :InputStreamReader,OutputStreamWriter

特点

就是能够 将字节流转换成字符流 ,在创建时,需要向 构造方法 传递一个 字节流和字符集 (默认为GBK)使用的方法跟字符流的使用方法差不多。

数据流

字节 :DataInputStream,DataOutputStream

特点

数据流是能够 将数据按照不同的类型写入 读取 也要按照相应的类型读取 。类似于写入时,将数据装入一个个不同类型的盒子里,读取时要按照盒子的类型并且按照写入的顺序来读取。

打印流

字节 :PrintStream
字符 :PrintWriter

特点

这两个流并没有对应的输入流,使用这两个的方法跟其他处理流差不多。在套上一个节点流后,就可以使用 print()或println()直接写入数据
有没有觉得这两个方法很熟悉,平时我们使用System.out.println()这个方法的内部其实也是使用PrintStream来实现的。

对象流

字节 :ObjectInputStream,ObjectOutputStream

特点

这两个流可以做一件事,就是 我们要写入或读取的 数据序列化 序列化 就是将对象转化成二进制数据。要使用这两个流, 第一步 也是要 套上一个节点流 第二步 就是在要序列化的类上 实现Serializable接口 ,剩下的使用方法就跟普通的节点流差不多了。

五、总结

这些流真的是多,总结一下使用场景吧。
写入或读取都是
文本类型 有中文 ,就用 字符流
写入或读取其他
杂七杂八的文件类型 没有中文 ,就用 字节流
要考虑
线程 通信 ,就用 Piped流 ;要 操作文件 ,就用 File流 ;要 将数据存在内存 中,就用 字节/字符数组流 ,没有性能和功能要求,用这三个就够了。
想要
提高读写性能 ,就套个 Buffered缓冲流 ;想要对 规定数据格式 ,就套个 数据流 ;想要 使用方便或换行 ,就套个 打印流 ;想要对 对象序列化 ,就套个 对象流

——————————————————————————————

你知道的越多,不知道的就越多。

如果本文章内容有问题,请直接评论或者私信我。如果觉得我写得还不错的话,点个赞也是对我的支持哦

未经允许,不得转载!

微信 搜【程序员徐小白】,关注即可第一时间阅读最新文章。回复【面试题】有我准备的50道高频校招面试题,以及各种学习资料。

文章来源:智云一二三科技

文章标题:「Java」一篇文章让你会用Java的io流

文章地址:https://www.zhihuclub.com/184319.shtml

关于作者: 智云科技

热门文章

网站地图