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

IO流-05:字节流

时间:2024-11-05 16:44:09浏览次数:3  
标签:文件 读取 05 内存 IO new os 字节

欢迎来到“雪碧聊技术”CSDN博客!

在这里,您将踏入一个专注于Java开发技术的知识殿堂。无论您是Java编程的初学者,还是具有一定经验的开发者,相信我的博客都能为您提供宝贵的学习资源和实用技巧。作为您的技术向导,我将不断探索Java的深邃世界,分享最新的技术动态、实战经验以及项目心得。

让我们一同在Java的广阔天地中遨游,携手提升技术能力,共创美好未来!感谢您的关注与支持,期待在“雪碧聊技术”与您共同成长!

目录

一、IO流的体系

思考问题1:字节和字符谁大?是什么关系?

思考问题2:输入流、输出流中的出、入,这两个动词是针对谁来讲的?

二、文件字节输入流(FileInputStream)

1、职责

2、创建输入流管道

3、读取文件(磁盘)的内容

①一个一个字节地读

②一组一组(一桶一桶)地读

4、使用字节流读取汉字,怎么保证输出不乱码?

①解决方案1:将字节数组定义的长度很大

②解决方案2:使用特定的方法readAllBytes()

5、结论

①字节流适合做数据的转移

②字符流适合读取文本

三、文件字节输出流

1、职责

2、创建输出流管道

3、从内存写到文件(磁盘)

①写一个字节出去

②写一个字节数组出去

③写一个字节数组的一部分出去

4、关闭流

5、演示

6、总结

四、文件复制

1、思路

2、举例

3、结论

①字节流非常适合做文件的复制操作

②字节流不适合读取汉字输出

五、资源释放问题

1、方式1:try-catch-finally(不推荐)

2、方式2:try-with-resource(推荐)

注意:try后面的括号()内,只能定义资源。


一、IO流的体系

抽象类只是个代表,不能构建对象,因此我们要学它们的实现类,即上图中的黑框内容。

思考问题1:字节和字符谁大?是什么关系?

答案:字符大!因为字符可能是字母、数组、符号、汉字,这几个都属于字符范围。因此,假如一个字符是汉字时,在GBK字符集中,占2字节,在UTF-8字符集中,占3个字节。

           此时这个字符的大小,无论如何都大于1字节。

           因此得出结论:字符大于字节。

思考问题2:输入流、输出流中的出、入,这两个动词是针对谁来讲的?

答案:是针对内存来讲的!

           举例1:字节输入流,就是将文件的内容读入内存,也相当于将磁盘内容读入内存,因为文件内容就在磁盘上,因此文件内容就等同于磁盘内容。

            举例2:字节输出流,就是将内存中的内容写出到文件中(磁盘)。

综上,理解出、入这两个动词所针对的对象,有利于我们学习下面的内容。

二、文件字节输入流(FileInputStream)

1、职责

        以内存为基准,可以把磁盘文件中的数据以字节的形式读入到内存中。

2、创建输入流管道

①形参为File对象

举例:

②形参为文件路径

举例:

那上面两个方法有什么区别吗?

答案:没有任何区别。通过阅读FileInputStream()方法的源码,可见本质上还是会将形参中的路径封装为一个文件对象,如下:

        

3、读取文件(磁盘)的内容

①一个一个字节地读

举例:

public class Test1 {
    public static void main(String[] args) throws Exception {
        //目标:掌握文件字节输入流读取文件中的字节数组到内存中
        //1、创建文件字节输入流管道与源文件接通
        //FileInputStream is = new FileInputStream(new File("file-io-app\\src\\123.txt"));
        FileInputStream is = new FileInputStream("src\\d1.txt");//简化写法

        //2、开始读取文件中的字节并输出
        //定义一个变量记住每次读取的一个字节
        int b;//记录一个字节的值(如:a的值为97)
        while((b = is.read()) != -1){
            System.out.print((char)b);
        }
    }
}

运行结果:

缺点:

  • 一个一个字节地读取,太费劲,性能太差。
  • 一个一个字节地读,必然导致中文乱码(因为一个中文长度不止一个字节)

举例:

②一组一组(一桶一桶)地读

举例:

public class Test2 {
    public static void main(String[] args) throws Exception {
        //目标:掌握文件字节输入流读取文件中的字节数组到内存中
        //1、创建文件字节输入流管道与源文件接通
        //FileInputStream is = new FileInputStream(new File("file-io-app\\src\\123.txt"));
        FileInputStream is = new FileInputStream("src\\d1.txt");//简化写法

        //2、开始读取文件中的字节并输出:每次读取多个字节
        //定义一个字节数组,用于存放每次读取的字节
        byte[] buffer = new byte[3];//每次读取三个字节
        //定义一个变量,记录每次读取了多少个字节
        int len;
        while((len = is.read(buffer)) !=-1 ){
            //把读取到的字节数组解码成字符串
            String str = new String(buffer, 0, len);
            System.out.print(str);
        }
    }
}

运行结果:

注意:上面不写String str = new String(buffer, 0, len);这行代码行不行?

答案:不行,会导致最后一次读到残留数据问题。如下:

注意:一组一组地读,也可能会导致中文乱码,如下:

4、使用字节流读取汉字,怎么保证输出不乱码?

①解决方案1:将字节数组定义的长度很大

定义字节数组时,让这个数组的长度足够大,能一次性读完文件中的所有字节,从而实现不截断汉字,达到输出不乱码的要求。

如下:

②解决方案2:使用特定的方法readAllBytes()

但这俩种方法只适合读小文件,如果文件过大,会导致字节数组过大,引起内存溢出问题。

5、结论

①字节流适合做数据的转移

因为人们又不看,所以乱码也没事,只要文件本身的字节没变化就行。

②字符流适合读取文本

所谓文本,就是给人看的,因此一定不能产生输出乱码问题。

读取文本内容,还得字符输入流来,毕竟这是一个字符一个字符地读,即:碰到字母就读1字节,碰到汉字就读3字节(字符集为UTF-8),此时就根本不会截断汉字,因此就不会产生输出乱码现象。

三、文件字节输出流

1、职责

        以内存为基准,把内存中的数据以字节的形式写出到文件(磁盘)中。

2、创建输出流管道

3、从内存写到文件(磁盘)

①写一个字节出去

②写一个字节数组出去

③写一个字节数组的一部分出去

4、关闭流

因为IO流管道,是内存和磁盘的一个连接,而内存速度快,磁盘速度慢,如果不关闭IO流管道,会导致磁盘拖累内存的速度。也可以释放很多占用的硬件资源,如:总线、CPU等等。

5、演示


public class Test4 {
    public static void main(String[] args) throws Exception {
        //目标:学会使用文件字节输出流
        //1、创建文件字节输出流管道与目标文件接通
        //FileOutputStream os = new FileOutputStream("src\\d1.txt");
        FileOutputStream os = new FileOutputStream("src\\d1.txt", true);//true表示追加写,而不是覆盖写

        //2、写入数据
        //public void write (int b)
        os.write(97);//写一个字节
        os.write('b');//写一个字节,此处会将‘b’转为字节98
        //os.write('徐');//写一个字节,会报错,因为一个汉字3字节,你这里只写了一个字节

        //3、写一个字节数组出去
        byte[] bytes = {97,98,99,100,101,102,103,104};
        os.write(bytes);
        byte[] bytes1 = "我爱你中国666".getBytes();
        os.write(bytes1);
        byte[] bytes2 = "\r\n".getBytes();//这里\r\n也是换行符,兼容性更好而已
        os.write(bytes2);

        //4、写一个字节数组的一部分出去
        byte[] bytes3 = "我爱中国".getBytes();
        os.write(bytes3, 0, 3);//从下标为0的字节,往后写3个,即“我”(注意此处为UTF-8字符集,汉字占3字节)

        //5、关闭IO流管道
        os.close();//关闭IO管道,释放资源

    }
}

运行效果:

6、总结

四、文件复制

1、思路

2、举例

        下面我们要将D:\01.gif这张动态图,复制到C:\Users\jhj15\Pictures目录下,并令新图片名称为new01.gif

public class Test5 {
    public static void main(String[] args) throws Exception {
        //目标:使用字节流完成文件的复制操作
        //源文件:D:\01.gif
        //目标文件:C:\Users\jhj15\Pictures\new01.gif  (注意:复制过去的时候必须带文件名,否则无法自动生成文件)

        //调用自定义的复制文件方法
        copyFile("D:\\01.gif", "C:\\Users\\jhj15\\Pictures\\new01.gif");
    }

    public static void copyFile(String srcPath, String destPath) throws Exception {
        //1、创建字节输入流管道,与源文件接通,用来读取磁盘(文件)的字节到内存(Java程序)
        FileInputStream is = new FileInputStream("D:\\01.gif");
        //2、创建字节输出流管道,与目标文件接通,用来从内存(Java程序)写数据到目标文件(磁盘)
        FileOutputStream os = new FileOutputStream("C:\\Users\\jhj15\\Pictures\\new01.gif");
        //3、创建一个字节数组,用来存放字节(中转站)
        byte[] bytes = new byte[1024];//长度设为1024
        int len;//用来标记一次读取到的字节数,防止数据残留问题
        while((len = is.read(bytes)) != -1){
            os.write(bytes, 0 , len);//读取多少,就倒多少字节,防止数据残留
        }
        System.out.println("复制成功!");


    }
}

运行结果:

3、结论

①字节流非常适合做文件的复制操作

任何文件的底层都是字节,字节流做复制,是一字不漏的转移全部字节,只要复制后的文件格式一致就没问题!

②字节流不适合读取汉字输出

因为字节流会截断汉字,导致输出乱码。

举例:使用UTF-8字符集时,汉字占3字节,而你使用字节流读取汉字时,若每次读取1字节,则必然输出乱码;而每次读取一个字节数组(n字节),也可能截断汉字,导致输出乱码。

五、资源释放问题

1、方式1:try-catch-finally(不推荐)

package com.itheima.IO流;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class Test5 {
    public static void main(String[] args) throws Exception {
        //目标:使用字节流完成文件的复制操作
        //源文件:D:\01.gif
        //目标文件:C:\Users\jhj15\Pictures\new01.gif  (注意:复制过去的时候必须带文件名,否则无法自动生成文件)

        //调用自定义的复制文件方法
        copyFile("D:\\01.gif", "C:\\Users\\jhj15\\Pictures\\new01.gif");
    }

    public static void copyFile(String srcPath, String destPath){
        FileInputStream is = null;
        FileOutputStream os = null;
        try {
            //1、创建字节输入流管道,与源文件接通,用来读取磁盘(文件)的字节到内存(Java程序)
            is = new FileInputStream("D:\\01.gif");
            //2、创建字节输出流管道,与目标文件接通,用来从内存(Java程序)写数据到目标文件(磁盘)
            os = new FileOutputStream("C:\\Users\\jhj15\\Pictures\\new01.gif");
            //3、创建一个字节数组,用来存放字节(中转站)
            byte[] bytes = new byte[1024];//长度设为1024
            int len;//用来标记一次读取到的字节数,防止数据残留问题
            while((len = is.read(bytes)) != -1){
                os.write(bytes, 0 , len);//读取多少,就倒多少字节,防止数据残留
            }
            System.out.println("复制成功!");
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                if(is!=null) is.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            try {
                if(os!=null) os.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }


    }
}

优点:finally里的代码一定会执行,因此一定会关闭IO流管道资源。

缺点:代码臃肿、不优雅,因此不推荐。

2、方式2:try-with-resource(推荐)

注意:try后面的括号()内,只能定义资源。

那什么叫资源呢?答案:实现Closeable接口的类,都叫资源。

举例:

以上就是字节流的全部内容,如果想了解更多IO流的知识,请关注本博主~~

标签:文件,读取,05,内存,IO,new,os,字节
From: https://blog.csdn.net/qq_63981644/article/details/143415282

相关文章

  • PCIe系列专题之二:2.0 Transaction layer事务层概述
    一、故事前传上回我们对PCIe的一些基础概念作了一个宏观的介绍,了解了PCIe是一种封装分层协议(packet-basedlayeredprotocol),主要包括事务层(Transactionlayer),数据链路层(Datalinklayer)和物理层(Physicallayer)。较为详细解释请见之前的文章:PCIe技术概述;二、事务层概述......
  • IO 多路复用技术:原理、类型及 Go 实现
    文章目录1.引言IO多路复用的应用场景与重要性高并发下的IO处理挑战2.IO多路复用概述什么是IO多路复用IO多路复用的优点与适用场景3.IO多路复用的三种主要实现3.1`select`3.2`poll`3.3`epoll`三者对比4.深入理解epoll4.1epoll的三大操作4.2epoll的......
  • 【文献阅读】Multi-region radiomics for artificially intelligent diagnosis of bre
    题目:基于多模态超声的人工智能诊断乳腺癌的多区域放射组学研究摘要:目的:乳腺癌的超声(US)诊断通常是基于单一的超声方式对整个乳腺肿瘤的单一区域,这限制了诊断性能。在乳腺肿瘤的多模态超声图像上的多个区域都可能对诊断有有用的信息。本研究旨在提出一种多模态放射组学多模式......
  • 关于LIME(局部可解释模型无关解释)和SHAP(SHapley Additive exPlanations)的具体应用案例
    关注我,持续分享逻辑思维&管理思维&面试题;可提供大厂面试辅导、及定制化求职/在职/管理/架构辅导;推荐专栏《10天学会使用asp.net编程AI大模型》,目前已完成所有内容。一顿烧烤不到的费用,让人能紧跟时代的浪潮。从普通网站,到公众号、小程序,再到AI大模型网站。干货满满。学成后可......
  • dotNet 整合 Microsoft.Extensions.DependencyInjection 利用反射实现依赖批量注入
    前言框架.net8.0Microsoft.Extensions.DependencyInjection8.0创建三个类库项目ConfigServicesLogServicesMailServices创建一个控制台项目ConsoleAppMailConfigServicesnamespaceConfigServices.IService{publicinterfaceIConfigService{......
  • [AAAI2024]AnomalyGPT Detecting Industrial Anomalies Using Large Vision-Language
    本篇论文将大语言模型应用在工业异常检测(IndustrialAnomalyDetection,IAD)任务。引言IAD任务旨在检测和定位工业产品图像中的异常。由于现实世界样本的稀有性和不可预测性,要求模型仅在正常样本上进行训练,并实现对测试时异常样本的检测。如图1,现有的IAD方法给出异常样本的概率,......
  • ssm051网上医院预约挂号系统+jsp(论文+源码)_kaic
     本科毕业设计论文题目:网上医院预约挂号系统设计与实现系   别:XX系(全称)专    业:软件工程班   级:软件工程15201学生姓名:学生学号:指导教师:导师1       导师22021年5月摘  要如今的信息时代,对信息的共享性,信息......
  • 使用 axios 拦截器实现请求和响应的统一处理(附常见面试题)
    在现代前端开发中,我们经常需要向服务器发送HTTP请求,并根据响应内容做不同的处理。axios是一个流行的HTTP库,提供了拦截器功能,可以在请求和响应阶段插入自定义逻辑,这使得我们在处理认证、错误提示等场景时更为简洁、统一。本文将讲解如何利用axios的请求拦截器和响应拦......
  • 【文献阅读】Multimodal feature learning and fusion on B-mode ultrasonography and
    题目:基于点门控深度网络的b型超声和超声弹性成像的多模态特征学习与融合诊断摘要:b型超声和超声弹性成像可用于前列腺癌(PCa)的临床诊断。两种超声(US)模式的结合使用计算机辅助可能有助于提高诊断性能。提出了一种基于多模态超声的计算机辅助诊断(CAD)技术。首先,从b型US图像和超声......
  • H5登录界面输入账号密码,在ios苹果微信手机上输入框上下闪烁问题
    场景描述:H5登录界面输入账号密码,在ios苹果微信手机上输入框上下闪烁问题苹果手机的浏览器就有了自动填充密码的功能,具体来说就是一个手机号密码登录的页面,ios识别到当前页面有密码输入框,所以触发了自动填充密码的功能。解决办法:在2个输入框中间加个隐藏输入框核心代码:<inpu......