首页 星云 工具 资源 星选 资讯 热门工具
:

PDF转图片 完全免费 小红书视频下载 无水印 抖音视频下载 无水印 数字星空

Java IO 流详解

编程知识
2024年08月10日 18:16

概述

流是一个抽象的概念,代表了数据的无结构化传递。流的本质是数据在不同设备之间的传输。在 Java 中,数据的读取和写入都是以流的方式进行的

在 Java 中,根据数据流向的不同,可以将流分为输入(Input)流和输出(Output)流。根据单位的不同,可以将流分为字节流和字符流。根据等级的不同,可以将流分为节点流和处理流


输入流和输出流

输入流用于将数据从控制台、文件、网络等外部设备输入应用程序进程中

输出流用于将应用程序进程中的数据输出到控制台、文件、显示器等中


字节流和字符流

字节流:字节流是以字节(1byte=8bit)为单位对数据进行读写操作的,也就是说,字节流进行一次读取或者写入都是以 8bit 为单位进行的,因此主要用于处理二进制据。在 Java 中使用 InputStream、OutputStream 处理字节数据,其中 InputStream 用于字节流输入,OutputStream 用于字节流输出

字符流:字符流以字符为单位对数据进行读写操作,一次读取或写入都是以 16bit 为单位进行的。Java 中的字符采用 Unicode 编码,一个字符占用 2 字节。字符流主要用于处理文本数据的读写,在处理过程中需要进行字符集的转化。在 Java 中使用 Reader、Writer 处理字符数据,其中 Reader 用于字符流输入,Writer 用于字符流输出

InputStream 字节输入流是一个抽象类,其子类包括:

  • FileInputStream(文件输入流)
  • ObjectInputStream(对象输入流)
  • ByteArrayInputStream(字节数组输入流)
  • PipedInputStream(管道输入流)
  • FilterInputStream(过滤器输入流)
    • BufferedInputStream(缓冲输入流)
    • PushbackInputStream(回牙输入流)
    • DataInputStream(数据输入流)
  • SequenceInputStream(顺序输人流)
  • StringBufferedInputStream(缓冲字符串流)

InputStream 类的所有方法在遇到错误时都会抛出 IOExcepiion 异常。InputStream 用于以字节形式将数据读入应用程序中,常用的方法及其作用如表所示

方法 作用
int read() 从输入流读取8字节数据并将其转换成一个0-255的整数,返回值为读取的总字节数,遇到数据流的末尾则返回-1
int read(byte[] b) 从输入流中读取最大长度为len字节的数据并保存到b字节数组中,遇到数据流的末尾则返回-1
int read(byte[] b, int off, int len) 以输入流中的off位置为开始位置读取最大长度为len字节的数据,并将其保存到b字节数组中
void close() 关闭输入流
int available() 返回可以从输入流中读取的位数
skip(long n) 从输入流跳过n字节

一段基于 FileInputStream 读取文件的代码如下:

public static void main(string[] args) throws IoException {
  String path = "file_dir/";
  String fileName = "File-Test.txt";
  // 1:定义待读取的文件
  File file = new File(path, fileName);
  // 2:从文件中读取数据到 FileInputStream
  FileInputStream fileInputStream = new FileInputStream(file);
  byte[] bytes = new byte[fileInputstream.available()];
  int n = 0;
  // 3:从FileInputstream中不断循环读取字节数据并写入bytes,直到遇到数据流结尾时
  while ((n = fileInputstream.read(bytes)) != -1) {
    // 4:将byte[]转化为字符串
    String s = new String(bytes);
    System.out.printIn(s);
  }
  // 5:关闭输入文件流
  fileInputStream.close();
} 

OutputStream 字节输出流是一个抽象类,其子类包括:

  • FileOutputStream(文件输出流)
  • ByteArrayOutputStream(字节数组输出流)
  • FilterOutputStream(过滤器输出流)
    • BufferedOutputStream(缓冲输出流)
    • DataOutputStream(数据输出流)
    • PrintOutputStream(打印输出流)
  • ObjectOutputStream(对象输出流)
  • PipedOutputStream(管道输出流)

OutputStream 类的所有方法在遇到错误时都会抛出 IOException 异常。OutputStream 用于以字节形式将数据输出到目标设备,常用的方法及其作用如表所示

方法 作用
int write() 将指定字节的数据写入输出流
int write(byte[] b) 将指定字节数组的内容写入输出流
int write(byte[] b, int off, int len) 将指定的字节数组从off位置开始的len字节的内容写入输出流
close() 关闭数据流
flush() 刷新输出流,强行将缓冲区的内容写入输出流

基于 FileOutputStream 读取文件的一段代码如下

public static void main(String[] args) throws IOException {
  String path = "file_dir/";
  String fileName = "File-Test.txt";
  // 1:定义待写入的文件
  File file = new File(path, fileName);
  // 2:定义FileOutputStream
  FileOutputStream fileOutputStream = new FileOutputStream(file, false);
  // 3:将数据写入FileOutputStream
  fileOutputStream.write("hello FileOutputStream new " .getBytes());
  // 4:关闭FileOutputStream
  fileOutputStream.close();
}

Reader 类是所有字符流输入类的父类,用于以字符形式将数据读取到应用程序中,其子类包括:

  • CharArrayReader:将字符数组转换为字符输入流并从中读取字符
  • StringReader:将字符串转换为字符输入流并从中读取字符
  • BufferedReader:为其他字符输入流提供读缓冲区
  • PipedReader:连接到一个 PipedWriter
  • FilterReader:Reader 类的子类,用于丰富 Reader 类的功能
  • InputStreamReader:将字节输入流转换为字符输入流,可以指定字符编码

Reader 类常用方法如下

方法 作用
int read() 从输入流中读取一个字符并转化为 0-65535 的整数,当读取到流的末尾时返回-1
int read(char[] buf) 从输入流中读取若干个字符并保存到参数buf指定的字符数组中,当读取到流的末尾时返回-1
int read(char[] buf, int off, int len) 以输入流中的off位置为开始位置读取最大长度为len字节的数据并将其保存到buf字符数组中,当读取到流的末尾时返回-1

基于 BufferedReader 读取文件的一段代码如下:

public static void main(string[] args) throws Exception {
  String path = "file_dir.mov";
  //1:创建FileReader
  FileReader fileReader = new FileReader(path);
  //2:基于FileReader创建BufferedReader
  BufferedReader bufferedReader = new BufferedReader(fileReader);
  //3:定义一个strLine,表示BufferedReader读取的结果
  String strLine = "";
  //4:调用readLine方法将缓冲区中的数据读取为字符串
  //当readLine返回-1时,表示已经读取到文件末尾了
  while((strLine = bufferedReader.readLine()) != null) {
    System.out.println(strLine);
  }
  //5:关团fileReader
  fileReader.close();
  //6:关闭bufferedReader
  bufferedReader.close();
}

Writer 类是所有字符流输出类的父类,用于以字符形式将数据写出到外部设备,其子类包括:

  • CharArrayWriter:用于向内存缓冲区的字符数组写数据
  • StringWriter:用于向内存缓冲区的字符串(StringBuffer)写数据
  • BufferedWriter:用于为其他字符输出流提供写缓冲区
  • PipedWriter:用于连接到一个 PipedReader
  • OutputStreamReader:用于将字节输出流转换为字符输出流,可以指定字符编码
  • FilterWriter:过滤器字符输出流

Writer 类常用方法如下

方法 作用
void write(int c) 向输出流中写入一个字符
void write(char[] cbuf) 将字符数组cbuf中的字符写入输出流中
void write(char[] cbuf,int off, int len) 将字符数组cbuf中从off位置开始获取长度为len的字符并写入输出流中
void write(String str) 将字符串写入输出流
void write(String str,int off, int len) 将字符串中的部分字符写入输出流
append(char c) 将字符c追加到输出流
append(charSequence csq) 将参数csq指定的字符序列追加到输出流
append(charSequence csq, int start, int end) 将参数csq指定的字符序列的子序列追加到输出流

基于 BufferedWriter 将字符串写入文件中的一段代码如下:

public static void main(String[] args) throws Exception {
  //1:定义一个FileWriter
  String path = "File-Test.txt";
  FileWriter writer = new FileWriter(path);
  //2:基于FileWriter定义一个BufferWriter
  BufferedWriter bufferedWriter = new BufferedWriter(writer)
  //3:调用BufferedWriter的write方法将字符串写入BufferedWriter
  bufferedWriter.write("write by str");
  //4:关闭BufferedWriter
  bufferedWriter.close();
  //5:关闭FileWriter
  writer.close();
}

节点流和处理流

节点流是低级流,直接与数据源相接,对数据源上的流进行读写。

处理流是高级流,采用修饰器模式对节点流进行了封装,不直接与数据源相连,主用于消除不同节点流的实现差异,提供更方便的方法来完成数据的输入和输出。

例如,FileInputStream、FileOutputStream、FileReader、FileWriter 属于节点流;BufferInputStream、BufferOutputStream、BufferReader、BufferWriter 属于处理流。

相对于节点流,处理流有如下特性:

  • 性能高:处理流通过增加缓存的方式提高数据的输入和输出效率。
  • 操作方便:处理流封装了一系列高级方法来完成一次性大批量数据的输入和输出。

内存映射文件技术

操作系统可以利用虚拟内存实现将一个文件或者文件的一部分“映射”到内存中。然后,这个文件就可被当作内存数据来访问,比传统的文件要快得多,这种技术就是内存映射文件技术。

内存映射文件技术的一个关键优势是操作系统负责真正的文件读写,应用程序只需处理内存数据,就可以实现非常快速的 IO 操作。在写入过程中,即使应用程序在将数据写人内存后进程出错退出,操作系统仍然会将内存映射文件中的数据写入文件系统。另一个更突出的优势是共享内存,即内存映射文件可被多个进程同时访问,起到低时延共享内存的作用。

Java 中的 java.nio 包支持内存映射文件,具体使用方式是通过 MappedByteBuffer 读写内存,而且内存映射文件技术涉及的内存在 Java 的堆空间之外,这也是其效率高的一个原因。

在 Java 中将一个文件映射到内存并操作共分为如下三步:

从文件中获得一个通道(channel)

RandomAccessFile raf = new RandomAccessFile(filePath, "rw");
FileChannel fc= raf.getChannel();

调用 FileChannel 的 map 方法将文件映射到虚拟内存

MappedByteBuffer buffer = channel.map(mode, 0, length);

mode 参数用于指定映射模式,支持的模式有如下三种:

  • FileChannel.MapMode.READ_ONLY:所产生的缓冲区是只读的
  • FileChannel.MapMode.READ_WRITE:所产生的缓冲区是可写的,任何修改在某个时刻写回到文件中。注意,其他映射同一个文件的程序可能不能立即看到这些修改,多个程序同时进行文件映射的最终行为是依赖于操作系统的
  • FileChanncl.MapMode.PRIVATE:所产生的缓冲区是可写的,但任何修改对该缓冲区来说都是私有的,不会传播到文件中

调用 MappedByteBuffer 的 put(byte[] src) 向内存映射文件中写入数据,调用 get(int index) 获取文件中对应索引的数据,以字节形式返回

public static void main(String[] args) throws Exception {
  //1:定义文件流
  String path = "file_path/File-Test.txt";
  RandomAccessFile raf = new RandomAccessFile(path,"rw");
  //2:获取FileChannel
  FileChannel fc = raf.getChannel();
  //3:定义MappedByteBuffer
  int start = 0:
  int len = 1024;
  //调用map函数的过程其实就是磁盘文件到内存数据的映射过程
  //对Filechannel调用map函数后,应用程序可以像使用内存一样使用该文件
  MappedByteBuffer mbb = fc.map(FileChannel.MapMode.PRIVATE, start, len);
  //4:进行MappedByteBuffer数据的输入,分别在内存映射文件中写入如下字符串
  mbb.put("12345".getBytes());
  mbb.put("6789".getBytes());
  mbb,put("wanglei".getBytes());
  //读取第9个字符,结果为"w"
  System.out.println((char)mbb.get(9));
  //5:MappedByteBuffer数据的读取:读取所有数据
  for (int i = start; i < mbb.position(); i++) {
    System.out.println((char)mbb.get(i));
  }
}
From:https://www.cnblogs.com/Yee-Q/p/18271395
本文地址: http://shuzixingkong.net/article/970
0评论
提交 加载更多评论
其他文章 # games101 作业3分析 详解bump mapping
games101 作业3分析 详解bump mapping 代码分析 整体代码结构 其实变化还是不大 主要是引入了vertexshader(什么都没做) 与 fragmentshader(使用了不同的着色方法 直接用法线作为rgb 使用blingphong光照模型 纹理贴图 bumpmapping
# games101 作业3分析 详解bump mapping # games101 作业3分析 详解bump mapping # games101 作业3分析 详解bump mapping
巨简单!弄懂递归的原理-带括号加法题而已
“递归”第5行代码这里你把它想成带括号的数学题,有括号先算括号内,直到没有括号,括号内的运算后的值在再与括号外的值运算
巨简单!弄懂递归的原理-带括号加法题而已 巨简单!弄懂递归的原理-带括号加法题而已
一款.NET开发的AI无损放大工具
前言 今天大姚给大家分享一款由.NET开源(GPL-3.0 license)、基于腾讯ARC Lab提供的Real-ESRGAN模型开发的AI无损放大工具:AI-Lossless-Zoomer。 Real-ESRGAN模型专注于人像和动漫图片的高质量无损放大。 项目功能 支持多线程处理、批量图片处理
一款.NET开发的AI无损放大工具 一款.NET开发的AI无损放大工具 一款.NET开发的AI无损放大工具
Python 潮流周刊#64:Python 的函数调用还很慢么?(摘要)
本周刊由 Python猫 出品,精心筛选国内外的 250+ 信息源,为你挑选最值得分享的文章、教程、开源项目、软件工具、播客和视频、热门话题等内容。愿景:帮助所有读者精进 Python 技术,并增长职业和副业的收入。 分享了 11 篇文章,13 个开源项目,1 则音视频,全文 2000 字。 以下是
[rCore学习笔记 024]多道程序与协作式调度
写在前面 本随笔是非常菜的菜鸡写的。如有问题请及时提出。 可以联系:1160712160@qq.com GitHhub:https://github.com/WindDevil (目前啥也没有 本节重点 主要是对&#160;任务&#160;的概念进行进一步扩展和延伸:形成 任务运行状态:任务从开始到
[rCore学习笔记 024]多道程序与协作式调度 [rCore学习笔记 024]多道程序与协作式调度 [rCore学习笔记 024]多道程序与协作式调度
使用 extract_sqlaudit_proc 存过分析ob性能问题
最近在某个金融单位核心系统项目做ob的性能压测,期间遇到不少问题,现场两周了每天都加班到凌晨一两点左右,真的是累死。&#129314;&#129314; 我其实进ob之前有心理预期,卷就卷吧,八九点下班也能接受,没想到真到了干项目的情况下,天天凌晨下班,真怕不知道啥时候会猝死。&#128514;&#
使用 extract_sqlaudit_proc 存过分析ob性能问题 使用 extract_sqlaudit_proc 存过分析ob性能问题 使用 extract_sqlaudit_proc 存过分析ob性能问题
代码随想录Day11
150. 逆波兰表达式求值 给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。 请你计算该表达式。返回一个表示表达式值的整数。 注意: 有效的算符为 &#39;+&#39;、&#39;-&#39;、&#39;*&#39; 和 &#39;/&#39; 。 每个操作数(运
代码随想录Day11 代码随想录Day11
[考试记录] 2024.8.10 csp-s 模拟赛18
80 + 20 + 0 + 70 = 170 第三题应该有 10 分暴力的,但我没打。 T1 星际旅行 题面翻译 总共有n个节点,m条路径,要求其中m-2条路径走两遍,剩下2条路径仅走一遍,问不同的路径总数有多少,如果仅走一遍的两条边不同则将这两条路径视为不同。 样例 #1 样例输入 #1 5 4
[考试记录] 2024.8.10 csp-s 模拟赛18 [考试记录] 2024.8.10 csp-s 模拟赛18