java IO流简介

在这里插入图片描述

一、概念、作用、特性

概念、作用:
java中IO流用来处理设备之间的数据传输,上传文件和下载文件;使用Decorator(装饰者)模式,按功能划分Stream,您可以动态装配这些Stream,以便获得您需要的功能。例如,您需要一个具有缓冲的文件输入流,则应当组合使用FileInputStream和BufferedInputStream。
特性:
1、先进先出,最先写入输出流的数据最先被输入流读取到。

2、顺序存取,可以一个接一个地往流中写入一串字节,读出时也将按写入顺序读取一串字节,不能随机访问中间的数据。(RandomAccessFile可以从文件的任意位置进行存取(输入输出)操作)

3、只读或只写,每个流只能是输入流或输出流的一种,不能同时具备两个功能,输入流只能进行读操作,对输出流只能进行写操作。在一个数据传输通道中,如果既要写入数据,又要读取数据,则要分别提供两个流

二、IO流的分类

1、按数据流的方向分为 输入流、输出流

此输入、输出是相对于我们写的代码程序而言,

输入流:从别的地方(本地文件,网络上的资源等)获取资源 输入到 我们的程序中

输出流:从我们的程序中 输出到 别的地方(本地文件), 将一个字符串保存到本地文件中,就需要使用输出流。

2、按处理数据单位不同分为 字节流、字符流

1字符 = 2字节 、 1字节(byte) = 8位(bit) 、 一个汉字占两个字节长度

字节流:每次读取(写出)一个字节,当传输的资源文件有中文时,就会出现乱码,

字符流:每次读取(写出)两个字节,有中文时,使用该流就可以正确传输显示中文。

3、按功能不同分为 节点流、处理流

节点流:以从或向一个特定的地方(节点)读写数据。如FileInputStream

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

4、4个基本的抽象流类型,所有的流都继承这四个。

流    输入流      输出流

字节流  InputStream  outputStream

字符流  Reader      Writer

三、IO流常用到的五类一接口

在整个Java.io包中最重要的就是5个类和一个接口。5个类指的是File、OutputStream、InputStream、Writer、Reader;一个接口指的是Serializable.掌握了这些IO的核心操作那么对于Java中的IO体系也就有了一个初步的认识了。

主要的类如下:

  1. File(文件特征与管理):File类是对文件系统中文件以及文件夹进行封装的对象,可以通过对象的思想来操作文件和文件夹。 File类保存文件或目录的各种元数据信息,包括文件名、文件长度、最后修改时间、是否可读、获取当前文件的路径名,判断指定文件是否存在、获得当前目录中的文件列表,创建、删除文件和目录等方法。

  2. InputStream(二进制格式操作):抽象类,基于字节的输入操作,是所有输入流的父类。定义了所有输入流都具有的共同特征。

  3. OutputStream(二进制格式操作):抽象类。基于字节的输出操作。是所有输出流的父类。定义了所有输出流都具有的共同特征。

  4. Reader(文件格式操作):抽象类,基于字符的输入操作。

  5. Writer(文件格式操作):抽象类,基于字符的输出操作。

  6. RandomAccessFile(随机文件操作):一个独立的类,直接继承至Object.它的功能丰富,可以从文件的任意位置进行存取(输入输出)操作。

1、输入字节流InputStream

在这里插入图片描述
ByteArrayInputStream:字节数组输入流,该类的功能就是从字节数组(byte[])中进行以字节为单位的读取,也就是将资源文件都以字节的形式存入到该类中的字节数组中

PipedInputStream:管道字节输入流,它和PipedOutputStream一起使用,能实现多线程间的管道通信

FilterInputStream :装饰者模式中处于装饰者,具体的装饰者都要继承它,所以在该类的子类下都是用来装饰别的流的,也就是处理类。具体装饰者模式在下面会讲解到,到时就明白了

BufferedInputStream:缓冲流,对处理流进行装饰,增强,内部会有一个缓存区,用来存放字节,每次都是将缓存区存满然后发送,而不是一个字节或两个字节这样发送。效率更高

DataInputStream:数据输入流,它是用来装饰其它输入流,它“允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型”

FileInputSream:文件输入流。它通常用于对文件进行读取操作

File:对指定目录的文件进行操作,具体可以查看讲解File的博文。注意,该类虽然是在IO包下,但是并不继承自四大基础类。

ObjectInputStream:对象输入流,用来提供对“基本数据或对象”的持久存储。通俗点讲,也就是能直接传输对象(反序列化中使用)。

2、输出字节流OutputStream

在这里插入图片描述
IO 中输出字节流的继承图可见上图,可以看出:

OutputStream 是所有的输出字节流的父类,它是一个抽象类。
ByteArrayOutputStream、FileOutputStream 是两种基本的介质流,它们分别向Byte 数组、和本地文件中写入数据。PipedOutputStream 是向与其它线程共用的管道中写入数据,
ObjectOutputStream 和所有FilterOutputStream 的子类都是装饰流(序列化中使用)。

3、字符输入流Reader

在这里插入图片描述
在上面的继承关系图中可以看出:

Reader 是所有的输入字符流的父类,它是一个抽象类。
CharArrayReader、StringReader 是两种基本的介质流,它们分别将Char 数组、String中读取数据。PipedReader 是从与其它线程共用的管道中读取数据。
BufferedReader 很明显就是一个装饰器,它和其子类负责装饰其它Reader 对象。
FilterReader 是所有自定义具体装饰流的父类,其子类PushbackReader 对Reader 对象进行装饰,会增加一个行号。
InputStreamReader 是一个连接字节流和字符流的桥梁,它将字节流转变为字符流。FileReader 可以说是一个达到此功能、常用的工具类,在其源代码中明显使用了将FileInputStream 转变为Reader 的方法。我们可以从这个类中得到一定的技巧。Reader 中各个类的用途和使用方法基本和InputStream 中的类使用一致。后面会有Reader 与InputStream 的对应关系。

4、字符输出流Writer

在这里插入图片描述
在上面的关系图中可以看出:

Writer 是所有的输出字符流的父类,它是一个抽象类。
CharArrayWriter、StringWriter 是两种基本的介质流,它们分别向Char 数组、String 中写入数据。PipedWriter 是向与其它线程共用的管道中写入数据,
BufferedWriter 是一个装饰器为Writer 提供缓冲功能。
PrintWriter 和PrintStream 极其类似,功能和使用也非常相似。
OutputStreamWriter 是OutputStream 到Writer 转换的桥梁,它的子类FileWriter 其实就是一个实现此功能的具体类(具体可以研究一SourceCode)。功能和使用和OutputStream 极其类似,后面会有它们的对应图。

四、字节流和字符流使用情况

字符流和字节流的使用范围:字节流一般用来处理图像,视频,以及PPT,Word类型的文件。字符流一般用于处理纯文本类型的文件,如TXT文件等,字节流可以用来处理纯文本文件,但是字符流不能用于处理图像视频等非文本类型的文件。

五、代码例子

1.字节流

// 读取f盘下该文件f://hell/test.txt
        //构造方法1
        InputStream inputStream = new FileInputStream(new File("f://hello//test.txt"));
        int i = 0;
        //一次读取一个字节
        while ((i = inputStream.read()) != -1) {

            // System.out.print(i + " ");// 65 66 67 68
            //为什么会输出65 66 67 68?因为字符在底层存储的时候就是存储的数值。即字符对应的ASCII码。
            System.out.print((char) i + " ");// A B C D
        }
        //关闭IO流
        inputStream.close();
        
        // 读取f盘下该文件f://hell/test.txt
        //构造方法2
        InputStream inputStream2 = new FileInputStream("f://hello/test.txt");
        // 字节数组
        byte[] b = new byte[2];
        int i2 = 0;
        //  一次读取一个字节数组
        while ((i2 = inputStream2.read(b)) != -1) {

            System.out.print(new String(b, 0, i2) + " ");// AB CD
        }
        //关闭IO流
        inputStream2.close();

一次读取一个字节数组,提高了操作效率,IO流使用完毕一定要关闭。

OutputStream outputStream = new FileOutputStream(new File("test.txt"));
        // 写出数据
        outputStream.write("ABCD".getBytes());
        // 关闭IO流
        outputStream.close();

        // 内容追加写入
        OutputStream outputStream2 = new FileOutputStream("test.txt", true);
        // 输出换行符
        outputStream2.write("\r\n".getBytes());
        // 输出追加内容
        outputStream2.write("hello".getBytes());
        // 关闭IO流
        outputStream2.close();

注;输出的目的地文件不存在,则会自动创建,不指定盘符的话,默认创建在项目目录下;输出换行符时一定要写\r\n不能只写\n,因为不同文本编辑器对换行符的识别存在差异性。

2、字节缓冲流(高效流)

 InputStream in = new FileInputStream("test.txt");
        // 字节缓存流
        BufferedInputStream bis = new BufferedInputStream(in);
        byte[] bs = new byte[20];
        int len = 0;
        while ((len = bis.read(bs)) != -1) {

            System.out.print(new String(bs, 0, len));
            // ABCD
            // hello
        }
        // 关闭流
        bis.close();
 BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("test.txt", true));
        // 输出换行符
        bos.write("\r\n".getBytes());
        // 输出内容
        bos.write("Hello Android".getBytes());
        // 刷新此缓冲的输出流
        bos.flush();
        // 关闭流
        bos.close();

3、转换流

//使用默认编码        
        InputStreamReader reader = new InputStreamReader(new FileInputStream("test.txt"));
        int len;
        while ((len = reader.read()) != -1) {
            System.out.print((char) len);//爱生活,爱Android

        }
        reader.close();

         //指定编码 
        InputStreamReader reader = new InputStreamReader(new FileInputStream("test.txt"),"utf-8");
        int len;
        while ((len = reader.read()) != -1) {
            System.out.print((char) len);//????????Android
        }
        reader.close();

4、字符缓冲流(高效流)

 //生成字符缓冲流对象
        BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("test.txt")));
        String str;
        //一次性读取一行
        while ((str = reader.readLine()) != null) {
            System.out.println(str);// 爱生活,爱Android
        }

        //关闭流
        reader.close();
FileInputStream inputStream = new FileInputStream("f://滑板//HEEL_FLIP.mp4");
        BufferedInputStream bis = new BufferedInputStream(inputStream);
        FileOutputStream outputStream = new FileOutputStream("HEEL_FLIP.mp4");
        BufferedOutputStream bos = new BufferedOutputStream(outputStream);
        int len;
        byte[] bs = new byte[1024];
        // 开始时间
        long begin = System.currentTimeMillis();
        while ((len = bis.read(bs)) != -1) {
            bos.write(bs, 0, len);
        }
        // 用时毫秒
        System.out.println(System.currentTimeMillis() - begin);// 78

        bis.close();
        bos.close();

六、装饰者模式

什么是装饰者模式?用我自己的话来说,就是往一个添加更多的功能,而我们首先想到的是继承,继承就很好的符合了我们的要求,不管你想加多少层的功能,都可以使用继承一层层的实现,但是这带来了一个问题,一旦我需要改变我的需求,那么我就需要往源码中改东西,再就是在这个继承链中某个类做一些修改,这不符合我们的设计模式思想,所以就有了装饰者模式,装饰者中拥有被装饰者的实例,然后有什么具体的装饰我们都另写一个类来继承该装饰者,当我们需要该装饰时,就new出该类来,然后将其被装饰者当作参数传递进去。

在这里插入图片描述
关说可能没理解那么清楚,现在来看看一个具体的实例。比如,我们需要制作一份鸡腿堡,流程是怎样的呢?看下图

1、先有基本原料,也就是两块面包,这是不管做什么汉堡都需要的,

2、做什么汉堡,取决于加什么材料,比如生菜,鸡肉等,所以根据材料来做汉堡,想做什么汉堡就加什么材料

3、所有材料加完之后,直接计算价格即可

这样使用装饰者模式,是不是比一直使用继承方便的多的多呢?换一种汉堡,也不需要改源码,什么也不需要,希望你能够理解清楚其中的思想。
在这里插入图片描述
io流中的装饰者模式的运用
在这里插入图片描述

七、打印流

打印流是输出信息最方便的类,注意包含字节打印流PrintStream和字符打印流:PrintWriter。打印流提供了非常方便的打印功能,
可以打印任何类型的数据信息,例如:小数,整数,字符串。

回顾:
之前打印信息需要使用OutputStream但是这样,所有数据输出会非常麻烦,String–>byte[],打印流中可以方便进行输出,

PrintStream类中常用方法:

package 类集;
import java.io.* ;
public class PrintDemo01{
    public static void main(String arg[]) throws Exception{
        PrintStream ps = null ;        // 声明打印流对象
        // 如果现在是使用FileOuputStream实例化,意味着所有的输出是向文件之中
        ps = new PrintStream(new FileOutputStream(new File("d:" + File.separator + "test.txt"))) ;
        String name = "李兴华" ;    // 定义字符串
        int age = 30 ;                // 定义整数
        float score = 990.356f ;    // 定义小数
        char sex = 'M' ;            // 定义字符
        ps.printf("姓名:%s;年龄:%d;成绩:%f;性别:%c",name,age,score,sex) ;
        ps.close() ;
    }
};

使用很多%s,%d,%c无法记住的话,实例可以全部使用“%s”表示。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值