当前位置: 首页 > news >正文

Java I/O (Input/Output)——文件字节流

  • 博客主页:誓则盟约
  • 系列专栏:Java SE 专栏
  • 关注博主,后期持续更新系列文章
  • 如果有错误感谢请大家批评指出,及时修改
  • 感谢大家点赞👍收藏⭐评论✍ 

Java I/O 简介

        Java I/O(输入/输出)是 Java 程序中用于处理数据输入和输出的重要部分。

输入流(Input Streams):用于从数据源读取数据。常见的输入流包括FileInputStream(从文件读取)、BufferedInputStream(提高读取效率)等。

输出流(Output Streams):用于将数据写入到目的地。例如FileOutputStream(向文件写入)、BufferedOutputStream(提高写入效率)。

字符流(Reader 和 Writer):处理字符数据,更适合处理文本。如FileReaderFileWriter

缓冲流(Buffered Streams):通过缓冲区来减少实际的 I/O 操作次数,提高性能。

对象流(Object Streams):用于实现对象的序列化和反序列化,如ObjectInputStreamObjectOutputStream

        在实际编程中,根据具体的需求选择合适的 I/O 流可以提高程序的效率和可读性。


计算机总线结构:   

        那么为什么会有I/O呢?其实I/O无时无刻不在我们身边,比如读取硬盘上的文件,网络文件的传输,鼠标键盘输入,也可以是接受单片机发回的数据,而能够支持这些操作的设备就是I/O设备。

我们可以大致看一下整个计算机的总线结构

        最核心的是CPU,CPU像计算机的大脑一样,是计算机的核心部件,几乎所有的计算都是靠这个CPU来进行的,CPU懂的比较多,它可以对各种类型进行计算,但是随着时代的发展对图形的要求越来越高,CPU就略显乏力;于是就出现了GPU(显卡),显卡就是专门对于图形进行计算。

        通过北桥芯片连接到内存,这样CPU就可以对内存进行操作;南桥芯片是用于读取U盘或者硬盘内的数据 。

        常见的I/O设备一般是鼠标、键盘这类通过USB进行传输的外设或者是通过Sata接口或是M.2连接的硬盘。一般情况下,这些设备是由CPU发出指令通过南桥芯片间接进行控制,而不是由CPU直接操作。

        而我们在程序中,想要读取这些外部连接的!O设备中的内容,就需要将数据传输到内存中。而需要实现这样的操作,单单凭借一个小的程序是无法做到的,而操作系统(如:Windows/inux/MacOS)就是专门用于控制和管理计算机硬件和软件资源的软件,我们需要读取一个IO设备的内容时,就可以向操作系统发出请求,由操作系统帮助我们来和底层的硬件交互以完成我们的读取/写入请求。

        JDK提供了一套用于IO操作的框架,为了方便我们开发者使用,就定义了一个像水流一样,根据流的传输方向和读取单位,分为字节流InputStream和OutputStream以及字符流Reader和Writer的IO框架,当然,这里的流指的是数据流,通过流,我们就可以一直从流中读取数据,直到读取到尽头,或是不断向其中写入数据,直到我们写入完成,而这类IO就是我们所说的BIO。


文件字节流:

        字节流一次读取一个字节,也就是一个 byte 的大小,而字符流顾名思义,就是一次读取一个字符,也就是一个 char 的大小(在读取纯文本文件的时候更加适合)。

文件输入流:

在 Java 中,文件输入流FileInputStream用于从文件中读取数据。FileInputStream 允许程序以字节为单位读取文件的内容。

创建方式
通常通过指定要读取的文件路径来创建文件输入流对象。例如:

try {FileInputStream fis = new FileInputStream("your_file_path");// 后续的读取操作
} catch (FileNotFoundException e) {e.printStackTrace();
}

        但是这种方式需要处理各种可能的异常,比如 FileNotFoundException 异常和 IOException 异常,并且需要手动关闭文件,完整代码如下:

public class Hello_World {public static void main(String[] args) { // 想读取一个文件  创建一个文件输入流   使用完把流关闭掉 释放掉 closeFileInputStream stream = null;try {stream = new FileInputStream("绝对路径/相对路径");
//            stream.close();} catch (FileNotFoundException e) {throw new RuntimeException(e);} finally {if (stream != null) {try {stream.close();} catch (IOException e) {throw new RuntimeException(e);}}}}
}

        仅仅是取得文件就如此费劲,不合乎常理。所以有了try-with-resources 语句这种简便方式,try-with-resources 语句是一种用于更方便、更安全地管理资源(如输入流、输出流、数据库连接等)的机制。

优点

  1. 自动资源管理:无需显式地调用 close 方法来关闭资源,避免了因忘记关闭资源而导致的资源泄漏问题。
  2. 简洁的代码:减少了样板代码,使代码更简洁、更易读。

语法格式

try (Resource res = new Resource()) {// 使用资源的操作
} catch (Exception e) {// 异常处理
}

        对于以上示例的完整代码转成try-with-resources 语句如下:

public class Hello_World {public static void main(String[] args) {try(FileInputStream inputStream = new FileInputStream("路径")){ // 直接在try()中定义要在完成之后释放的资源} catch (IOException e){ // 这里变成IOException是因为调用close()可能会出现,而FileNotFoundException是继承自IOException的e.printStackTrace();}// 无需再编写finally语句块,因为在最后自动帮我们调用了close()。}
}

        由此可见,try-with-resources 语句极大地提高了资源管理的便利性和可靠性,使代码更加健壮和易于维护。

数据的传递:

        如图所示,在计算机数据由文件向内存进行传递的形式是以二进制01串进行的,一次一个字节,就像水流一样源源不断的传输,直至文件传输结束。

        数据不断传输过来,那我们如何去读取数据呢?

        调用read()方法是必要的,但是read()方法的调用方式也有很多种,这里主要列出来常见的三种。

1.直接读取

       try(FileInputStream inputStream = new FileInputStream("C:\\Users\\Xxy63\\Desktop\\无限弹窗代码.txt")){ // 直接在try()中定义要在完成之后释放的资源int i = inputStream.read();System.out.println((char)i);int x = inputStream.read();  // 当没有内容后,会返回-1System.out.println((char)x);} catch (IOException e){ // 这里变成IOException是因为调用close()可能会出现,而FileNotFoundException是继承自IOException的e.printStackTrace();}// 无需再编写finally语句块,因为在最后自动帮我们调用了close()。

        由于读取数据返回的是int类型的一个数据,所以我们用int i 去接收它,然后利用强制类型转换把i 转为char类型进行输出。调用一次读取一个字符,当读取完之后会返回-1.这样效率较为低下,所以有下面第二种读取方法。

2.循环读取

         由于读取完之后会返回数字-1,所以可以利用这一性质进行while循环进行读取,直到返回-1时结束循环,代码如下:

try(FileInputStream inputStream = new FileInputStream("C:\\Users\\Xxy63\\Desktop\\无限弹窗代码.txt")){ // 直接在try()中定义要在完成之后释放的资源int i;while ((i = inputStream.read()) != -1) {System.out.print((char)i);}} catch (IOException e){ // 这里变成IOException是因为调用close()可能会出现,而FileNotFoundException是继承自IOException的e.printStackTrace();
}// 无需再编写finally语句块,因为在最后自动帮我们调用了close()。

        通过这种方式就可以一次性对文件内的内容全部读取。但是由于不够灵活,可变性较差,所以还可以用下面第三种方法进行读取。

3.区间读取

        区间读取,顾名思义就是定义一个固定长度的区间,将文件内的内容按照这个区间大小进行读取,当文件未读内容小于区间长度时会以小于区间长度的形式进行最后一次读取,若没有元素可读取时,一样会返回-1。具体代码如下:

        try(FileInputStream inputStream = new FileInputStream("C:\\Users\\Xxy63\\Desktop\\无限弹窗代码.txt")){ // 直接在try()中定义要在完成之后释放的资源System.out.println(inputStream.available()); // 获取有多少个数据可读byte [] bytes = new byte[inputStream.available()]; // 一次读x个数据while (inputStream.read(bytes) != -1)   // 当最后不足x个或者已经没有时,会返回少于x个的数据或者-1System.out.println(new String(bytes));} catch (IOException e){ // 这里变成IOException是因为调用close()可能会出现,而FileNotFoundException是继承自IOException的e.printStackTrace();}// 无需再编写finally语句块,因为在最后自动帮我们调用了close()。

        读取过程中可使用available()方法查询可读数量,在上面的案例中,我将区间长度x设置为了可读长度,这样也可以一次性读取完文件内数据。也可以设置其他int类型的x作为长度参数。

        这种方法在文件输出流常用,一个字节一个字节的读取出来并一个字节一个字节的写入另一个文件,相当于文件的拷贝操作。

       跳过操作:skip()方法。给skip(x)传人参数x,可以设置跳过前几个字节进行读取其下一个字节。


文件输出流:

        文件输出流(FileOutputStream)用于将数据写入到文件中。文件输出流允许您以字节为单位向文件写入数据。

        在写入之前您需要提供要写入的文件的路径和名称。如果文件不存在,它将被创建;如果文件已存在,默认情况下,新写入的数据会覆盖原有的内容。

   try {FileOutputStream fos = new FileOutputStream("your_file.txt");} catch (IOException e) {e.printStackTrace();}

  stream.flush()方法的主要作用是将输出流缓冲区中的数据强制刷新并输出。通常,当我们使用输出流(如 FileOutputStream 、BufferedOutputStream 等)写入数据时,数据并不是立即被发送到目的地(如文件),而是先被存储在缓冲区中。缓冲区的目的是减少实际的 I/O 操作次数,从而提高性能。

        然而,在某些情况下,我们希望确保数据能够立即被发送出去,而不是等到缓冲区填满或者输出流被关闭。这时就可以使用 flush 方法。  

        默认情况下(append的参数默认是false),写入的内容会直接取代原文件内的内容,即覆盖掉。代码如下:

public class Hello_World {public static void main(String[] args) {try(FileOutputStream stream = new FileOutputStream("C:\\Users\\Xxy63\\Desktop\\无限弹窗代码.txt")){stream.write("Hello World".getBytes());  // 直接取代原内容stream.flush();}catch (IOException e){e.printStackTrace();}}
}

        如果想接着文件的内容往后继续写(追加模式),那么只需要把append的参数改为true即可,代码如下:

public class Hello_World {public static void main(String[] args) {try(FileOutputStream stream = new FileOutputStream("C:\\Users\\Xxy63\\Desktop\\无限弹窗代码.txt",true)){ // 加上true 变成追加模式stream.write("Hello World".getBytes());  // 直接取代原内容stream.flush();}catch (IOException e){e.printStackTrace();}}
}

        至此,我们就完成了输出流操作,那么,就可以结合输入流和输出流进行拷贝操作了。

文件的拷贝:

        文件拷贝是将一个文件的内容完整地复制到另一个文件的操作。相关的类有:

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

        文件的拷贝操作一般使用读取数据的第三种方法,区间读取。因为这种方法可以设置足够大的区间,读取速度较快,不需要一个字节一个字节的去读取。下面是两个拷贝的示例代码:

// 文件拷贝+进度条
public class Hello_World {public static void main(String[] args) {File file = new File("C:\\Users\\Xxy63\\Desktop\\文章.md");try(FileInputStream in = new FileInputStream(file);FileOutputStream out = new FileOutputStream("XXX.txt")){byte [] bytes = new byte[400];int len;long total = file.length() , sum = 0;while ((len = in.read(bytes))!=-1){out.write(bytes, 0, len);sum += len;System.out.println("文件已拷贝" + (sum*100/total) + '%');}}catch (IOException e){e.printStackTrace();}}
}
public class Hello_World {public static void main(String[] args) {try(FileInputStream in = new FileInputStream("C:\\Users\\Xxy63\\Desktop\\无限弹窗代码.txt");FileOutputStream out = new FileOutputStream("C:\\Users\\Xxy63\\Desktop\\copy.txt")){byte[] bytes = new byte[1024];int len;while ((len = in.read(bytes)) != -1) {out.write(bytes, 0, len);} // 拷贝速度大大提升}catch (IOException  e){e.printStackTrace();}}
}

        在上述代码中,通过创建输入流 FileInputStream 从源文件读取数据,创建输出流 FileOutputStream 向目标文件写入数据。使用一个缓冲区来提高拷贝效率,每次读取一定数量的字节到缓冲区,然后将缓冲区中的数据写入目标文件,直到读取完源文件的所有内容。

文件拷贝在很多场景中都很有用,比如:

  • 数据备份:将重要文件复制一份以防止数据丢失。
  • 共享文件:将文件拷贝到多个位置以便不同的程序或用户使用。

        例如,如果您有一个包含重要配置信息的文件,为了安全起见,可以定期进行备份拷贝。又或者在一个文件处理系统中,需要将原始文件拷贝到多个不同的目录下以供不同的模块处理。


 “且将新火试新茶,诗酒趁年华。”——《望江南·超然台作》

相关文章:

Java I/O (Input/Output)——文件字节流

博客主页:誓则盟约系列专栏:Java SE 专栏关注博主,后期持续更新系列文章如果有错误感谢请大家批评指出,及时修改感谢大家点赞👍收藏⭐评论✍ Java I/O 简介 Java I/O(输入/输出)是 Java 程序中…...

VisionPro二次开发学习笔记4-使用C#创建绘图图形

VisionPro提供了许多可以添加到CogDisplay的基本形状,例如CogCircle,CogRectangle,CogEllipse和CogRectangleAffine。这些形状可以是用户可以用鼠标操作的交互式图形,也可以是用户无法更改的静态形状。 若要在CogDisplay控件上绘…...

【langchain学习】使用JsonOutputParser让大模型生成结构化JSON数据

使用Langchain处理结构化数据,以JsonOutputParser为例。以下是具体步骤和代码示例: 导入所需库: from config import llm from langchain_core.output_parsers import JsonOutputParser from langchain_core.prompts import PromptTemplate f…...

【学习笔记】Matlab和python双语言的学习(最大最小化规划)

文章目录 前言一、最大最小化规划二、选址问题三、代码实现----Matlab1.Matlab 的 fminimax 函数2.Matlab 代码 四、代码实现----python总结 前言 通过模型算法,熟练对Matlab和python的应用。 学习视频链接: https://www.bilibili.com/video/BV1EK41187…...

基于SpringBoot的Redis开发实战教程

配置和集成缓存涉及多个步骤,从选择适当的缓存技术到实现缓存的存取操作。以下是具体的步骤和示例,假设我们使用Redis作为缓存工具,并基于Spring Boot进行开发。 1. 选择和配置缓存技术 a. 选择缓存工具 Redis 是一个流行的内存数据结构存…...

mysql 分区操作

1。新建分区 mysql 没有全局唯一索引,因此所有涉及唯一索引的都需要加上分区键,因此要做好权衡,键分区不一定能提高效率哦,建分区的主要目的是为了分区查询和删除数据 --将CREATE_TIME 加入主键 ALTER TABLE your_table DROP PR…...

[网鼎杯 2018]Comment

使用环境为https://adworld.xctf.org.cn/challenges,搜索题目[网鼎杯 2018]Comment。 进入环境,发现为一个留言板,点击发帖试试。 尝试发帖 跳转到登录页面,根据提示使用burp进行暴力破解。 发现payload为666时状态码不同。 尝试…...

LVS详解

目录 一、LVS简介 LVS 官网: 二、LVS 负载均衡模式 2.1 LVS-NAT模式: 2.1.1 简介 2.1.2 工作流程图: 2.1.3 说明: 2.1.4 LVS-NAT的优缺点: 2.2 LVS-DR模式: 2.2.1 简介 2.2.2 工作原理: 2.2.3 工作…...

Yolo-World初步使用

Yolo v8目前已经支持Yolo-World,整理一下初步使用步骤。 使用步骤 1 先下载Yolo-World的pt文件,下载地址:GitHub - AILab-CVC/YOLO-World: [CVPR 2024] Real-Time Open-Vocabulary Object Detection 官网应该是点这里(有个笑脸…...

Navicat Premium使用

文章目录 Navicat Premium 16的使用连接MySQL建立数据库并构建表导入数据 Navicat Premium 16是一款功能强大的数据库管理工具,它允许用户从单一应用程序中同时连接多种数据库,提供了极其便捷和高效的管理和开发环境,对于 MySQL 用户来说&…...

LLC数字控制TMS320F28034,4-DSP的epwm配置介绍

LLC数字控制TMS320F28034,4-DSP的epwm配置介绍 1 TMS320F280341.1 概述1.2 PWM详细介绍 2 TMS320F28034 PWM功能框图2.1 ePWM功能模块2.2 ePWM功能寄存器框图 3 TMS320F28034 PWM初始化流程4 结合项目设计5 代码设计5.1 PWM初始化程序5.2 工程代码 6 总结 配套代码示…...

MongoDB学习记录

1、初识Mongo 概述:与关系型数据库不同,MongoDB 的数据以类似于 JSON 格式的二进制文档存储,通常称这种格式为Bson,Bson不仅支持JSON中已有的数据类型,还增加了一些额外的数据类型,例如日期和二进制数据&a…...

vlunstack-2(复现红日安全-ATT CK实战)

环境搭建 配置信息 DC IP:10.10.10.10 OS:Windows 2012(64) 应用:AD域 WEB IP1:10.10.10.80 IP2:192.168.47.131 OS:Windows 2008(64) 应用:Weblogic 10.3.6MSSQL 2008 PC IP1:10.10…...

【生信入门】预览快速体验Linux-重生之小明闯Linux

生信少走弯路,快试试生信云专用服务器。新用户注册免费体验5小时。https://www.tebteb.cc 一.故事 小明的Linux冒险 在一片混沌的黑暗中,小明睁开了眼睛。他感到头痛欲裂,四周一片漆黑,只有一行闪烁的字符映入眼帘: [xiaomingu…...

用.net core简易搭建webapi托管到IIS

1、从官网下载.NET Core 托管捆绑包 https://learn.microsoft.com/zh-cn/aspnet/core/tutorials/publish-to-iis?viewaspnetcore-8.0&tabsvisual-studio 2、新建ASP.NET Core WEB API项目 新建控制器TestController并生成GetInfo方法 3、发布 目标路径选择 2)显示所有…...

【计算机网络---OSI七层模型】

一、OSI的基本概念及原则 OSI是Open System Interconnect的缩写,意为开放式系统互联。各个层次的划分遵循以下原则: 1. 同一层的各网络节点都有相同的层次结构,具有同样的功能; 2. 同一节点的内相邻层之间通过接口进行通信&…...

Error updating database. Cause: org.apache.shiro.UnavailableSecurity

mybtisplus查看MetaObjectHandler是否有自定义获取用户信息填充用户的方法...

【网络安全】本地文件包含及远程文件包含漏洞详解

一、文件包含漏洞概述 1.1 什么是文件包含 开发人员将需要重复调用的函数写入一个文件,对该文件进行包含时产生的操作。这样编写代码能减少冗余,降低代码后期维护难度。 保证网站整体风格统一:导航栏、底部footer栏等,把这些不…...

redis启动的三种方式

默认启动: # 默认的启动指令 redis-server 默认启动属于前台启动,会阻塞整个会话窗口,窗口关闭或者按下CTRL C则Redis停止。不推荐使用。 //查看云服务器是否安装过redis redis-server -v//检查安装目录 which redis-server//查看redis进…...

手机怎么远程控制电脑屏幕?手机远程控制电脑方法分享

手机与电脑之间的互联互通变得越来越便捷。 无论是工作还是学习,有时我们需要在手机上远程控制电脑屏幕,以完成一些复杂的操作或查看电脑上的文件。 本文将详细介绍几种实用的手机远程控制电脑屏幕的方法,帮助读者轻松实现这一目标。 一、使…...

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑:陈萍萍的公主一点人工一点智能 未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战,在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...

大数据学习栈记——Neo4j的安装与使用

本文介绍图数据库Neofj的安装与使用,操作系统:Ubuntu24.04,Neofj版本:2025.04.0。 Apt安装 Neofj可以进行官网安装:Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...

Day131 | 灵神 | 回溯算法 | 子集型 子集

Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)

概述 在 Swift 开发语言中,各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过,在涉及到多个子类派生于基类进行多态模拟的场景下,…...

Objective-C常用命名规范总结

【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名(Class Name)2.协议名(Protocol Name)3.方法名(Method Name)4.属性名(Property Name)5.局部变量/实例变量(Local / Instance Variables&…...

1688商品列表API与其他数据源的对接思路

将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案

随着新能源汽车的快速普及,充电桩作为核心配套设施,其安全性与可靠性备受关注。然而,在高温、高负荷运行环境下,充电桩的散热问题与消防安全隐患日益凸显,成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

Ascend NPU上适配Step-Audio模型

1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统,支持多语言对话(如 中文,英文,日语),语音情感(如 开心,悲伤)&#x…...

ABAP设计模式之---“简单设计原则(Simple Design)”

“Simple Design”(简单设计)是软件开发中的一个重要理念,倡导以最简单的方式实现软件功能,以确保代码清晰易懂、易维护,并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计,遵循“让事情保…...