Java学习42-Java 流(Stream)、文件(File)和IO - FileReader\FileWriter的使用

IO流

IO流的概述,分类等

Java程序中,对于数据的输入输出以stream方式进行,可以看作是一种数据的流动。
IO流中的IO是Input和Output的缩写,是非常实用的技术,用于处理设备之间的数据传输。读写文件,网络通讯等。

(以下视角,都是站在程序(内存)内部角度观察的。)
输入Input:读取外部数据(磁盘,光盘等存储设备的数据)到程序(内存)中
输出Output:将程序(内存)数据输出到磁盘,光盘等存储设备中

流的分类:

java.io包下提供了各种“流”类和接口,用以获取不同种类的数据,并通过下列方法输入或输出数据。

  • 按数据的流向不同分为:输入流和输出流。

    • 输入流:把数据从其他设备上读取到内存中的流。(以InputStream / Reader结尾)
    • 输出流:把数据从内存中写出到其他设备上的流。(以OutputStream / Writer结尾)
  • 按操作数据单位的不同分为:字节流(8 bit)和字符流(16 bit)

    • 字节流: 以字节为单位,读写数据的流。字节Byte是计算机数据处理的基本单位,通常由8位(bit)组成。(以InputStream, OutputStream结尾)
    • 字符流:以字符为单位,读写数据的流。字符Character用于表示文本中的单个字母、数字或符号。在Java中,char是一个基本数据类型,char类型占用16位(2字节)。(以Reader Writer结尾)
  • 根据IO流的角色不同分为节点流和处理流。

    • 节点流:直接从数据源或目的地读写数据。

在这里插入图片描述

    • 处理流:不直接连接到数据源或目的地,而是连接在以存在的流(节点流或处理流)之上,通过对数据的处理为程序提供更为强大的读写功能。

在这里插入图片描述

流的分类图示:

在这里插入图片描述

流的API

java的IO流共涉及40多个类,实际上非常规则,都是从如下4个抽象类派生出来的。

抽象基类输入流输出流
字节流InputStreamOutputStream
字符流ReaderWriter

由这四个类派生出来的子类名称都是以其父类名作为子类名后缀。

分类字节输入流字节输出流字符输入流字符输出流
抽象基类InputStreamOutputStreamReaderWriter
访问文件FileInputStreamFileOutputStreamFileReaderFileWriter
访问数组ByteArrayInputStreamByteArrayOutputStreamCharArrayReaderCharArrayWriter
访问管道PipeInputStreamPipeOutputStreamPipedReaderPipedWriter
访问字符串StringReaderStringWriter
缓冲流BufferedInputStreamBufferedOutputStreamBufferedReaderBufferedWritter
转换流InputStreamReaderOutputStreamWriter
对象流ObjectInputStreamObjectOutputStream
FilterInputStreamFilterOutputStreamFilterReaderFilterWriter
打印流PrintStreamPrintWriter
推回输入流PushbackInputStreamPushbackReader
特殊流DataInputStreamDataOutputStream

总结一下:

抽象基类(基本类)4个节点流(也称文件流,能处理文件)
InputStreamFileInputStream
OutputStreamFileOutputStream
ReaderFileReader
WriterFileWriter

说明:本章虽然涉及到的流很多,但是使用流进行数据的读写操作是非常标准和规范的。

练习1:读取hello.txt中的内容,显示在控制台上。
建议使用try-catch-finally的方式处理异常,确保流一定被关闭了,避免内存泄漏。

提示:
File f1= new File("xxx.txt");

FileReader myfr1 = new FileReader(f1)

int mydata = myfr1.read();

if(mydata != -1){ System.out.print((char)mydata); }

//提示:因为当读取数值为-1时候,是文件全部读取完成的标记。

package IOTest;

import org.junit.Test;

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

public class FileReaderWriterTest {
    /*
    * 需求:读取hello.txt中的内容,显示在控制台上。
    * 建议使用try-catch-finally的方式处理异常,确保流一定被关闭了,避免内存泄漏。
    * 举例见如下的test2
    * */
    @Test
    public void test1() throws IOException {
        //1.创建File类的对象,对应hello.txt文件
        File f1 = new File("hello.txt");
        //2.创建输入型字符流,用于读取数据
        FileReader fr1 = new FileReader(f1);
        //3.读取数据并且显示在控制台上

        //方式1:
        //   int readfr1 = fr1.read();
        //   while (readfr1 !=-1)
        //   //一旦等于-1说明读到最末尾了,读完毕了
        //   {
        //       System.out.print((char)readfr1);
        //       readfr1 = fr1.read();
        //   }


        /* 这种写法也是类似的,都可以用
        while(true){
            int ff1 = fr1.read();
            if(ff1 == -1) break;
            else System.out.print((char)ff1);
            }
        */

        //方式2:
        int data;
        while ((data = fr1.read()) != -1) {

            System.out.print((char) data);
        }
        //4.流资源的关闭操作(必须关闭,否则资源泄漏)
        fr1.close();

    }

        @Test
        public void test2(){
            //1.创建File类的对象,对应hello.txt文件
            File f2 = new File("hello.txt");
            //2.创建输入型字符流,用于读取数据
            FileReader filereader1= null;
            //3.读取数据并且显示在控制台上(读取结果为int类型,当获得-1时说明读到了末尾)
            try {
                filereader1 = new FileReader(f2);
                int data2;
                while( ( data2=filereader1.read() ) != -1){

                    System.out.print((char)data2);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                //4.流资源的关闭操作(必须关闭,否则资源泄漏)
                try {
                    if(filereader1 != null)//这里是为了优化添加的,如果fread为null,说明某种原因创建fread失败了,直接关闭资源就可以了。
                        filereader1.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }


    /*
     * 需求:读取hello.txt中的内容,显示在控制台上。
     * 对test2()进行优化,每次读取多个字符串存放到字符数组中,减少与磁盘的交互次数,从而提高效率。
     *
     * */

    @Test
    public void test3() throws FileNotFoundException {
        FileReader filereader1= null;

        try {
            //1.创建File类的对象,对应hello.txt文件
            File f2 = new File("hello.txt");
            //2.创建输入型字符流,用于读取数据
            filereader1 = new FileReader(f2);

            //3.读取数据,并显示在控制台上
            char[] cbuffer =new char[5];
            int len= filereader1.read(cbuffer);
            //当filereader1.read(cbuffer)一般返回的是读取到数组char[]cbuffer里面的数据个数,当返回-1说明读完了
             while(len!=-1){
             //遍历数组
                //for (int i = 0; i < cbuffer.length; i++) {
                for (int i = 0; i < len; i++) {
                    System.out.print(cbuffer[i]);
                }
                len = filereader1.read(cbuffer);
            }




        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            //4.流资源的关闭操作(必须关闭,否则资源泄漏)
            try {
                if(filereader1 != null)//这里是为了优化添加的,如果fread为null,说明某种原因创建fread失败了,直接关闭资源就可以了。
                    filereader1.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    }


运行结果:

helloWorld123

举例2:往文件hello.txt中写入自定义的的内容。
比如原文件hello.txt文件内容为

this is line 1
this is line 2
this is line 3

代码结构类似这样

File myf1 = new File("hello.txt");
filewriter1=new FileWriter(myf1);
filewriter1.write("写进文件的内容");

//注意,如果文件不存在,系统会自动创建。

  • 如果想要覆盖原文件内容,直接写
    filewriter1=new FileWriter(myf1);
    或者写
    filewriter1=new FileWriter(myf1,flase);

  • 如果想要直接在原文件内容后面直接追加内容:
    filewriter1=new FileWriter(myf1,true);

参考代码:


    /*
    * 需求:将内存中的数据写入到指定文件中
    *
    * */

package IOTest;

import org.junit.Test;

import java.io.*;

public class FileReaderWriterTest {
    @Test
    public void test04()  {
        FileWriter wr1= null;
        try {
            //1.创建File类的对象,指明要写出的文件的名称
            File filedest= new File("hello.txt");
            //2.创建输出流

            //覆盖文件内容,使用构造器:
            //wr1 = new FileWriter(filedest);
            // 这一句等同于wr1 = new FileWriter(filedest,false);会覆盖文件内容

            //在现有的文件上追加内容使用构造器:
            wr1 = new FileWriter(filedest,true);
            //3.写出具体过程

            wr1.write("写入的内容");
            System.out.println("输出完毕");
        } catch (IOException e) {
            e.printStackTrace();
        } finally { //4.关闭资源
            try {
                if(wr1 != null)
                wr1.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }


    }


    }



输出结果:

输出完毕

Process finished with exit code 0

/*
*
* 需求:复制一份hello.txt文件(以及其内容),命名为hello_copy.txt
*
* */

提示:
1.创建file文件(src & desination)
File file_src = new File("src_file.txt");
File file_des = new File("des_file.txt");
2. 创建输入输出流
FileReader filereader1 = new FileReader(file_src);
FileWriter filewriter1 = new FileWriter(file_des);
3. 构建数据读入写出char当然这一步也可以不用
char [] cart = new char[5];
4. 读写文件

int len = filereader1.read(cart);
while(len !=-1){
	for(i=0;i<len;i++){
	filewriter1.write(cart,0,len);			
						}
len=filereader1.read(cart);
	}
filewriter1.close();
filereader1.close();

程序示例:

package IOTest;

import org.junit.Test;

import java.io.*;

public class FileReaderWriterTest {
@Test
    public void test05(){

        //替代方案(注意这种方法会将原始文件删除):
        //File myf1 = new File("hello.txt");
        //myf1.renameTo(new File("hello_copy.txt"));

        //方式2:
        FileReader filereader1 = null;
        FileWriter filewriter1 = null;
        try {
            //1.创建File类的对象
            File f_org = new File("hello_copy.txt");
            File f_dest = new File("hello_3.txt");
  //File f_dest = new File("hello_3.txt",true); //在现有的文件后面直接追加内容,而不是简单覆盖原文件内容

            //2.创建输入流,输出流
            filereader1 = new FileReader(f_org);
            filewriter1 = new FileWriter(f_dest);
            //3.数据的读入和写出的过程
            char[] charbuff = new char[5];

            //原本的程序如下:
            int len = filereader1.read(charbuff);//记录每次读到charbuff中的字符个数。
            while(len!=-1) {
                for (int i = 0; i < len; i++) {
                    System.out.print(charbuff[i]);
                    //filewriter1.write(charbuff[i]);
                   //filewriter1.write(charbuff,0,len);//这样写是错误的。因为这句其实没有用到i,在i=0到len的循环会一遍又一遍写入至少5次同样的信息。正确的写法,这一句话放在for循环的外面就行。
                    //filewriter1.write(charbuff);//这样写是也错误的。在不是5的倍数情况下,比如12345hi有可能读出12345hi345,
                    // 因为内存中的345还在,而hi后面又没有数据了。
//
                }
                filewriter1.write(charbuff,0,len);
                len=filereader1.read(charbuff);
            }

            //可优化为如下:len写入while循环括号内(但是确保是在for循环外面,或者直接不要for循环了)
           // int len;
           // while((len = filereader1.read(charbuff)) != -1){
           //     filewriter1.write(charbuff,0,len);//0角标开始写,一共写len个角标
           // }

            System.out.println("复制成功");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if(filereader1 != null)
                filereader1.close();

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

            try {
                if(filewriter1 !=null)
                filewriter1.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }


    }

    }



运行结果提示,文件内容复制成功:

this is line 1
this is line 2
this is line 3
this is my writting stamp
一二三四物流七八
写入的内容复制成功

Process finished with exit code 0

总结:FileReader\FileWriter的使用
执行步骤:

  1. 创建读取或写出File类的对象
  2. 创建输入流或输出流
  3. 具体的读如或写出的过程
    读入:read(char[] charbuffer)
    写出:write(String str) / write(char[] chabuffer,0,len)
  4. 关闭流资源,避免内存泄漏

注意:

  • 因为涉及到流资源的关闭操作,所以出现异常的话,需要使用try-catch-finally的方式来处理异常。
  • 对于输入流来讲,要求File类的对象对应的物理磁盘上的文件必须存在。否则报错FileNotFoundException;
  • 对于输出流来讲,File类的对象对应的物理磁盘上的文件可以不存在。
    如果此文件不存在,则在此输出的过程中,会自动创建此文件,并写出数据到此文件中。
    如果此文件存在,使用FileWriter(File file)或 FileWriter(File file,false):输出数据过程中,会新建同名的文件,对现有的文件进行覆盖。
    如果用FileWriter(File file,true):表示输出数据过程中,会在现有的文件的末尾追加写出的内容。

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

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

相关文章

JUC并发编程2(高并发,AQS)

JUC AQS核心 当有线程想获取锁时&#xff0c;其中一个线程使用CAS的将state变为1&#xff0c;将加锁线程设为自己。当其他线程来竞争锁时会&#xff0c;判断state是不是0&#xff0c;不是自己就把自己放入阻塞队列种&#xff08;这个阻塞队列是用双向链表实现&#xff09;&am…

聚丙烯PP材料粘接方法?泰达克TADHE专用于PP材料塑料粘接的UV胶水提供了解决方案

PP&#xff08;聚丙烯&#xff09;&#xff0c;简称PP。 PP是一种疏水性的塑料&#xff0c;需要特殊的处理后再和胶水粘接&#xff0c;以确保良好的粘接效果。常用的PP材料粘接方法&#xff1a; ​1.表面处理 因PP表面的疏水性&#xff0c;可以先进行表面处理。使用酒精或丙酮…

完整的项目源码!在线考试完整系统源码(可接私活)

最近有一些读者问我有没有完整的基于SpringbootVue的项目源码&#xff0c;今天给大家整理了一下&#xff0c;并且录制了搭建的教程&#xff0c;无偿分享给大家。 一、系统运行图 1、登陆页面 2、后台管理 3、全套环境资源 ​源码文件部分截图&#xff0c;带视频教程 ​ 在实际…

【图论】Dijkstra单源最短路径-朴素方法-简单模板(迪杰斯特拉算法)

Dijkstra单源最短路径 问题描述 输入n 表示n个结点&#xff0c;m表示m条边&#xff0c;求编号1的结点到每个点的最短路径 输出从第一个点到第n个点的最短路径 思路 将图g[][]中所有的权值初始化为0x3f表示正无穷 将dist[]中所有的值初始化为0x3f表示从第一个点到所有点的距离…

linux的io的知识大全

C语言的io操作 写文件 #include<stdio.h> #include<string.h>#define FILE_NAME "log.txt" int main() {FILE * fp fopen(FILE_NAME, "w");if(fpNULL){printf("fopen error!\n");}const char* msg "hello zk\n";int c…

如何准确测量电源噪声

目录 电源噪声的特点 影响噪声测试的因素 总结 电源噪声的特点 以往电源噪声的幅度规范一般在几十mV&#xff0c;但是随着芯片电源电压的降低&#xff0c;很多芯片的电源噪声的规范已经低至mV的量级&#xff0c;某些对电源噪声敏感的芯片要求甚至到了百uV的量级。 电源上的…

基于Android studio 实现外卖(点)订餐系统-编程乐学最新原创

&#x1f345;文章末尾有获取完整项目源码方式&#x1f345; 目录 一、实现介绍 视频演示 1.1 启动页 1.2登录页 1.3注册页 1.4商家主页 1.5商家发布商品页面 1.6商家我的页面 1.7商家个人信息修改页 1.8商家商品信息修改页 1.9用户首页 1.10用户我的订单页面 1.1…

C++学习进阶:二进制与位运算

目录 1.进制与原反补码 2.位运算 2.1.按位与 2.2.按位或 2.3.异或 2.4.取反 2.5.移位 3.部分面试题 3.1.不创建新的变量&#xff0c;实现两个变量的交换 3.2.求一个整数存储在内存中二进制中1的个数 这一部分本来是C语言的内容&#xff0c;当学习位图时&#xff0c…

期货分账户软件|程序化软件|风控软件|资产管理软件开发用到哪些技术?

期货/股票资管分仓软件分账户系统APP的开发涉及多个技术领域&#xff0c;以确保软件的功能性、安全性和易用性。以下是一些在开发过程中可能需要用到的关键技术&#xff1a; 前端开发技术&#xff1a;前端部分主要负责用户界面的设计和实现。通常使用HTML、CSS和JavaScript等技…

YARN-Client 与 YARN-Cluster 区别

YARN-Client 与 YARN-Cluster 区别 理解YARN-Client和YARN-Cluster深层次的区别之前先清楚一个概念&#xff1a;Application Master。在YARN中&#xff0c;每个Application实例都有一个ApplicationMaster进程&#xff0c;它是Application启动的第一个容器。它负责和ResourceMa…

【HTML】制作一个简单的实时字体时钟

目录 前言 HTML部分 CSS部分 JS部分 效果图 总结 前言 无需多言&#xff0c;本文将详细介绍一段HTML代码&#xff0c;具体内容如下&#xff1a; 开始 首先新建文件夹&#xff0c;创建一个文本文档&#xff0c;两个文件夹&#xff0c;其中HTML的文件名改为[index.html]&am…

Jmeter杂记:测试计划参数详解

测试计划各参数详解 1&#xff0c;用户自定义变量&#xff0c;是全局变量&#xff0c;供所有线程组使用&#xff0c;可用配置元件&#xff1a;用户自定义变量替代 2&#xff0c;连续的运行线程组&#xff0c;默认不勾选&#xff0c;则随机的运行多个线程组中的取样器&#xff…

在隐私计算应用中和数链具备哪些技术特点?

在加速“可信数字化”进程的背景下&#xff0c;我国区块链产业将在打造新型平台经济&#xff0c;开启共享经济新时代的同时&#xff0c;带动数字经济“脱虚向实”服务实体经济。 和数软件在加速数字化进程的同时&#xff0c;进一步服务实体经济&#xff0c;提高实体经济的活力…

VS2019 VS2022 LNK2019 无法解析的外部符号sprintf

解决方案&#xff1a; 项目属性》配置属性》链接接-》输入》附加依赖项&#xff0c;增加 legacy_stdio_definitions.lib legacy_stdio_definitions.lib 是一个库文件&#xff0c;通常与使用 Visual Studio 编译的 C/C 项目相关。它的作用是解决在使用新版本的 Visual Studio 编…

IIS中部署netcore程序出现500错误如何处理?

500错误在IIS部署中经常出现&#xff0c;但是解决非常耗时 官方也有给出一些指引&#xff0c;但是无法解决根本问题 建议检查netcore相关组件是否正确安装&#xff0c;如下&#xff1a; aspnetcore-runtime-3.1.32-win-x64 dotnet-hosting-3.1.32-win dotnet-runtime-3.1.…

两数相加(leetcode)

给你两个 非空 的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只能存储 一位 数字。 请你将两个数相加&#xff0c;并以相同形式返回一个表示和的链表。 你可以假设除了数字 0 之外&#xff0c;这两个数都不会以 0 …

Intel VAAPI/QSV/oneVPL区别简介

一、常用视频加速接口汇总 libmfx就是Intel QSV. 二、VAAPI VAAPI (视频加速API&#xff0c;Video Acceleration API)包含一套开源的库(LibVA) 以及API规范, 用于硬件加速下的视频编解码以及处理&#xff0c;只有Linux上的驱动提供支持。由Intel主导&#xff0c;但是AMD&…

51单片机上面的IIC协议

1、什么是IIC协议 2、模拟IIC协议 51单片机上面是没有与IIC协议相关的寄存器的&#xff08;没有相关的硬件&#xff09;&#xff0c;不像串口可以配置对应的寄存器达到目的&#xff08;比如修改波特率9600 or 115200&#xff09;&#xff0c;要配置IIC只能够根据用户手册里面的…

未来课堂革命:OpenAI 发布 ChatGPT 使用指南,探索生成式 AI 如何重塑教育景观

随着新学期的来临&#xff0c;众多初登教师舞台的 00 后们&#xff0c;也完成了他们的第一个教师身份下的暑期生活。 对于开学的抵触情绪&#xff0c;不仅学生们普遍存在&#xff0c;许多 00 后的新晋教师们也同样感同身受。某种程度上&#xff0c;这些抗拒上班的年轻教师群体…

Java日期正则表达式(附Demo)

目录 前言1. 基本知识2. Demo 前言 对于正则匹配&#xff0c;在项目实战中运用比较广泛 原先写过一版Python相关的&#xff1a;ip和端口号的正则表达式 1. 基本知识 对于日期的正则相对比较简单 以下是一些常见的日期格式及其对应的正则表达式示例&#xff1a; 年-月-日&a…