首页 > 其他分享 >IO流:字节流

IO流:字节流

时间:2024-08-30 12:24:35浏览次数:3  
标签:字节 buffer IO new out os 读取

1.前置知识:字符集

简介

使用ASCII码表示128个字符,第一位都是0。

GBK:一个中文字符编码成两个字节存储。包含ASCII,汉字第一个字节第一位必须是1,以此来区分是汉字还是字母或者其他。

Unicode:万国码。

UTF-32:四个字节表示一个字符。

UTF-8:可变长编码方案。一到四个字不等。ASCII占一个字节,汉字占三个字节

IO流:字节流_输入流

字符集的编码与解码

IO流:字节流_字节数_02

2.IO流

概述

输入流和输出流。

IO流:字节流_System_03

(1)字节输入流   InputStream   FileInputStream 从磁盘读内容到内存

(2)字节输出流   OutStream   FileOutStream

(3)字符输入流   Reader   FileReader

(4)字符输出流   Writer   FileWriter

以上四个都是抽象类,后面是他们的实现类。

(1)FileInputStream 文件字节输入流(读一个字节)

IO流:字节流_输入流_04

public class FileInputStreamTest1 {

    public static void main(String[] args) throws Exception {
        // 1. 创建文件字节输入流对象,与源文件接通。
        // InputStream is = new FileInputStream(new File("file-io-app\\src\\a01.txt"));
        // 简化写法,推荐使用。
        InputStream is = new FileInputStream("file-io-app\\src\\a01.txt");

        // 2. 开始读取文件的字节数据:
        // public int read():每次读一个字节返回,如果没有数据了,返回-1。
        int b1 = is.read();
        System.out.println((char) b1);

        int b2 = is.read();
        System.out.println((char) b2);

        int b3 = is.read();
        System.out.println(b3);
        
        //循环读取,读中文会出错
        while((b1 = is.read()) != -1){
            System.out.println((char) b1);
            
         is.close();//关闭通道
    }
}

上面代码有很多去缺陷。1.读取性能很差,因为这是到硬盘去读,效率低。2.读取汉字会乱码。

流使用之后需要关闭。

(2)读取多个字节

IO流:字节流_输入流_05

public class FileInputStreamTest2 {
    public static void main(String[] args) throws Exception {
        // 1. 创建一个字符输入流对象以代表字符输入流管道与源文件接通。
        InputStream is = new FileInputStream("file-io-app\\src\\a\\data.txt");//存的是abcde

        // 2. 开始读取文件中的字节数据,每次读取多个字节。
        byte[] buffer = new byte[3];
        int len = is.read(buffer);
        String rs = new String(buffer);
        System.out.println(rs);
        System.out.println("当次读取的字节数是:" + len);//abc

        // 第二次读取
        int len2 = is.read(buffer);
        String rs2 = new String(buffer, 0, len2);//不加后边的0-len2,读的是dec,加了读的是de
        System.out.println(rs2);
        System.out.println("当次读取的字节数是:" + len2);

        // 第三次读取
        int len3 = is.read(buffer);
        System.out.println(len3); // -1
        //循环,
         byte[] buffer = new byte[3];
        int len; // 记录每次读取了多少个字节
        while ((len = is.read(buffer)) != -1) {
            // 注意:读取多少,输出多少
            String rs = new String(buffer, 0, len);
            System.out.print(rs);
        }

        // 关闭输入流
        is.close();
    }
}

上面代码读取性能的搭配提升,但读取汉字也会出现问题,会出现乱码。

(3)一次性读完全部字节

public class FileInputStreamTest3 {
    public static void main(String[] args) throws Exception {
        // 1. 一次性读取完文件的全部字节到一个字节数组中去。
        // 创建一个字符输入流管道与源文件接通
        InputStream is = new FileInputStream("file-io-app\\src\\a03.txt");
        
        // 2. 准备一个字节数组,大小与文件的大小正好一样大。
        File f = new File("file-io-app\\src\\a03.txt");
        long size = f.length();
        byte[] buffer = new byte[(int) size];

        int len = is.read(buffer); 
        System.out.println(new String(buffer));

        // 输出文件大小和读取的字节数
        System.out.println(size);
        System.out.println(len);

		// 使用 readAllBytes() 方法读取文件所有字节
        byte[] buffer = is.readAllBytes();
        System.out.println(new String(buffer));
        
        // 关闭输入流以释放资源
        is.close();
    }
}

可以解决中文乱码的问题,适合读相对较较小的文件。如果文件过大,创建的字节数组也会过大,会引起内存溢出。

读取文本内容更适合用字符流。

字节流适合做数据的转移,如文件复制。

(4)文件字节输出流

把内存的数据以字节的形式写到文件中去。

IO流:字节流_字节数_06

public class FileOutputStreamTest4 {
    public static void main(String[] args) throws Exception {
        // 追加数据到文件的管道
        OutputStream os = new FileOutputStream("file-io-app/src/itheima04out.txt", true);

        // 2. 开始写字节数据出去
        os.write(97); // 97是一个字节,代表'a'
        os.write('b'); // 'b'也是一个字节

        byte[] bytes = "我爱你中国abc".getBytes();
        os.write(bytes);

        os.write(bytes, 0, 15);// 从bytes数组的0开始,写入15个字节

        //换行符
        
        os.write("\r\n".getBytes());
        // 关闭流
        os.close();
    }
}

案例:文件复制

public class FileCopy {
    public static void main(String[] args) throws Exception {
        // 1. 创建一个字节输入流管道与源文件接通
        InputStream is = new FileInputStream("D:/resource/meinv.png");

        // 2. 创建一个字节输出流管道与目标文件接通
        OutputStream os = new FileOutputStream("C:/data/meinv.png");//这里需要自己先写出文件名,因为系统不会自己创建

        // 3. 创建一个字节数组,负责转移字节数据
        byte[] buffer = new byte[1024]; // 1KB

        // 4. 从字节输入流中读取字节数据,每次读到字节数组中,读多少写出多少
        int len; // 记录每次读取了多少字节
        while ((len = is.read(buffer)) != -1) {
            os.write(buffer, 0, len);
        }

        // 关闭流
        os.close();
        is.close();
        System.out.println("复制完成!");
    }
}

一切文件的复制,不会出错,虽然读的时候是分开读的,但是传输完成会接着读,只要编码合适就能成功显示。

释放资源的方式

前面学的close方法关闭通道会出现问题,比如程序异常了,就不会执行后边的程序,通道关不上。下面这两种是解决方法。

(1)try-catch-finally

finally代码区的特点:无论try的程序是否正常执行了,还是出现了异常,最后一定会执行finally的代码,除非jvm终止,加return也没用。

注意:在finally不要加return语句。

finally作用:一般用于执行完程序释放资源。

public class FileCopyWithExceptionHandling {
    public static void main(String[] args) {
        InputStream is = null;
        OutputStream os = null;//放在前边,是因为如果放在try中,finally无法调用is os

        try {
            // 1. 创建一个字节输入流管道与源文件接通
            is = new FileInputStream("file-io-app\\src\\a03.txt");
            // 2. 创建一个字节输出流管道与目标文件接通
            os = new FileOutputStream("file-io-app\\src\\a03copy.txt");

            // 3. 创建一个字节数组,负责转移字节数据
            byte[] buffer = new byte[1024]; // 1KB

            // 4. 从字节输入流中读取字节数据,每次读到字节数组中,读多少写出多少
            int len; // 记录每次读取了多少个字节
            while ((len = is.read(buffer)) != -1) {
                os.write(buffer, 0, len);
            }

            System.out.println("复制完成!");

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 释放资源的管道
            try {
                if (os != null) os.close();
                if (is != null) is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

(2)try-with-resource

更简单的资源释放方案。 

IO流:字节流_System_07

public class Test3 {
    public static void main(String[] args) {
        try (
            // 1. 创建一个字节输入流管道与源文件接通
            InputStream is = new FileInputStream("file-io-app\\src\\itheima03.txt");
            // 2. 创建一个字节输出流管道与目标文件接通
            OutputStream os = new FileOutputStream("file-io-app\\src\\itheima03copy.txt")

            //这里只能放资源,int a = 1;会报错
            //资源是实现了AutoCloseable接口的对象,在try语句块结束时自动调用close()方法释放资源
            //也可以自己写一个类实现AutoCloseable接口,在try语句块结束时自动调用close()方法释放资源
        ) {
            // 3. 创建一个字节数组,负责转移字节数据
            byte[] buffer = new byte[1024]; // 1KB

            // 4. 从字节输入流中读取字节数据,每次读到字节数组中,读多少写出多少
            int len; // 记录每次读取了多少字节
            while ((len = is.read(buffer)) != -1) {
                os.write(buffer, 0, len);
            }

            System.out.println("复制完成!");

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

try这里只能放资源,int a = 1;会报错

资源是实现了AutoCloseable接口的对象,在try语句块结束时自动调用close()方法释放资源

也可以自己写一个类实现AutoCloseable接口,在try语句块结束时自动调用close()方法释放资源

标签:字节,buffer,IO,new,out,os,读取
From: https://blog.51cto.com/u_16382144/11875205

相关文章

  • Encoding.Default.GetByteCount(),C# 获取字符串字节长度
    原文链接:https://blog.csdn.net/lidin888/article/details/127674079一、C#获取字符串字节长度1.在C#语言中使用string字符串Unicode编码2.在C#语言中常用汉字占3个字节方式1:使用默认编码类获取字节长度Console.WriteLine(Encoding.Default.GetByteCount("张三"));//输......
  • Centos-MinIO安装
    1.下载MinIO可执行文件首先,您需要下载MinIO可执行文件。确保您的系统上已经安装了wget,如果没有安装,可以先参考我之前的建议来解决yuminstallwget的问题。下载MinIO:也可以在window在官网或者中文镜像网站下好二进制文件再导入到linux上wgethttps://dl.minio.org.cn......
  • 工作 6 年,@Transactional 注解用的一塌糊涂
    接手新项目一言难尽,别的不说单单就一个@Transactional注解用的一塌糊涂,五花八门的用法,很大部分还失效无法回滚。有意识的在涉及事务相关方法上加@Transactional注解,是个好习惯。不过,很多同学只是下意识地添加这个注解,一旦功能正常运行,很少有人会深入验证异常情况下事务是否能......
  • SQL Server视图定义中不能使用option(recompile)提示
    SQLSever数据库中,我们一般使用OPTION(RECOMPILE)查询提示(QueryHints)来解决SQL语句或存储过程的参数嗅探问题或某些SQL性能问题,它强制优化器重新编译查询语句,生成新的执行计划。最近在帮同事优化一个复杂视图时,发现这个视图的执行计划一直在变化,有时候生成的一个糟糕执行计划,导......
  • An unbiased evaluation of environment management and packaging tools
    forward:https://alpopkes.com/posts/python/packaging_tools/ LastupdateThispostwaslastupdatedonAugust29th,2024.MotivationWhenIstartedwithPythonandcreatedmyfirstpackageIwasconfused.Creatingandmanagingapackageseemedmuchhard......
  • An unbiased evaluation of environment management and packaging tools
    forward:https://alpopkes.com/posts/python/packaging_tools/ LastupdateThispostwaslastupdatedonAugust29th,2024.MotivationWhenIstartedwithPythonandcreatedmyfirstpackageIwasconfused.Creatingandmanagingapackageseemedmuchhard......
  • Java核心API——io类缓冲流
    在前面的学习中我们学习了如何向文件中简单的传输写入数据java将流分为两类节点流与处理流节点流:又称为低级流,特点:实际连接程序与另一端的"管道",负责实际读写数据的流.IO一定是建立在某个低级流的基础上进行的.文件流就是低级流,它们是实际连接程序与文件的管道,负责......
  • 在Ubuntu系统上安装RELION的详细教程。
     从官网给出的安装说明(Download&install-Relion(cam.ac.uk))和Github上给的安装说明(GitHub-3dem/relion:Image-processingsoftwareforcryo-electronmicroscopy)都可以实现RELION的快速安装。但是官网的说明比较繁琐,会让新手感到混淆。虽然Github的教程比较清晰,但是......
  • day07(IO进程)线程 Thread
    目录一.什么是线程1. 概念2. 进程和线程区别3.线程资源二.函数接口1.创建线程:pthread_create2. 退出线程:pthread_exit3.回收线程资源 pthread_join练习:输入输出,quit结束三.同步1.概念2.同步机制3. 函数接口练习:用信号量实现输入输出quit结束......
  • CF1980F1 & F2 Field Division
    前言纪念一下独立做出来的\(2400\)的题Easyversion思路先说\(Easy\)版本的我们走路的方式只有可能是这种样子:(出处:luoguuserFiraCode)不想手绘图了即对列排序后,所形成的一个行编号上升的序列所以\(Easy\)就很简单了,对于每一列的最大值,如果大于当前前缀最大值,则......