Java教程

Java IO流

本文主要是介绍Java IO流,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

Java IO流

1. 什么是IO

谜底就在谜面上

I : Input 输入

O :Output 输出

输入输出(IO)是指计算机同任何外部设备之间的数据传递,创建的输入输出设备有键盘,打印机,屏幕等。 举个例子,我们将存储在硬盘之中的数据读入内存之中,将内存之中的数据存储在硬盘之中这些行为都可以被叫做输入输出。只不过输入输出的主体有所变化而已。

一般来讲我们将内存作为输入输出的主体。从内存之中出来叫输出,读入内存之中叫输入。

2. 什么是IO流

I : 输入流

O : 输出流

我们将数据的无结构化传递抽象为流,按照流的方式将数据进行输入输出,在这其中数据被当作无结构的字符序列或字节序列,这样的话通俗点来讲IO流就是按照流的方式进行输入与输出。

IO流的分类

  1. 按照流的方向分类

    1. 输入流

      读入内存

    2. 输出流

      从内存中输出

  2. 按照读取数据方式不同进行分类

    1. 字节流

      忽略所读取文件的类型,一次读取一个字节,也就是一次读取八个位,这种流可以读取任意文件类型。

    2. 字符流

      一次读取一个字符,这种流可以效率很高的读取普通文本文件(.txt),但也只能读取普通的文本文件。

  3. 按照流的角色分类

    1. 节点流

      从/向一个特定的地方读写数据

    2. 处理流

      是对一个已经存在的流的连接和封装,通过所封装的流的功能调用实现数据的读写,如BufferedReader。处理流的构造方法总是要带一个其他的流对象做参数。一个流对象经过其他流的多次包装,称为流的链接

3. 什么是Java的IO流

以下是Java的IO类的一个继承结构图(很宝贵的!!!)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t3AEBvjn-1636869529177)(/home/wfh/Pictures/选区_001.png)]

引用自https://blog.csdn.net/u011578734/article/details/108346430

令我们高兴的是Java以及将IO流写好了,省去了很多麻烦,我们可以直接面向封装过的IO流对象。了解这些对象就行了。

首先我们通过上图可以很清楚的明白java的IO流大体分为两类 字符流, 字节流 。

  • 他们都是抽象类,

  • 他们都实现了closeable接口,也就是说他们都是可关闭的。流就像管子用完要关闭

  • 输出流都实现了Flushable接口,而输入流没有实现。 输出流可刷新,输出完最好刷新一下,这个操作的作用在于强制将Buffer(缓冲区位于内存)中的数据,写入文件(硬盘中)。

我们需要掌握以下Java的IO流

1.文件流

1. FileInputStream(硬盘到内存的操作)
  • read()

    一次从硬盘读取一个字节,以int存储这个结果并返回,当结果返回值为-1的时候说明文件已经读到末尾,为什么要以int类型作为存储结果?,因为一般来说有可能存在某个字节本身八个位全为1的情况,这样的一个字节若用byte存储,其会被识别为-1,与我们的判别是否读取完毕条件相冲突。所以我们用int来存储。(其实我还有一个小疑问为什么不用short(2字节)或char(2字节))

    存在一个帧记录着读取位置,这个帧每次向后偏移一个字节。我把他叫文件位置记录帧

    优点: 一次只读一个

    缺点:一次只读一个,增加了访问磁盘的次数。

  • read(byte[] b)

    将数据读入b中,最多一次读b.length;

    这个方法也存在着一个文件位置记录帧,且和第一个方法的帧是同一个,只不过他的偏移量等于他的读取量。

    这个方法也有一个返回值是读取到的字节数量。

    字节流从字节数组的起始开始写入,会覆盖掉字节数组原本的值。当然也可以设置起始位置,和读入长度

    优点:一次读的多,减少了磁盘访问次数。

  • int available()

    返回流中剩余没有读到的字节数量

    也就是说我们可以这样读取磁盘内容

      public static void main(String[] args) {
            FileInputStream fileInputStream = null;
    
            try {
                fileInputStream = new FileInputStream("src/wenben.txt"); 
           
                byte[] bytes = new byte[fileInputStream.available()];
    
                fileInputStream.read(bytes);
                System.out.println(new String(bytes));
    
    
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (fileInputStream != null) {
                    try {
                        fileInputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    

    但是这样做意味着可能要开非常大的数组,用很多内存。我们要减少内存内存开销的话可以多次读取,在同一数组上进行处理就好了。

  • long skip()

    跳过几个字节不读

2. FileOutputStream(“path”) (内存到硬盘)

path不存在的时候会新建一个文件

  • void write()

  • void write(byte[] b)

  • void write(byte[] b,int off,int len)

    注意以下几点

    1. 若在打开文件的时候,构造方法的参数中第二个参数没有注明true,则会清空原文件。无论是否执行write()方法。若设置了第二个参数为true,则在原来的文本内容上会追加

    2. 注意写完之后一定要刷新

其他方面与read()在思想上并无不同,这里就不再赘述,要是大家有问题的话可以在评论区中指出。

3. FileReader
  • read()

    一次读取一个字符,可以是中文字符也可以是其他字符。

  • read(char[])

    向char[]内读入字符。与InputStream基本无二

4.FileWriter

blank 暂时想不出什么特别的

2. 转换流

(转换 + 包装可谓是弥补了java不能多重继承的无奈之举吧)

  • InputSteamReader

    将InputStream转换为Reader

  • OutputSteamWriter

    将OutputSream转换为Writer

3. 缓冲流

自带缓冲不需要指定byte[]或char[]

  • BufferedReader

    • 构造函数 BufferedReader(Read in)

      可以将一个FileReader作为参数传入

      当一个流的构造方法需要另一个流的时候这个被传进来的流叫做,节点流,外部负责包装的流叫包装流,关闭流的时候只需要关闭包装流

    • readLine()

      读取一个文本行返回一个字符串,不从硬盘从内存(从硬盘读入的行为发生在何时)

      当读到末尾时返回一个null

  • BufferedWrite

    网上的说法是BufferedWriter相对于FileWriter来讲的话增加了一个缓冲器,即缓冲器满了以后才向硬盘内读写,但我不认为是这样,因为Writer和OutputStream这两个输出流都实际上都带有flush()方法,也就是说每一个输出流本身就含有缓冲区,所以这里我就不太清楚了,将来知道了再更新吧

  • BufferedInputStream

  • BufferedOutputStream

4.数据流

  • DataInputStream

    DataOutputStream写入的文件需要DataInputStream去读

    readUTF()

    readInt()

  • DataOutputStream

    数据专属流可以连同数据以及数据的类型一并写入文件。

    • writeInt()
    • writeDouble() 。。。。

大家有没有觉得这个特别鸡肋啊,其实在网络传输中用的比较多。就像是协议一样的

5. 对象专属流

是一种永久化对象的技术,也可以实现远距离传输对象(哈哈哈,可以这么说吗?),通过序列化(Serialize)反序列化(diSerialize)实现。

  • ObjectInputStream

    负责反序列化生成对象。

  • ObjectOutputStream

    负责对象的序列化。

通过writeObject(Object obj);

readObject(Object obj);

可以对象的序列化与反序列化

不过只有实现标志性接口Serializable的类的对象,才能通过这两个方法进行传输否则会报错,虚拟机看到Serialiazable接口后,会根据该类为该类提供一个序列化版本号,当类发生变化时,序列化版本号也会随之发生改变。

4. 标准输出流

  • PrintWriter

  • PrintStream

    标准字节输出流,默认输出到控制台(print)

    其实PrintStream离我们并不远,大家应该用过System.out.println吧

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GZxNKBer-1636869529181)(/home/wfh/Pictures/选区_005.png)]

​ out其实就是System类下的一个PrintStream类型的public成员

我们也可以改变System的out通过setOut方法。

可以跟一个setOut(new FileOutputStream),这样标准输出流就指向了一个文件。

用再次使用System.out

这是日志框架的一个原理

4. File类

File代表的是一个文件或目录的路径名

以下是File类中的常用方法

  • 构造方法
    • (path)
  • 非构造方法
    • exite()判断是否存在
    • creatNewFile() 以对象的path创建一个文件 //什么文件
    • mkdir()以path创建一个目录
    • getParent()获取父路径
    • getParentFile()
    • getAbsolutePath()获取绝对路径
    • delete()删除此file代表的文件或目录
    • isDerctory()是个目录吗
    • isFile()是个文件吗
    • listFile()当前目录下所有子文件
这篇关于Java IO流的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!