首页 > 编程语言 >Java IO 流详解

Java IO 流详解

时间:2024-08-10 19:17:11浏览次数:14  
标签:字符 Java 字节 输出 int 详解 IO 输入 读取

概述

流是一个抽象的概念,代表了数据的无结构化传递。流的本质是数据在不同设备之间的传输。在 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));
  }
}

标签:字符,Java,字节,输出,int,详解,IO,输入,读取
From: https://www.cnblogs.com/Yee-Q/p/18271395

相关文章

  • IOS-AR-游戏开发入门手册-全-
    IOSAR游戏开发入门手册(全)原文:BeginningiOSARGameDevelopment协议:CCBY-NC-SA4.0一、介绍在本书中,我们将学习如何使用Unity(Unity3D2018,或者更常见的是Unity)的游戏开发软件来创建一个增强现实(或AR)游戏。在这一章中,我们将介绍Unity的下载和安装过程,并了解Un......
  • Java计算机毕业设计基于Android的校园网上拍卖平台(开题报告+源码+论文)
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景在数字化校园建设的浪潮中,学生们对于便捷、高效的二手商品交易需求日益增长。传统的校园跳蚤市场受限于时间、空间等因素,难以满足学生群体对于多样化......
  • Spring Boot:开启Java开发的新篇章
    引言随着互联网技术的飞速发展,业务需求变化日益频繁,对开发效率提出了更高要求。传统的Java应用构建过程往往繁琐复杂,涉及到大量的配置文件编写与依赖管理等工作。SpringBoot正是针对这一痛点而生,它通过约定优于配置的原则,简化了Spring应用的搭建过程,使得开发者可以更加专......
  • Java计算机毕业设计基于微信小程序的HPV疫苗预约与抢苗系统的设计与实现(开题+源码+论
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着健康意识的提升,人们对疾病预防的重视程度日益增强,尤其是针对女性健康的HPV(人乳头瘤病毒)疫苗,其作为预防宫颈癌等恶性肿瘤的有效手段,需求量急剧增......
  • Java计算机毕业设计基于Android的生活记账小助手APP的设计与实现(开题报告+源码+论文)
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景在快节奏的现代生活中,个人财务管理成为了许多人面临的一大挑战。随着智能手机的普及和移动互联网技术的飞速发展,移动应用成为辅助个人财务管理的得力......
  • Java计算机毕业设计基于微信小程序的网络文学管理平台(开题+源码+论文)
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着移动互联网的迅猛发展,网络文学已成为大众文化消费的重要组成部分,其便捷性、互动性和丰富性深受读者喜爱。然而,传统网络文学平台多依赖于网页或AP......
  • flutter 中scrollable_positioned_list 控制列表滚动
    scrollable_positioned_list 是Flutter中一个强大的列表控件,它允许通过位置来控制列表滚动。它常用于需要精确控制列表滚动位置的应用场景依赖scrollable_positioned_list:^0.3.8#精确控制列表滚动位置代码提前知道每个模块高度classMyListextendsStatefulWidget......
  • 暑假学习Java第六周
    这周我学习了cmd的基础语言,在Java编程语言中,"CMD"主要指的是命令行接口,它允许开发者通过命令行窗口执行各种操作系统级的任务。Java标准类库中提供了一些用于在命令行界面中执行命令的类和接口,最主要的是 Runtime 类和 ProcessBuilder 类。这些类使得从Java应用程序中启动其......
  • 如何在Java项目中使用自定义序列化器处理URL
    如何在Java项目中使用自定义序列化器处理URL在Java开发中,处理和序列化URL是一个常见的需求,尤其是在涉及到图像资源时。如果项目需要根据特定条件处理图像URL(如添加前缀),可以自定义一个序列化器来简化这一过程。本文将介绍如何创建一个自定义的ImgJsonSerializer类,处理单个URL和UR......
  • 每周Java学习汇总
    在Java编程中,有几个重要的概念和关键字你需要理解:就近原则、this关键字、String构造方法以及字符串的比较。就近原则:在Java中,就近原则指的是当存在多个同名的变量或方法时,程序会优先使用最近定义的那个。这意味着,如果在同一个作用域内有两个同名的变量,程序会使用离它最近的那个......