JAVAEE之文件IO_数据流概念,字节流:InputStream、OutputStream,字符流:reader、writer,及实例代码

什么是数据流

 顾名思义,I 表示input,O 表示output,也就是输入输出流,主要是在程序与文件之间,用于传输数据的通道。既然要传输数据,那么我们需要理解文件和程序之间哪种方向的传输是输入流,哪种传输作为输出流?我们可以举一个例子,如下图所示:
在这里插入图片描述
 IO 流是 Java IO 中的核心概念。流是在概念上表示无穷无尽的数据流。IO 流连接到数据源或数据的目的地,连接到数据源的叫输入流,连接到数据目的地的叫输出流。Java 程序不能直接从数据源读取和向数据源写入,只能借助 IO 流从输入流中读取数据,向输出流中写入数据。
 Java IO 中的流可以是基于字节的(读取和写入字节)也可以基于字符的(读取和写入字符),所以分为字节流和字符流,两类流根据流的方向都可以再细分出输入流和输出流。
注意:这里的输入、输出是站在CPU的角度。


一、字节流

 字节流主要操作字节数据或二进制对象。字节流有两个核心抽象类:InputStream 和 OutputStream。所有的字节流类都继承自这两个抽象类。

1.1 输入字节流:InputStream

 InputStream 只是一个抽象类,要使用还需要具体的实现类。关于 InputStream 的实现类有很多,基本可以认为不同的输入设备都可以对应一个 InputStream 类,我们现在只关心从文件中读取,所以使用 FileInputStream
常用的方法
在这里插入图片描述
参考实例代码:

package CharStream;

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


public class Demo3 {

    public static void main(String[] args) {
    //1、创建File对象
        try(InputStream inputStream = new FileInputStream("D:/text.txt")){
            byte[] buffer = new byte[1024];
            int n = inputStream.read(buffer);   //2、读取文件内容
            System.out.println("n:"+n);
            for (int i = 0; i < n; i++) {
                System.out.printf("%x\n",buffer[i]);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

利用 Scanner 进行字符读取

 我们看到了对字符类型直接使用 InputStream 进行读取是非常麻烦且困难的,所以,我们使用一种我们之前比较熟悉的类来完成该工作,就是 Scanner 类。

package CharStream;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Scanner;

public class Demo5 {

    public static void main(String[] args) {

        try(InputStream inputStream = new FileInputStream("d:/text.txt")){
            //此时scanner就是从文件中读取了!!
            Scanner scanner = new Scanner(inputStream);
            String s = scanner.next();
            System.out.println(s);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

1.2 输出字节流:OutputStream

构造方法:
在这里插入图片描述
 OutputStream 同样只是一个抽象类,要使用还需要具体的实现类。我们现在还是只关心写入文件中,所以使用 FileOutputStream。
常用方法
在这里插入图片描述
参考实例代码:

package CharStream;

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


public class Demo4 {

    public static void main(String[] args) {
    
    //1. 打开文件,如果文件存在,会清除文件的内容,如果文件不存在,就会创建新文件
        try(OutputStream outputStream  = new FileOutputStream("d:/text.txt",true)){
            String s= "你好世界";
            
	//2. 使用wirte方法写入内容,字符串调用getBytes()方法可以得到字符串对应的字节数组
            outputStream.write(s.getBytes());    
            //和writer类似,OutPutStream打开一个文件,就会默认清空文件的原有内容,如果不想清空,在构造方法中第二个参数传入true
	//3. 关闭文件

        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

 上述,我们其实已经完成输出工作,但总是有所不方便,我们接来下将 OutputStream 处理下,使用PrintWriter 类来完成输出,因为PrintWriter 类中提供了我们熟悉的 print/println/printf 方法。
参考实例代码如下:

package CharStream;

import java.io.*;
public class Demo6 {
    public static void main(String[] args) {
        try(OutputStream outputStream = new FileOutputStream("d:/text.txt")){
        
            //这里就相当于把字节流转成字符流了
            PrintWriter writer = new PrintWriter(outputStream);
            writer.println("hello");
            writer.flush();   //
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }


    }
}

二、 字符流

 上面的字节流是以字节为单位读写文件数据,但是对unicode字符来说,中文字符占了两个字节,处理不当会出现“乱码”现象。
 字符流操作的是字符,字符流有两个核心类:Reader 类和 Writer 。所有的字符流类都继承自这两个抽象类。

2.1 输入字符流: Reader

字符流输入流作用:读取文件内容。
参考实例代码:

package CharStream;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;

public class Demo1 {
    /**
     * 字符流
     * read
     * @param args
     * @throws IOException
     */

    public static void main(String[] args) throws IOException {

      //  Reader reader = new FileReader("d:/text.txt");


        /**
         * 1.一次read一个字符
         *
         * while(true){
         *             int c  = reader.read();   //无参数read,一次只返回一个字符
         *             if (c== -1){
         *                 //读取完毕
         *                 break;
         *             }
         *             char ch = (char) c;
         *             System.out.println(ch);
         *         }
		*/


        try{
            //2.一次read多个字符
            while(true){
                char[] cubf = new char[1024];
                int n = reader.read(cubf);

                 * n表示当前读取到的字符的个数
                 *  一个参数read:一次读取若干个字符,会把参数指定的cbuf数组给填充满
                 *  应该往这个read里传入的是一个空的字符数组,然后由read方法内部对这个数组内容进行填充,次数"cbhf"这个参数,称为”输出型参数·“
         if (n== -1){
         //完毕读取
         break;
         }
         System.out.println("n = "+n);
         for (int i = 0; i < n; i++) {
         System.out.println(cubf[i]);
         }

         }
         }finally {
         reader.close();
         //3. 一个文件使用完了,要记得close (使用close方法,最主要的方法是为了释放文件描述符)
         }
         */
        //try with resources语法的目的 :()定义的变量,会在try代码快结束的时候(无论是正常结束还是抛异常),自动调用其中的close方法


        try(Reader reader = new FileReader("D:/text.txt") ){
            while(true){
                char[] cubf = new char[3];
                int n = reader.read(cubf);
                if (n == -1){
                    break;
                }
                System.out.println("n:"+n);
                for (int i = 0; i < n; i++) {
                    System.out.println(cubf[i]);

                }

            }
        }
       // reader.read();   //三个参数read:一次读取若干个字符,会把参数执行的cbuf数组中的off这个位置开始,到len这么长的范围内填满

    }
}

2.2 输出字符流:Writer

参考代码实例:

package CharStream;

import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;

/**
 * @author Zhang
 * @date 2024/5/1620:23
 * @Description:
 */
public class Demo2 {
    /**
     *字符流
     * write
     * @param args
     */


    public static void main(String[] args) {
        try(Writer writer = new FileWriter("d:/text.txt",true);) {
            writer.write("我在学习IO");  //写入文件,默认会把原来的内容清空,解决办法加true

        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

三、 字节流、字符流怎么选择?

 字节流和字符流都有 read()、write()、flush()、close() 这样的方法,这决定了它们的操作方式近似。
 字节流的数据是字节(二进制对象)。主要核心类是 InputStream 类和 OutputStream 类。字符流的数据是字符,主要核心类是 Reader 类和 Writer 类。所有的文件在硬盘或传输时都是以字节方式保存的,例如图片,影音文件等都是按字节方式存储的。字符流无法读写这些文件。
 所以,除了纯文本数据文件使用字符流以外,其他文件类型都应该使用字节流方式。字节流到字符流的转换可以使用 InputStreamReader 和 OutputStreamWriter。使用 InputStreamReader 可以将输入字节流转化为输入字符流,使用OutputStreamWriter可以将输出字节流转化为输出字符流。

相关练习:扫描指定目录,并找到名称中包含指定字符的所有普通文件(不包含目录),并且后续询问用户是否要删除该文件:

package CharStream;

import java.io.File;
import java.util.Scanner;

/**
 * @author Zhang
 * @date 2024/5/1715:28
 * @Description:
 */
public class Test {


    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        // 1. 先让用户输入一个要扫描的目录
        System.out.println("请输入要扫描的路径");
        String path = scanner.next();
        //判断路径是否存在
        File rootPath = new File(path);
        if (!rootPath.isDirectory()){
            System.out.println("您输入的扫描的路径有误");
            return;
        }

        //2.再让用户输入一个要查询的关键词
        System.out.println("请输入要删除文件的关键词");
        String word = scanner.next();

        //3. 进行递归扫描,这个方法进行递归
        scanDir(rootPath,word);

    }

    private static void scanDir(File rootPath, String word) {

        //1. 先列出rootPath 中的所有文件和目录
        File[] files = rootPath.listFiles();
        if(files  == null){
            ///当前目录为空,就可以直接返回了
            return;
        }

        //2. 遍历这里的每个元素,针对不同各类型做出不同的处理
        for (File f: files){
            System.out.println("当前扫描的文件:"+f.getAbsolutePath()); //加个日志,方便观察当前递归的执行过程
            if (f.isFile()){
                //普通文件,检查是否要被删除,并执行删除操作
                checkDelete(f,word);
            }else {
                //目录,运用递归再去判定子目录里包含的内容
                scanDir(f,word);
            }
        }
    }

    private static void checkDelete(File f, String word) {
        if (!f.getName().contains(word)){
            //不必删除,直接方法结束
            return;
        }
        //需要删除
        System.out.println("当前文件为:"+f.getAbsolutePath() +",确认是否要删除");
        Scanner scanner  = new Scanner(System.in);
        String choice = scanner.next();
        if (choice.equals("Y") || choice.equals("y")){
            //真正执行删除操作
            f.delete();
            System.out.println("删除完毕!");
        }else{
            //如果出入其他值,不一定是n,都会取消删除操作
            System.out.println("取消操作!");
        }



    }
}

总结

文件IO流框架:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/665517.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ros2 launch gazebo_ros gazebo.launch.py无法启动

现象&#xff1a; 我的系统是ubuntu22.04&#xff0c;ros2的版本是humble&#xff0c;当运行os2 launch gazebo_ros gazebo.launch.py命令&#xff0c;会卡死在第六行&#xff0c;gazebo也不会打开但最后单独使用gazebo则可以打开 原因&#xff1a; 没有设置环境变量 解决办法 …

开源硬件初识——Orange Pi AIpro(8T)

开源硬件初识——Orange Pi AIpro&#xff08;8T&#xff09; 大抵是因为缘&#xff0c;妙不可言地就有了这么一块儿新一代AI开发板&#xff0c;乐于接触新鲜玩意儿的小火苗噌一下就燃了起来。 还没等拿到硬件&#xff0c;就已经开始在Orange Pi AIpro 官网上查阅起资料&…

Aws CodeCommit代码仓储库

1 创建IAM用户 IAM创建admin用户&#xff0c;增加AWSCodeCommitFullAccess权限 2 创建存储库 CodePipeline -> CodeCommit -> 存储库 创建存储库 3 SSH 1) window环境 3.1.1 上载SSH公有秘钥 生成SSH秘钥ID 3.1.2 编辑本地 ~/.ssh 目录中名为“config”的 SSH 配置文…

ARM32开发——第一盏灯

&#x1f3ac; 秋野酱&#xff1a;《个人主页》 &#x1f525; 个人专栏:《Java专栏》《Python专栏》 ⛺️心若有所向往,何惧道阻且长 文章目录 开发流程需求分析项目新建代码编写GPIO初始化 程序编译程序烧录烧录扩展&#xff08;熟悉&#xff09;官方烧录器烧录&#xff08;…

Java过滤特殊空格nbsp;

现象&#xff1a; 用Java处理excel文件中的以下字符串时&#xff0c;想去除此空格&#xff0c;却发现用String.trim()没有直到预期效果&#xff1a; 原因&#xff1a; 在网上找了下&#xff0c;应该是这其实是html中经常使用的一种特殊空格字符&nbsp&#xff1b; 处理&a…

LabVIEW调用外部DLL(动态链接库)

LabVIEW调用外部DLL&#xff08;动态链接库&#xff09; LabVIEW调用外部DLL&#xff08;动态链接库&#xff09;可以扩展其功能&#xff0c;使用外部库实现复杂计算、硬件控制等任务。通过调用节点&#xff08;Call Library Function Node&#xff09;配置DLL路径、函数名称和…

C/C++ 进阶(4)二叉搜索树

个人主页&#xff1a;仍有未知等待探索-CSDN博客 专题分栏&#xff1a;C 一、概念 二叉搜索树&#xff0c;又称二叉排序树&#xff08;中序是有序的&#xff09;。 性质 1、非空左子树的键值小于根节点的键值 2、非空右子树的键值大于根节点的键值 &#xff08;空树也是二叉搜…

变压器励磁涌流MATLAB仿真模型

微❤关注“电气仔推送”获得资料&#xff08;专享优惠&#xff09; 变压器励磁涌流的产生机理 1、变压器是电力系统的关键部分&#xff0c;在实际的 运行中&#xff0c;变压器需要进行相应的充电&#xff0c;而在充电的过 程中&#xff0c;就需要进行开合闸作业。在开合闸作业…

智慧楼宇:城市生活的新篇章

在城市的喧嚣与繁华中&#xff0c;楼宇不仅是我们工作与生活的场所&#xff0c;更是智慧科技发展的前沿阵地。当传统的建筑遇上智慧的火花&#xff0c;便诞生了令人瞩目的智慧楼宇。 山海鲸可视化搭建的智慧楼宇数字孪生系统 一、智慧楼宇&#xff0c;定义未来生活 智慧楼宇不…

vue3学习使用笔记

1.学习参考资料 vue3菜鸟教程&#xff1a;https://www.runoob.com/vue3/vue3-tutorial.html 官方网站&#xff1a;https://cn.vuejs.org/ 中文文档: https://cn.vuejs.org/guide/introduction.html Webpack 入门教程&#xff1a;https://www.runoob.com/w3cnote/webpack-tutor…

【linux】docker下nextcloud安装人脸识别插件2

接上文 【linux】docker下nextcloud安装人脸识别插件-CSDN博客 由于作者不再维护此插件&#xff0c;转而开发新的插件 recognize &#xff0c;因此同步更新插件使用教程。 1、下载人脸识别app&#xff1a;recognize Recognize - Apps - App Store - Nextcloud 2、将插件recog…

Java后端模拟面试 题集⑤

1.先作个自我介绍吧 面试官您好&#xff0c;我叫张睿超&#xff0c;来自湖南长沙&#xff0c;大学毕业于湖南农业大学&#xff0c;是一名智能科学与技术专业的统招一本本科生。今天主要过来面试贵公司的Java后端开发工程师岗位。 大学里面主修的课程是Java、Python、数字图像…

Linux自动挂载服务autofs讲解

1.产生原因 2.配置文件讲解 总结&#xff1a;配置客户端&#xff0c;先构思好要挂载的目录如&#xff1a;/abc/cb 然后在autofs.master中编辑&#xff1a; /abc&#xff08;要挂载的主目录&#xff09; /etc/qwe&#xff08;在这个文件里去找要挂载的副目录&#xff0c;这个名…

【C++】入门(二):引用、内联、auto

书接上回&#xff1a;【C】入门&#xff08;一&#xff09;&#xff1a;命名空间、缺省参数、函数重载 文章目录 六、引用引用的概念引用的使用场景1. 引用做参数作用1&#xff1a;输出型参数作用2&#xff1a;对象比较大&#xff0c;减少拷贝&#xff0c;提高效率 2. 引用作为…

LangGraph实战:可控的AI航空客服助手

上节课&#xff0c;我们定义了AI航空客服助手需要使用的一系列API接口工具&#xff0c;并定义了一个简单的零样本代理作为用户的助手。没看过的同学可以点击链接LangGraph实战&#xff1a;从零分阶打造人工智能航空客服助手查阅。这次我们将讲述&#xff0c;如何通过LangGraph的…

预编码算法(个人总结)

引言 预编码算法是现代无线通信系统中的关键技术&#xff0c;特别是在多输入多输出&#xff08;MIMO&#xff09;系统中。它们通过在发送端对信号进行处理&#xff0c;减少干扰并提高信道容量。这种技术广泛应用于5G、Wi-Fi和卫星通信系统中。本教程将详细介绍预编码算法的背景…

Redis 探索之旅(进阶)

目录 今日良言&#xff1a;从不缺乏从头开始的勇气 一、持久化 1、RDB 2、AOF 二、Redis 的事务 三、主从复制 四、哨兵模式 五、集群模式 六、缓存 七、分布式锁 今日良言&#xff1a;从不缺乏从头开始的勇气 一、持久化 持久化就是把数据存储在硬盘上&#xff0c;无…

鸿蒙开发接口媒体:【@ohos.multimedia.media (媒体服务)】

媒体服务 说明&#xff1a; 本模块首批接口从API version 6开始支持。后续版本的新增接口&#xff0c;采用上角标单独标记接口的起始版本。 开发前请熟悉鸿蒙开发指导文档&#xff1a; gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md点击或者复制转到。 媒体子系…

C++青少年简明教程:While和Do-while循环语句

C青少年简明教程&#xff1a;While和Do-while循环语句 C的while和do-while语句都是循环控制语句&#xff0c;用于重复执行一段代码。while语句在循环开始前检查循环条件&#xff0c;而do-while语句在循环结束后检查循环条件。 使用while循环时&#xff0c;如果需要在每次迭代前…