Java IO流

Java IO流

1、什么是IO

Java中I/O操作主要是指使用Java进行输入,输出操作. Java所有的I/O机制都是基于数据流进行输入输出,这些数据流表示了字符或者字节数据的流动序列。Java的I/O流提供了读写数据的标准方法。任何Java中表示数据源的对象都会提供以数据流的方式读写它的数据的方法。

IO又分为流IO(java.io)和块IO(java.nio)

Java.io是大多数面向数据流的输入/输出类的主要软件包。此外,Java也对块传输提供支持,在核心库 java.nio中采用的便是块IO。

流IO的好处是简单易用,缺点是效率较低。块IO效率很高,但编程比较复杂。

这里先讲流IO。

2、什么是流

在电脑上的数据有三种存储方式,一种是外存,一种是内存,一种是缓存。比如电脑上的硬盘,磁盘,U盘等都是外存,在电脑上有内存条,缓存是在CPU里面的。外存的存储量最大,其次是内存,最后是缓存,但是外存的数据的读取最慢,其次是内存,缓存最快。这里总结从外存读取数据到内存以及将数据从内存写到外存中。对于内存和外存的理解,我们可以简单的理解为容器,即外存是一个容器,内存又是另外一个容器。那又怎样把放在外存这个容器内的数据读取到内存这个容器以及怎么把内存这个容器里的数据存到外存中呢?

在Java类库中,IO部分的内容是很庞大的,因为它涉及的领域很广泛:

​ 标准输入输出,文件的操作,网络上的数据流,字符串流,对象流,zip文件流等等,java中将输入输出抽象称为流,就好像水管,将两个容器连接起来。将数据从外存中读取到内存中的称为输入流,将数据从内存写入外存中的称为输出流。

3、根据流向分为输入流和输出流

注意输入流和输出流是相对于程序而言的。

  • 输出:把程序(内存)中的内容输出到磁盘、光盘等存储设备中

  • 输入:读取外部数据(磁盘、光盘等存储设备的数据)到程序(内存)中

4、字节流和字符流

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

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

  • 字符流:每次读取〈写出〉一个字符,有中文时,使用该流就可以正确传输显示中文。

字节流和字符流的原理是相同的,只不过处理的单位不同而已。

  • 后缀是stream是字节流,而后缀是Reader , Writer是字符流。

字符流的由来:Java中字符是采用unicode标准,一个字符是16位,即一个字符使用两个字节来表示。为此,Java引入了处理字符的流。因为数据编码的不同,而有了对字符进行高效操作的流对象。本质其实就是基于字节流读取时,去查指定的码表。

字节流和字符流的区别:

  • 读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节

  • 处理对象不同:字节流能处理所有类型的数据〈如图片、avi等),而字符流只能处理字符类型的数据。

  • 字节流:一次读入或读出是8位二进制。

  • 字符流:一次读入或读出是一个或者多个字节。

设备上的数据无论是图片或者视频,文字,它们都以二进制存储的。二进制的最终都是以一个8位为数据单元进行体现,所以计算机中的最小数据单元就是字节。意味着,字节流可以处理设备上的所有数据,所以字节流一样可以处理字符数据

5、根据功能分为节点流和包装流

节点流:可以从或向一个特定的地方(节点)读写数据,直接连接数据源。如最常见的是文件的FileReader,还可以是数组、管道、字符串,关键字分别为ByteArray/CharArray,Piped,String。.

处理流(包装流):并不直接连接数据源,是对一个已存在的流的连接和封装,是一种典型的装饰器设计模式,使用处理流主要是为了更方便的执行输入输出工作,如PrintStream,输出功能很强大,又如BufferedReader提供缓存机制,推荐输出时都使用处理流包装。

​ 一个流对象经过其他流的多次包装,称为流的链接。

注意:一个IO流可以即是输入流又是字节流又或是以其他方式分类的流类型,是不冲突的。比如FileInputStream,它既是输入流又是字节流还是文件节点流。

6、IO流整体构架图

img

7、节点流

在这里插入图片描述

节点流:直接和数据相连,读入或者读出

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

read()方法每次调用都读取一个字

8、 FileInputStream输入流

// 读取1.txt文件的内容
    /*
    * 1、创建输入流
    * 2、读取文件内容
    * 3、关闭输入流 */
    @Test
    public void readData1() throws IOException {
        FileInputStream fis = null;
                // 读取文件,传入file或者直接写文件路径
//        FileInputStream fis = new FileInputStream("scr/main/resources/1.txt");
        // 或者
        File file = new File("src/main/resources/1.txt");
        if (file.exists()){
            fis = new FileInputStream(file);
//            // 读取一个字节
//            int ch = fis.read();
            System.out.println((char)ch);
//            // 全部读入并且输出出去
//            while(ch!=-1){
//                System.out.print((char) ch);
//                ch = fis.read();
//            }
            // 更简洁的写法
            int ch;
            while((ch = fis.read()) != -1){
                System.out.println((char) ch);
            }
            // 关闭输入流
            fis.close();
        }
    }
    @Test
    public void readData2() throws IOException {
        FileInputStream fis = null;
        File file = new File("src/main/resources/1.txt");
        if (file.exists()){
            fis = new FileInputStream(file);


//            int available()返回从此输入流中可以读取(或跳过)的剩余字节数的估计值,而不会被下一次调用此输入流的方法阻塞。
            System.out.println("输入流里面剩余的字节数有:" + fis.available()); //输入流里面剩余的字节数有:10
//            read(byte[] b)从该输入流读取最多 b.length个字节的数据为字节数组。
            byte[] bytes = new byte[5];
            int length = fis.read(bytes);
            System.out.println(fis.available());


            fis.close();
        }
    }

9、FileOutputStream

    /*
    * 向hello.txt写入数据
    * 1、定义输出流
    * 2、向文件写入内容
    * 3、关闭流
    *
    * 注意:如果输出流关联的文件不存在,则会创建文件
    * 使用 FileOutputStream(file/String)创建,会覆盖文件
    * 如果想要追加写,那么需要传递第二个参数为true*/

    @Test
    public void writeData1() throws IOException {

        File file = new File("src/main/resources/1.txt");
        // 创建输出流 追加写
        FileOutputStream fos = new FileOutputStream(file,true);
        // 向hello.txt 写入内容
        fos.write(98);
        byte[] bytes = new byte[]{11,12,12,123};
        fos.write(bytes);
        // 把str转化为数组
        String str = "你好呀";
        byte[] bytes1 = str.getBytes();
        fos.write(bytes1);
        fos.close();
    }

实现文件复制

    @Test
    public void copyData1() throws IOException {
        // 实现文件的复制
        File file = new File("src/main/resources/1.txt");
        FileInputStream fis = new FileInputStream(file);
        FileOutputStream fos = new FileOutputStream("src/main/resources/3.txt");
        byte[] bytes = new byte[10];
        int len;
        while((len=fis.read(bytes))>-1){
            fos.write(bytes,0,len);
        }
        fis.close();
        fos.close();
    }

10、字符流

  • FileReader() 和字节输入流差不多,就是读入的时候一个字符一个读入.read()
  • FileWriter()
  • 方法多了个getEncoding()

11、缓冲流

缓冲流能有效提高文件的读写速度

BufferedInputStream

BufferedOutputStream

  • 文件复制 速度提升十倍+
    @Test
    public void Test2() throws IOException {
        // 创建文件流和缓冲流
        File file = new File("src/main/resources/1.txt");
        FileInputStream fis = new FileInputStream(file);
        FileOutputStream fos = new FileOutputStream("src/main/resources/11.txt");
        BufferedInputStream bis = new BufferedInputStream(fis);
        BufferedOutputStream bos = new BufferedOutputStream(fos);

        // 使用缓冲流来读写锁数据
        byte[] bytes = new byte[100];
        int len;
        while((len=bis.read(bytes))!=-1){
            bos.write(bytes,0,len);
        }
        // 只需要关闭外层流即可
        bos.close();
        bis.close();

    }

BufferedReader

BufferedWriter

  • 同上

12、转换流:把字节流转换为字符流

解决中英文都存在的文件时乱码问题,是字符与字节之间的桥梁

InputStreamReader:把字节输入流转换为字符输入流

OutputStreamWriter:把字节输出流转换为字符输出流

13、序列化与反序列化

13.1、什么是序列化与反序列化?

序列化:指把堆内存中的 Java 对象数据,通过某种方式把对象存储到磁盘文件中或者传递给其他网络节点(在网络上传输)。这个过程称为序列化。通俗来说就是将数据结构或对象转换成二进制串的过程

反序列化:把磁盘文件中的对象数据或者把网络节点上的对象数据,恢复成Java对象模型的过程。也就是将在序列化过程中所生成的二进制串转换成数据结构或者对象的过程

13.2、为什么要做序列化?

①、在分布式系统中,此时需要把对象在网络上传输,就得把对象数据转换为二进制形式,需要共享的数据的 JavaBean 对象,都得做序列化。

②、服务器钝化:如果服务器发现某些对象好久没活动了,那么服务器就会把这些内存中的对象持久化在本地磁盘文件中(Java对象转换为二进制文件);如果服务器发现某些对象需要活动时,先去内存中寻找,找不到再去磁盘文件中反序列化我们的对象数据,恢复成 Java 对象。这样能节省服务器内存。

13.3、Java 怎么进行序列化?

①、需要做序列化的对象的类,必须实现序列化接口:Java.lang.Serializable 接口(这是一个标志接口,没有任何抽象方法),Java 中大多数类都实现了该接口,比如:String,Integer

②、底层会判断,如果当前对象是 Serializable 的实例,才允许做序列化,Java对象 instanceof Serializable 来判断。

③、在 Java 中使用对象流来完成序列化和反序列化

ObjectOutputStream:通过 writeObject()方法做序列化操作

ObjectInputStream:通过 readObject() 方法做反序列化操作

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值