Java 入门指南:Java IO流 —— 字节流

何为Java流

Java 中的流(Stream) 是用于在程序中读取或写入数据的抽象概念。流可以从不同的数据源(输入流)读取数据,也可以将数据写入到不同的目标(输出流)。流提供了一种统一的方式来处理不同类型的数据,例如文件、网络数据、内存数据等。

Java IO 流

在 Java 中,流分为输入流(InputStream)输出流(OutputStream)。输入流用于从数据源读取数据,而输出流用于将数据写入到目标

IO 即 Input/Output,输入和输出。数据输入到计算机内存的过程即输入,反之输出到外部存储(比如数据库,文件,远程主机)的过程即输出。数据传输过程类似于水流,因此称为 IO 流。IO 流在 Java 中分为输入流和输出流,而根据数据的处理方式又分为字节流和字符流

如果音频文件、图片等媒体文件用字节流比较好,如果涉及到字符的话使用字符流比较好。

Java IO 流的 40 多个类都是从如下 4 个抽象类基类中派生出来的

  • InputStream/Reader: 所有的输入流的基类,前者是字节输入流,后者是字符输入流

  • OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输出流

字节操作

Java提供了两个抽象类来表示字节流输入输出:InputStreamOutputStream,二者不能直接实例化,通过其子类来创建实例

字节流 (Byte Stream)

字节流以字节为单位进行输入和输出的操作,主要用于处理二进制数据。它以字节为单位进行读取和写入操作,适用于处理二进制文件、图片、音频、视频等非文本数据。

InputStream 字节输入流

InputStream是所有字节输入流类的超类,它定义了读取字节的基本方法
用于从源头(通常是文件)读取数据(字节信息)到内存中

常用方法

InputStream 常用方法:

  • read():返回输入流中下一个字节的数据。返回的值介于 0 到 255 之间。如果未读取任何字节,则代码返回 -1 ,表示文件结束。

  • read(byte b[ ]) : 从输入流中读取一些字节存储到数组 b 中。如果数组 b 的长度为零,则不读取。如果没有可用字节读取,返回 -1
    如果有可用字节读取,则最多读取的字节数最多等于 b.length , 返回读取的字节数。这个方法等价于 read(b, 0, b.length)

  • read(byte b[], int off, int len):在 read(byte b[ ]) 方法的基础上增加了 off 参数(偏移量)和 len 参数(要读取的最大字节数)。

  • skip(long n):忽略输入流中的 n 个字节 ,返回实际忽略的字节数。

  • available():返回输入流中可以读取的字节数。

  • close():关闭输入流释放相关的系统资源。

从 Java 9 开始,InputStream 新增加了多个实用的方法:

  • readAllBytes():读取输入流中的所有字节,返回字节数组。

  • readNBytes(byte[] b, int off, int len):阻塞直到读取 len 个字节。

  • transferTo(OutputStream out):将所有字节从一个输入流传递到一个输出流。

常见实现子类
DataInputStream

DataInputStream:用于读取基本数据类型的二进制表示,不能单独使用,必须结合其它流,比如 FileInputStream:

![[Pasted image 20231016095342.png]]

构造方法

  1. FileInputStream(String name):创建一个 FileInputStream 对象,并打开指定名称的文件进行读取。文件名由 name 参数指定。如果文件不存在,将会抛出 FileNotFoundException 异常。

  2. FileInputStream(File file):创建一个 FileInputStream 对象,并打开指定的 File 对象表示的文件进行读取。

FileInputStream

FileInputStream:可直接指定文件路径,可以直接读取单字节数据,也可以读取至字节数组中。

一般不会直接单独使用 FileInputStream ,通常会配合 BufferedInputStream 字节缓冲输入流来使用

例如,通过 readAllBytes() 读取输入流所有字节并将其直接赋值给一个 String 对象:

![[Pasted image 20231016095318.png]]

ByteArrayInputStream

ByteArrayInputStream:用于从内存中读取字节数据。它的数据源是一个内存中的字节数组。将一个字节数组作为输入流,然后按字节顺序读取数组中的数据

提供了一系列用于读取字节的方法,如 read()read(byte[] buffer)read(byte[] buffer, int offset, int length),可以读取单个字节、一组字节,或者指定长度的字节块

下面的示例使用了 ByteArrayInputStream 逐字节读取字节数组中的数据,并转换为字符并打印出来

import java.io.ByteArrayInputStream;
import java.io.IOException;public class ByteArrayInputStreamExample {public static void main(String[] args) {// 创建一个字节数组byte[] data = "Hello, World!".getBytes();// 创建 ByteArrayInputStream 对象ByteArrayInputStream bis = new ByteArrayInputStream(data);// 读取数据try {int b;while ((b = bis.read()) != -1) {System.out.print((char) b);}} catch (IOException e) {e.printStackTrace();} finally {// ByteArrayInputStream 不需要关闭,因为它不会占用系统资源}}
}
OutputStream 字节输出流

OutputStream是所有字节输出流类的超类,它定义了写入字节的基本方法
用于将数据(字节信息)写入到目的地(通常是文件)

常用方法
  • write(int b):将特定字节写入输出流。

当使用 write(int b) 方法写出一个字节时,参数 b 表示要写出的字节的整数值。由于一个字节只有8位,因此参数 b 的取值范围应该在 0 到 255 之间,超出这个范围的值将会被截断。例如,如果参数 b 的值为 -1,那么它会被截断为 255,如果参数 b 的值为 256,那么它会被截断为 0。

  • write(byte b[ ]) : 将数组b 写入到输出流,等价于 write(b, 0, b.length)

  • write(byte[] b, int off, int len) : 在write(byte b[ ]) 方法的基础上增加了 off 参数(偏移量)和 len 参数(要读取的最大字节数)。

  • flush():刷新此输出流并强制写出所有缓冲的输出字节。

  • close():关闭输出流释放相关的系统资源。

FileOutputStream 是最常用的字节输出流对象,可直接指定文件路径,可以直接输出单字节数据,也可以输出指定的字节数组。

常见实现子类
FileOutputStream

FileOutputStream 是最常用的字节输出流对象,可直接指定文件路径,可以直接输出单字节数据,也可以输出指定的字节数组。

![[Pasted image 20231016095239.png]]

类似于 FileInputStreamFileOutputStream 通常也会配合 BufferedOutputStream(字节缓冲输出流)

构造方法

  1. 使用文件名创建
FileOutputStream fos = new FileOutputStream(fileName);

如果文件不存在,则创建一个新文件;如果文件已经存在,则覆盖原有文件

  1. 使用文件对象创建
FileOutputStream fos = new FileOutputStream(file);
  1. 借助追加模式实现数据的追加
FileOutputStream fos = new FileOutputStream(file/filename, true/false);

如果文件不存在,则创建一个新文件;如果文件已经存在,则在文件末尾追加数据。

第二个参数中都需要传入一个boolean类型的值,true 表示追加数据,false 表示不追加也就是清空原有数据。

若要实现追加数据的换行,需要在追加的内容字符串中添加 \r\n(Windows)\n (macOS)符号

DataOutputStream

DataOutputStreamFilterOutputStream 的子类)用于写入指定类型数据,不能单独使用,必须结合其它流,比如 FileOutputStream

![[Pasted image 20231016095412.png]]

  • ByteArrayOutputStream:用于向内存中的字节数组写入字节数据。

    除了基本的写入操作(write())外,ByteArrayOutputStream还提供了其他一些方法,如:

    • reset() 用于重置流,以便重新使用
    • size() 用于获取当前写入的字节数
    • toString() 用于将写入的字节数组转换为字符串

字节缓冲流

IO 操作是很消耗性能的,缓冲流将数据加载至缓冲区,一次性读取/写入多个字节,从而避免频繁的 IO 操作,提高流的传输效率。

字节缓冲流这里采用了 Java IO 设计模式中的装饰器模式来增强 InputStreamOutputStream子类对象的功能。

字节流和字节缓冲流的性能差别主要体现在使用两者的时候都是调用 write(int b)read() 这两个一次只读取一个字节的方法的时候。

由于字节缓冲流内部有缓冲区(字节数组),因此,字节缓冲流会先将读取到的字节存放在缓存区,大幅减少 IO 次数,提高读取效率。

性能差别

使用 write(int b)read() 方法,分别通过字节流和字节缓冲流复制一个 524.9 mb 的 PDF 文件耗时对比如下:

使用缓冲流复制PDF文件总耗时:     15428 毫秒
使用普通字节流复制PDF文件总耗时: 2555062 毫秒

两者耗时差别非常大,缓冲流耗费的时间是字节流的 1/165。

如果是调用 read(byte b[])write(byte b[], int off, int len) 这两个写入一个字节数组的方法的话,只要字节数组的大小合适,两者的性能差距其实不大,基本可以忽略。

使用 read(byte b[])write(byte b[], int off, int len) 方法,分别通过字节流和字节缓冲流复制一个 524.9 mb 的 PDF 文件耗时对比如下:

使用缓冲流复制PDF文件总耗时:     695 毫秒
使用普通字节流复制PDF文件总耗时: 989 毫秒

两者耗时差别不是很大,缓冲流的性能要略微好一点点。

BufferInputStream 字节缓冲输入流

BufferedInputStream 从源头(通常是文件)读取数据(字节信息)到内存的过程中不会一个字节一个字节的读取,而是会先将读取到的字节存放在缓存区,并从内部缓冲区中单独读取字节。这样大幅减少了 IO 次数,提高了读取效率。

BufferedInputStream 内部维护了一个缓冲区,这个缓冲区实际就是一个字节数组

缓冲区的大小默认为 8192 字节,也可以通过构造方法BufferedInputStream(InputStream in, int size) 来指定缓冲区的大小。

BufferInputStream 使用示例
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;public class BufferedInputStreamExample {public static void main(String[] args) {// 指定文件路径String filePath = "example.txt";try (FileInputStream fis = new FileInputStream(filePath);BufferedInputStream bis = new BufferedInputStream(fis)) {int b;while ((b = bis.read()) != -1) {System.out.print((char) b);}} catch (IOException e) {e.printStackTrace();}}
}
  • 创建 FileInputStream:创建了一个FileInputStream对象fis,指向文件example.txt

  • 创建 BufferedInputStream:使用fis作为参数创建了一个BufferedInputStream对象bis

  • 读取数据:通过调用bis.read()方法逐字节读取文件内容。如果read()返回-1,表示已到达文件末尾。

  • 打印数据:将读取到的字节转换为字符并打印出来

BufferOutputStream 字节缓冲输出流

BufferedOutputStream 将数据(字节信息)写入到目的地(通常是文件)的过程中不会一个字节一个字节的写入,而是会先将要写入的字节存放在缓存区,并从内部缓冲区中单独写入字节。这样大幅减少了 IO 次数,提高了读取效率

BufferedOutputStream 内部也维护了一个缓冲区,并且,这个缓存区的大小也是 8192 字节。也可以通过构造方法
BufferedOutputStream(OutputStream in, int size) 来指定缓冲区的大小。

BufferOutputStream 使用示例
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;public class BufferedOutputStreamExample {public static void main(String[] args) {// 指定文件路径String filePath = "example.txt";String content = "Hello, World!";try (FileOutputStream fos = new FileOutputStream(filePath);BufferedOutputStream bos = new BufferedOutputStream(fos)) {// 将字符串转换为字节数组并写入缓冲区bos.write(content.getBytes());} catch (IOException e) {e.printStackTrace();}}
}

代码说明:

  • 创建 FileOutputStream:创建了一个FileOutputStream对象fos,指向文件example.txt

  • 创建 BufferedOutputStream:使用fos作为参数创建了一个BufferedOutputStream对象bos

  • 写入数据:将字符串content转换为字节数组,并通过bos.write()方法写入缓冲区。

  • 自动刷新:由于使用了 try-with-resources 语句,BufferedOutputStream会自动关闭并刷新缓冲区,将所有数据写入文件。

随机访问流

随机访问流指的是支持随意跳转到文件的任意位置进行读写RandomAccessFile
RandomAccessFile 的构造方法如下,可以指定 mode(读写模式)。

// openAndDelete 参数默认为 false 表示打开文件并且这个文件不会被删除
public RandomAccessFile(File file, String mode)throws FileNotFoundException {this(file, mode, false);
}// 私有方法
private RandomAccessFile(File file, String mode, boolean openAndDelete)  throws FileNotFoundException{// 省略大部分代码
}

读写模式主要有下面四种:

  • r : 只读模式。
  • rw: 读写模式
  • rws: 相对于 rwrws 同步更新对“文件的内容”或“元数据”的修改到外部存储设备。
  • rwd : 相对于 rwrwd 同步更新对“文件的内容”的修改到外部存储设备。

文件内容指的是文件中实际保存的数据,元数据则是用来描述文件属性比如文件的大小信息、创建和修改时间。

RandomAccessFile 中有一个文件指针用来表示下一个将要被写入或者读取的字节所处的位置。我们可以通过 RandomAccessFileseek(long pos) 方法来设置文件指针的偏移量(距文件开头 pos 个字节处)。如果想要获取文件指针当前的位置的话,可以使用 getFilePointer() 方法。

实际应用

RandomAccessFile 比较常见的一个应用就是实现大文件的 断点续传
简单来说就是上传文件中途暂停或失败(比如遇到网络问题)之后,不需要重新上传,只需要上传那些未成功上传的文件分片即可。分片(先将文件切分成多个文件分片)上传是断点续传的基础。

RandomAccessFile 可以帮助我们合并文件分片,示例代码如下:
![[Pasted image 20231017222219.png]]

字节流的对象操作

ObjectInputStream 用于从输入流中读取 Java 对象,反序列化

![[Pasted image 20231016101022.png]]

ObjectOutputStream 用于将 Java 对象写入到输出流,序列化

![[Pasted image 20240827192941.png]]

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2024.8.27 作业

1> 提示并输入一个字符串&#xff0c;统计该字符串中字母个数、数字个数、空格个数、其他字符的个数 #include <iostream>using namespace std;int main() {string s;cout << "请输入字符串>>>";getline(cin,s);int letter0,digit0,blank0,…

华为eNSP:静态路由配置、浮动路由配置

静态路由&#xff1a; 一、拓扑图 二、路由器配置 2.1&#xff1a;配置接口 R1&#xff1a; [r1]int g0/0/0 [r1-GigabitEthernet0/0/0]ip add 192.168.1.254 24 [r1-GigabitEthernet0/0/0]qu [r1]int g0/0/1 [r1-GigabitEthernet0/0/1]ip add 10.1.1.1 24 [r1-GigabitEth…

CMake之PUBLIC、PRIVATE、INTERFACE

竹杖芒鞋轻胜马,谁怕?一蓑烟雨任平生~ 个人主页&#xff1a; rainInSunny | 个人专栏&#xff1a; C那些事儿、 Qt那些事儿 文章目录 写在前面抽象版解释头文件和链接库传递测试代码结构PUBLIC传递PRIVATE传递INTERFACE传递 写在前面 使用CMake必然离不开target_include_dir…

第2章 双向链表

双向链表 概念 对链表而言&#xff0c;双向均可遍历是最方便的&#xff0c;另外首尾相连循环遍历也可大大增加链表操作的便捷性。因 此&#xff0c;双向循环链表&#xff0c;是在实际运用中是最常见的链表形态。 基本操作 与普通的链表完全一致&#xff0c;双向循环链表虽然…

FPGA 如何进入 AI 领域的思考

FPGA在AI领域如何发力&#xff0c;如何抢碗饭吃&#xff1f;大多数提到是硬件加速&#xff0c;在AI工程里&#xff0c;完成数据前处理&#xff08;加速&#xff09;。大家很少提到AI模型的本身的推理过程&#xff0c;让FPGA成为AI模型的推理/算力芯片&#xff0c;这自然是 FPGA…

2535. 解密 [CSP-J 2022]

代码 #include <bits/stdc.h> using namespace std; long long m,n; int check(int x){if(x * (m - x) n) return 0;if(x * (m - x) < n) return 1;if(x * (m - x) > n) return 2; } int main(){int k;cin >> k;while(k--){long long e, d,p0,q0;scanf(&q…

如何抠去PPT图片的背景?推荐这款AI智能抠图软件!

做ppt的过程中&#xff0c;我们会用到各式各样的图片素材&#xff0c;其中有些图片不能完全满足我们的需求&#xff0c;得先对图片进行处理&#xff0c;最常见的是抠图&#xff0c;去除图片原有的背景&#xff0c;得到一张包含透明像素的图片&#xff0c;方便我们排版PPT页面上…

高德企业用车负责人:以AI技术革新出行服务体验

在助力产业数字化转型的大潮中&#xff0c;高德企业用车以其前沿的科技理念和创新服务&#xff0c;正在成为出行领域的领跑者。近日接受采访时&#xff0c;高德地图行业合作业务总经理姜义丹先生分享了AI技术在出行领域应用的思考&#xff0c;以及如何提升企业服务智能化水平&a…

【C/C++】typedef用法

typedef用法讲解&#xff0c;时隔半年&#xff0c;再看typedef。 &#x1f381;typedef可以简化结构体关键字 #include<iostream> using namespace std;struct Person {char name[64];int age; };void test01() {struct Person p { "张三",18 };//不用type…

005、架构_数据节点

​DN组件总览 ​ DN节点包含进程 dbagent进程:主要提供数据节点高可用、数据导入导出、数据备份恢复、事务一致性、运维类功能、集群的扩缩容、卸数等功能;MySQL进程:主要提供数据一致性、分组管理、快同步复制、高低水位等;

卡在恢复模式怎么办?这样操作一键轻松退出iPhone 恢复模式

iOS 18beta版本发布后&#xff0c;已经成功升级到iOS 18beta并享受新功能的小伙伴们真是太幸运了。但是还有一些小伙伴在更新iOS 18beta的过程中遇到了各种问题&#xff0c;比如iPhone卡在恢复模式是常见问题。如果你也遇到此问题&#xff0c;不要着急&#xff0c;接下来我们将…

Graylog日志丢失解决方案

问题描述 目前公司使用的日志方案是Graylog5.0版本&#xff0c;当接入的日志并发多时&#xff0c;就会出现日志丢失的情况。 目前硬件系统centos7.9 内核5.16.13。一台graylog和一台es服务器。 两台机器硬件配置 graylog CPU 36C 内存 150G 系统硬盘 500G &#xff08;固态&…

[论文阅读] mobile aloha实验部分

DP:[1] CHI C, FENG S, DU Y, et al. Diffusion Policy: Visuomotor Policy Learning via Action Diffusion[J]. 2023. Diffusion Policy: Visuomotor Policy Learning via Action Diffusion精读笔记&#xff08;一&#xff09;-CSDN博客 哥伦比亚大学突破性的方法- Diffusio…

Android中apk安装过程源码解析

本文中使用的Android源码基于Android 14 1 三方应用安装apk调用方法 public void installApk() {Intent intent new Intent(Intent.ACTION_VIEW);intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);/** 自Android N开始&#xff0c;是通过FileProvider共享相关文件&#xff0…

git提交本地项目到远程仓库

1、查看项目目录&#xff0c;是否存在.git文件夹&#xff08;若存在则删除&#xff09; 2、登录git并新建一个空白项目 3、idea创建本地git仓库&#xff08;选择本地项目&#xff09; 4、添加要提交的项目&#xff08;项目右键&#xff09; 5、提交代码到本地仓库 6、配置远程…

SQLserver中的游标的分类和游标的生命周期

SQLserver中的游标的分类 在 SQL Server 中&#xff0c;游标&#xff08;Cursor&#xff09;是一种数据库对象&#xff0c;用于逐行处理结果集中的数据。游标可以用于复杂的数据处理任务&#xff0c;尤其是那些不能通过简单的 SELECT 语句和 JOIN 操作完成的任务。SQL Server …

48.x86游戏实战-封包抓取进图call

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 本次游戏没法给 内容参考于&#xff1a;微尘网络安全 工具下载&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1rEEJnt85npn7N38Ai0_F2Q?pwd6tw3 提…

OpenAI API: How to count tokens before API request

题意&#xff1a;“OpenAI API&#xff1a;如何在 API 请求之前计算令牌数量” 问题背景&#xff1a; I would like to count the tokens of my OpenAI API request in R before sending it (version gpt-3.5-turbo). Since the OpenAI API has rate limits, this seems impor…

OpenLayers3,地图探查功能实现

文章目录 一、前言二、代码实现三、总结 一、前言 图层探查&#xff0c;即对置于地图下方的图层进行一定范围的探查&#xff0c;以便用户查看到不易察觉的地理地况。本文基于OpenLayers3&#xff0c;实现地图探查的功能。 二、代码实现 <!DOCTYPE HTML PUBLIC "-//W…

基于Transformer架构的大模型推理硬件加速器设计

概述 当前大模型的基础架构正在向 Transformer 结构收敛1&#xff0c;Transformer架构自谷歌2017年提出后比较稳定&#xff0c;因此针对Transformer的计算设计专用的ASIC加速器很有必要。 尤其是“Attention is All you Need”》“Money is All you Need”&#xff0c;哈哈哈…