JavaEE 初阶篇-深入了解 I/O 流(FileInputStream 与 FileOutputStream 、Reader 与 Writer)

🔥博客主页: 【小扳_-CSDN博客】
❤感谢大家点赞👍收藏⭐评论✍
 

文章目录

        1.0 I/O 流概述

        2.0 文件字节输入流(FileInputStream)

        2.1 创建 FileInputStream 对象

        2.2 读取数据

        2.3 关闭流

        3.0 文件字节输出流(FileOutputStream)

        3.1 创建 FileOutputSrteam 对象

        3.2 写入数据

        3.3 写入字节数组

        3.3 关闭流

        4.0 用字节输入流与字节输出流来实现文件复制

        5.0 释放资源的方式

        6.0 文件字符输入流(FileReader)

        6.1 创建 FileReader 对象

        6.2 读取字符

        6.3 读取字符数组

        7.0 文件字符输出流(FileWriter)

        7.1 创建 FileWriter 对象

        7.2 写入字符


        1.0 I/O 流概述

        I/O 流是 Java 中用于处理输入和输出的机制,它提供了一种统一的方式来处理不同来源和目的地的数据。在 Java 中,I/O 流主要用于与文件、网络、内存等进行数据的读取和写入操作。

        I 指 Input,称为输入流:负责把数据读到内存中。

        O 指 Output,称为输出流:负责把数据从内存中写到磁盘或者网络等等。

        I/O 流可以分为字节流和字符流两种类型。字节流以字节为单位读写数据,适用于处理二进制文件或字节数据;字符流以字符为单位读写数据,适用于处理文本文件或字符数据。

        2.0 文件字节输入流(FileInputStream)

        FileInputStream 是 Java 中用于从文件中读取字节数据的输入流类。它继承 InputStream 类,提供了一些方法来读取文件中的字节数据。

        2.1 创建 FileInputStream 对象

        可以使用 FileInputStream 的构造函数来创建对象,需要传入要读取的文件路径或者文件对象作为参数。

代码如下:

FileInputStream fis = new FileInputStream("path/to/file.txt");

         简单来说,创建了 FileInputStream 对象相当于创建了连通文件与内存之间的管道,进行字节流的流通。但是,该管道只能从文件流到内存中。

        2.2 读取数据

        FileInputStream 提供了 read() 方法来读取文件中的字节数据。每次调用 read() 方法会读取一个字节,并返回读取的字节数据(以 int 类型表示,范围为 0 到 255),如果已到达文件末尾,则返回 -1。

举个例子:

        

        将该文件中的内容读取到内存中。 

代码如下:

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

public class demo1 {
    public static void main(String[] args) throws IOException {
        InputStream inputStream = new FileInputStream("D:\\software\\code\\2023_java\\2023_java_code\\code_24_4_21\\src\\MyFile\\MyText.text");
        //每次读取一个字节
        int n;
        //直到返回-1,就意味这已经将全部内容读取完毕了
        while ( (n = inputStream.read()) != -1 ){
            //因为读取出来的是字节,读出来的都是整数,那么可以将其转换为字符
            System.out.print((char) n);
        }

        //关闭资源
        inputStream.close();
    }
}

运行结果:

        除了单个字节的读取, FileInputStream 还提供了 read(byte[] b) 方法来一次性读取多个字节到指定的字节数组中,其中返回值为读取的字节个数。

        简单来说,可以将 b 数组当作成一个容器,那么 b 数组一下子可以从文件中装指定大小个字节,并且返回 b 容器中装了多少了字节,一旦返回值为 -1 ,则代表已经将文件中的内容读取完毕了。

        该方法的效率远比一个一个字节读取到内存中的方法高效很多。

代码如下:

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

public class demo2 {
    public static void main(String[] args) throws IOException {
        InputStream inputStream = new FileInputStream("D:\\software\\code\\2023_java\\2023_java_code\\code_24_4_21\\src\\MyFile\\MyText.text");

        //指定容器大小为 1024 个字节(1kb)
        byte[] b = new byte[1024];
        int n ;
        while ((n = inputStream.read(b)) != -1){
            //为了更好的观察,转换成字符串,不可能每一次都恰好可以装满1kb,只解析 0 到 n 个字节。
            String s = new String(b,0,n);
            System.out.println(s);
        }

        //关闭流
        inputStream.close();
    }
}

运行结果:

注意事项:

        1)使用 FileInputStream 每次读取一个字节,读取性能较差,并且读取汉字输出会乱码。

        2)使用 FileInputStream 每次读取多个字节,读取性能得到提升,但读取汉字输出还是会乱码。

使用字节流读取中文,如何保证输出不乱码,怎么解决?

        定义一个与文件一样大小的字节数组,一次性读取完文件的全部字节。

代码如下:

import java.io.*;

public class demo3 {
    public static void main(String[] args) throws IOException {
        File file = new File("D:\\software\\code\\2023_java\\2023_java_code\\code_24_4_21\\src\\MyFile\\MyText.text");
        InputStream inputStream = new FileInputStream(file);
        byte[] b = new byte[(int)file.length()];
        inputStream.read(b);
        String s = new String(b);
        System.out.println(s);

        inputStream.close();
    }
}

运行结果:

        此外官方也提供了相对应的方法 readAllBytes()

代码如下:

import java.io.*;

public class demo4 {
    public static void main(String[] args) throws IOException {
        File file = new File("D:\\software\\code\\2023_java\\2023_java_code\\code_24_4_21\\src\\MyFile\\MyText.text");
        InputStream inputStream = new FileInputStream(file);
        byte[] b = inputStream.readAllBytes();
        String s = new String(b);
        System.out.println(s);
    }
}

        效果是跟自己实现的代码时相同的。

运行结果:

直接把文件数据全部读取到一个字节数组可以避免乱码,是否存在问题?

        如果文件过大,创建的字节数组也会过大,可能引起内存溢出。

        无论用官方实现的代码还是自己实现的代码,面对文件中的内容较大的时候,用该方法就很不现实了,因为磁盘肯定比内存空间大很多。读取文本内容更适合用字符流。而字节流适合坐数据的转移,如:文件复制等。

        2.3 关闭流

        在读取完文件数据后,应该及时关闭 FileInputStream 对象以释放资源。可以使用 close() 方法来关闭流。

        以上代码已经出现过了。

fis.close();

        3.0 文件字节输出流(FileOutputStream)

        FileOutputStream 是 Java 中用于向文件中写入字节数据的输出流类。它继承 OutputStream类,提供了一些方法来向文件中写入字节数据。

        3.1 创建 FileOutputSrteam 对象

        可以使用 FileOutStream 的构造函数来创建对象,需要存入要写入的文件路径作为参数。如果文件不存在,会自动创建新文件;如果文件已存在,会覆盖原有内容,也可以给构造器中再传入一个参数 true ,以支持继续追加,不会覆盖原有的内容。

代码如下:

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

public class demo5 {
    public static void main(String[] args) throws FileNotFoundException {
        OutputStream outputStream = new FileOutputStream("D:\\software\\code\\2023_java\\2023_java_code\\code_24_4_21\\src\\MyFile\\MyText.text");
        
    }
}

        简单来说:创建 FileOutputStream 对象相当于创建了连接内存与文件的通道,只是该通道只能将字节流从内存流到文件中。

        3.2 写入数据

        FileOutputStrea 提供了 write(int b) 方法来向文件中写入一个字节数据。可以将一个整数作为参数传递,只会取低 8 位字节写入文件。

代码如下:

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

public class demo5 {
    public static void main(String[] args) throws IOException {
        OutputStream outputStream = new FileOutputStream("D:\\software\\code\\2023_java\\2023_java_code\\code_24_4_21\\src\\MyFile\\MyText.text");
        outputStream.write(97);
        outputStream.write(98);
        outputStream.write(99);
        outputStream.write(100);
        outputStream.write(101);
        outputStream.write(102);
        outputStream.write(103);
        outputStream.write(104);
        
        outputStream.close();
    }
}

运行结果:

        3.3 写入字节数组

        除了单个字节的写入,FileOutputStream 还提供了 write(byte[] b) 方法来一次性写入整个字节数组中的数据。

代码如下:

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

public class demo6 {
    public static void main(String[] args) throws IOException {
        OutputStream outputStream = new FileOutputStream("D:\\software\\code\\2023_java\\2023_java_code\\code_24_4_21\\src\\MyFile\\MyText.text");

        String str = "土豆土豆我是地瓜";
        outputStream.write(str.getBytes());

        outputStream.close();
    }
}

运行结果:

        如果不想覆盖原有的内容,那么在构造 FileOutputSrteam 对象的时候,构造方法再传入一个参数 true ,代表允许追加内容。

代码如下:

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

public class demo6 {
    public static void main(String[] args) throws IOException {
        OutputStream outputStream = new FileOutputStream("D:\\software\\code\\2023_java\\2023_java_code\\code_24_4_21\\src\\MyFile\\MyText.text",true);

        String str = "土豆土豆我是地瓜";
        outputStream.write(str.getBytes());

        outputStream.close();
    }
}

运行结果:

        再次强调,是以一个字节输出或者输出字节数组到文件中。

        3.3 关闭流

        在读取完文件数据后,应该及时关闭 FileOutputStream 对象以释放资源。可以使用 close() 方法来关闭流。

        以上代码已经出现过了。

fis.close();

        4.0 用字节输入流与字节输出流来实现文件复制

        思路:先将要读取的文件创建通道,将文件中字节流流到内存中,再将内存中的字节流流到指定的文件中。即创建文件 ==> 读取数据 ==> 写入数据 。

代码如下:

import java.io.*;

public class demo7 {
    public static void main(String[] args) throws Exception {
        copy("D:\\照片\\201651723362635996.jpg","D:\\software\\aaa.jpg");
    }
    public static void copy(String path, String obj) throws Exception {
        if (path == null || obj == null){
            return;
        }
        InputStream inputStream = new FileInputStream(path);
        OutputStream outputStream = new FileOutputStream(obj);

        byte[] b = new byte[3];
        int n;
        while ((n = inputStream.read(b)) != -1){
            outputStream.write(b,0,n);

        }

        outputStream.close();
        inputStream.close();
    }
}

运行结果:

字节流非常适合做一切文件的复制操作:

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

        5.0 释放资源的方式

        在 Java 中释放资源通常是指关闭文件流、数据库连接、网络连接等资源,以避免资源泄露和浪费。以下是几种常见的释放资源的方式:

        1)使用 try-with-resources:Java 7 引入了 try-with-resources 语句,可以自动关闭实现了 AutoCloseable 接口的资源。在 try-with-resources 语句中创建的资源会在代码块执行完毕后自动关闭,无需手动调用 close() 方法。

try (FileInputStream fis = new FileInputStream("file.txt")) {
    // 读取文件内容
} catch (IOException e) {
    // 异常处理
}

        2)手动关闭资源:如果无法使用 try-with-resources,需要手动关闭资源。在不再需要资源时,通过调用资源的 close() 方法来关闭资源。

FileInputStream fis = null;
try {
    fis = new FileInputStream("file.txt");
    // 读取文件内容
} catch (IOException e) {
    // 异常处理
} finally {
    if (fis != null) {
        try {
            fis.close();
        } catch (IOException e) {
            // 异常处理
        }
    }
}

        6.0 文件字符输入流(FileReader)

        FileReader 是 Java 中用于读取字符数据的输入流,继承自 Reader 类。FileReader 可以用来读取文本文件中的字符数据。

        6.1 创建 FileReader 对象

        使用 FileReader,首先需要创建 FileReader 对象并指定要读取的文件路径或者文件对象。

代码如下:

FileReader fr = new FileReader("file.txt");

        6.2 读取字符

        FileReader 提供了 read() 方法来读取单个字符。它会返回一个整数,表示读取的字符的 Unicode 编码。读取到文件末尾时返回 -1。

代码如下:

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

public class demo8 {
    public static void main(String[] args) {
        try (Reader reader = new FileReader("D:\\software\\code\\2023_java\\2023_java_code\\code_24_4_21\\src\\MyFile\\MyText.text");){
            int n;
            while ((n = reader.read()) != -1){
                System.out.print((char) n);
            }
        }catch (IOException e){
            e.printStackTrace();
        }

    }
}

运行结果:

        6.3 读取字符数组

        FileReader 还提供了 read(char[] cbuf )方法来一次性读取多个字符,并将其存储到字符数组中。读取到文件末尾时返回 -1。返回值是读取的字符个数。

代码如下:

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

public class demo9 {
    public static void main(String[] args) {
        try (Reader reader = new FileReader("D:\\software\\code\\2023_java\\2023_java_code\\code_24_4_21\\src\\MyFile\\MyText.text")){
            char[] chars = new char[3];
            int n;
            while ((n = reader.read(chars)) != -1){
                String s = new String(chars,0,n);
                System.out.print(s);
            }
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

运行结果:

        7.0 文件字符输出流(FileWriter)

        FileWriter 是 Java 中用于写入字符数据的输出流,继承自 Writer 类。FileWriter 可以用来向文件中写入字符数据。

        7.1 创建 FileWriter 对象

        要使用 FileWriter ,首先需要创建 FileWriter 对象并指定要写入的文件路径或者文件对象。可以指定是否追加数据到文件末尾。

代码如下:

FileWriter fw = new FileWriter("file.txt");

        简答来说,创建 FileWriter 对象相当于创建连接了内存与文件的通道,只是该通道只能将字符流从内存流到文件中。

        7.2 写入字符

        FileWriter 提供了 write(int c) 方法来写入单个字符,以及 write(String str) 方法来写入字符串,还可以写入字符数组。

代码如下:

public class demo10 {
    public static void main(String[] args) {
        try (Writer writer = new FileWriter("D:\\software\\code\\2023_java\\2023_java_code\\code_24_4_21\\src\\MyFile\\MyText.text")){
            writer.write(97);
            //换行
            writer.write("\r\n");
            writer.write("土豆土豆我是地瓜");
            //换行
            writer.write("\r\n");
            writer.write('c');

            //换行
            writer.write("\r\n");
            String s = "地瓜地瓜我是土豆";
            writer.write(s.toCharArray());

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

运行结果:

注意事项:

        字符输出流写出数据后,必须刷新流,或者关闭流,写出去的数据才能生效。

        写出数据时,数据会先被写入到内存缓冲区中,而不是直接写入到文件中。这是为了提高写入效率,减少频繁地访问磁盘的开销。

        因此,为了确保写出去的数据能够及时生效,你可以选择调用 flush() 方法来刷新缓冲区,或者调用 close() 方法来关闭流。这样可以保证数据被写入到文件中,而不会遗失或被丢弃。

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

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

相关文章

代码随想录第42天|416. 分割等和子集

416. 分割等和子集 416. 分割等和子集 - 力扣(LeetCode) 代码随想录 (programmercarl.com) 动态规划之背包问题,这个包能装满吗?| LeetCode:416.分割等和子集_哔哩哔哩_bilibili 给你一个 只包含正整数 的 非空 数组…

知识加油站:数字阅览室全天候满足师生阅读需求

在知识经济时代,阅读已成为获取信息、提升素养、拓宽视野的重要途径。但在传统知识的海洋里,每一本书都是一座孤岛,每一个思想是一股潮流。传统的纸质阅读已经无法完全满足现代人快速、便捷、多样化的学习和阅读需求。因此,数字阅…

C++ 右值引用

1.左值引用和右值引用的概念 什么是左值?什么是左值引用? 左值是一个表示数据的表达式(如变量名或解引用的指针),我们可以获取它的地址可以对它赋值,左值可以出现赋值符号的左边,右值不能出现在赋值符号左边。定义时co…

查看上一次错误的方法$err,hr,到底是什么意思

在《windows核心编程》或者《windows via C/C》一书中&#xff0c;提到过查看函数错误的方法&#xff0c;可以在watch窗口中输入"$err,hr"&#xff0c;来显示。比如下面一个程序 #include <Windows.h> int APIENTRY wWinMain(_In_ HINSTANCE hInstance,_In_op…

FPGA - ZYNQ Cache一致性问题

什么是Cache&#xff1f; Cache是一种用来提高计算机运行速度的一种技术。它是一种小而快的存储设备&#xff0c;位于CPU与内存之间&#xff0c;用于平衡高速设备与低速设备之间的速度差异。Cache可以存储常用的数据或指令&#xff0c;以便CPU更快地获取&#xff0c;从而减少对…

基于肿瘤相关成纤维细胞的前列腺癌患者分层研究(多组学)

Integrating single-cell and bulk RNA sequencing data unveils antigen presentation and process-related CAFS and establishes a predictive signature in prostate cancer https://pubmed.ncbi.nlm.nih.gov/38221616/#full-view-affiliation-3 文章思路学习&#xff1a…

YOLOv9改进策略 | SPPF篇 | 利用RT-DETR的AIFI模块替换SPPFELAN助力小目标检测涨点

一、本文介绍 本文给大家带来是用最新的RT-DETR模型中的AIFI模块来替换YOLOv9中的SPPFELAN。RT-DETR号称是打败YOLO的检测模型&#xff0c;其作为一种基于Transformer的检测方法&#xff0c;相较于传统的基于卷积的检测方法&#xff0c;提供了更为全面和深入的特征理解&#x…

如何30天快速掌握键盘盲打

失业后在家备考公务员&#xff0c;发现了自己不正确的打字方式&#xff0c;决定每天抽出一点时间练习打字。在抖音上看到一些高手的飞速盲打键盘后&#xff0c;觉得使用正确的指法打字是很必要的。 练习打字&#xff0c;掌握正确的键盘指法十分关键。 练习打字的第一步是找到…

基本的SELECT语句及DESC显示表结构

1. SELECT ... 例 : 2. SELECT ... FROM ... (1). SELECT ... : 标识选择哪些列. (2). FROM ... : 标识从哪个表中选取. (3). *通配符 : 选择表中全部列. 例 : 3.列的别名 (1). 空一格. (2). 在列和别名间加入关键字AS. (3). 别名可以使用双引号&#xff0c;以便于在…

【Datawhale LLM学习笔记】一、什么是大型语言模型(LLM)

文章目录 1. 什么是大模型2. 检索增强生成 RAG一、什么是 RAG二、RAG 的工作流程 3. langChain介绍一、什么是 LangChain二、LangChain 的核心组件 4. 开发 LLM 应用的整体流程一、何为大模型开发二、大模型开发的一般流程三、搭建 LLM 项目的流程简析&#xff08;以知识库助手…

从迷宫问题理解dfs

文章目录 迷宫问题打印路径1思路定义一个结构体要保存所走的路径&#xff0c;就需要使用到栈遍历所有的可能性核心代码 部分函数递归图源代码 迷宫问题返回最短路径这里的思想同上面类似。源代码 迷宫问题打印路径1 定义一个二维数组 N*M &#xff0c;如 5 5 数组下所示&…

掌握Node Version Manager(nvm):跨平台Node.js版本管理

&#x1f31f; 前言 欢迎来到我的技术小宇宙&#xff01;&#x1f30c; 这里不仅是我记录技术点滴的后花园&#xff0c;也是我分享学习心得和项目经验的乐园。&#x1f4da; 无论你是技术小白还是资深大牛&#xff0c;这里总有一些内容能触动你的好奇心。&#x1f50d; &#x…

整合阿里云短信服务

1. 申请服务 如图&#xff1a; 申请签名管理和模板管理 2. 进入快速学习和调试 2.1 进入快速学习 2.2 获取依赖和代码实现 3. 具体实现案例 3.1 添加依赖 <dependency><groupId>com.aliyun</groupId><artifactId>dysmsapi20170525</artifact…

9.MMD 基础内容总结及制作成品流程

前期准备 1. 导入场景和模型 在左上角菜单栏&#xff0c;显示里将编辑模型时保持相机和光照勾选上&#xff0c;有助于后期调色 将抗锯齿和各向异性过滤勾掉&#xff0c;可以节省资源&#xff0c;避免bug 在分辨率设定窗口&#xff0c;可以调整分辨率 3840x2160 4k分辨率 1…

Umi.js:登录之后需要手动刷新权限菜单才能渲染

在使用Umi.js开发后台管理页面时&#xff0c;用户登录之后&#xff0c;总是需要手动刷新一次页面&#xff0c;才能够拿到全局状态/权限信息。 问题描述 结合使用umi/plugin-layout和umi/plugin-access&#xff0c;登录进入页面&#xff0c;配置的权限菜单未渲染&#xff0c;需…

【Redis 神秘大陆】005 常见性能优化方式

五、Redis 性能优化 5.1 系统层面的优化 https://github.com/sohutv/cachecloud/blob/main/redis-ecs/script/cachecloud-init.sh initConfig() {# 支持虚拟内存分配sysctl vm.overcommit_memory1# 最大排队连接数设置为 511&#xff0c;一般默认是 128echo 511 >/proc/sy…

openobserve-filebeat配置

优势 rustgolang开发的日志工具组合&#xff0c;自带日志数据存储&#xff0c;简化部署和管理。日志数据可配置保留x天。从日志文件中采集&#xff0c;做到非侵入式日志集中管理。 可从日志内容中提取信息进行报警等二次开发。 下载 openobserve-v0.10.1-windows-amd64 fil…

【题解】NC40链表相加(二)(链表 + 高精度加法)

https://www.nowcoder.com/practice/c56f6c70fb3f4849bc56e33ff2a50b6b?tpId196&tqId37147&ru/exam/oj class Solution {public:// 逆序链表ListNode* reverse(ListNode* head) {// 创建一个新节点作为逆序后链表的头节点ListNode* newHead new ListNode(0);// 当前…

使用51单片机控制T0和T1分别间隔1秒2秒亮灭逻辑

#include <reg51.h>sbit LED1 P1^0; // 设置LED1灯的接口 sbit LED2 P1^1; // 设置LED2灯的接口unsigned int cnt1 0; // 设置LED1灯的定时器溢出次数 unsigned int cnt2 0; // 设置LED2灯的定时器溢出次数// 定时器T0 void Init_Timer0() {TMOD | 0x01;; // 定时器…

代码学习记录49---单调栈

随想录日记part49 t i m e &#xff1a; time&#xff1a; time&#xff1a; 2024.04.20 主要内容&#xff1a;今天开始要学习单调栈的相关知识了&#xff0c;今天的内容主要涉及&#xff1a;柱状图中最大的矩形 84.柱状图中最大的矩形 Topic184.柱状图中最大的矩形 题目&…