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

浅玩IO流

Java IO流

文章目录

  • Java IO流
    • 一、基础概念
    • 二、字节流
      • 2.1 字节输出流
      • 2.2 字节输入流
    • 三、字符流
      • 3.1 、字符输入流
      • 3.2、字符输出流
    • 四、缓冲流
      • 4.1、字节输出缓冲流
      • 4.2、字节输入缓冲流
      • 4.3字符缓冲输出流
      • 4.4、字符缓冲输入流
    • 五、转换流
      • 5.1、InputStreamReader
      • 5.2、OutputStreamWriter
    • 六、序列化与反序列化
      • 6.1、序列化(Serialization)
      • 6.2、反序列化(Deserialization)
        • 反序列化对象
      • 注意事项

一、基础概念

1、输入输出流的概念:

输入流: 从外部源(如磁盘、网络等)读取数据到内存。比如从文件读取字节数据到一个字节数组。
输出流: 从内存将数据写入到外部目标(如磁盘、网络等)。比如把字节数组的数据输出到一个磁盘文件。**缓存区概念:**在输入输出过程中,数据通常会先经过一个缓存区,以减少与外部设备的交互次数,提高效率。

2、字符流 vs 字节流
字节流: 处理原始字节数据,如 FileInputStream 和 FileOutputStream。

字符流: 处理字符数据,通常涉及字符编码转换,如 FileReader 和 FileWriter。有 write 和 read 方法的不一定是字符流,字节流也有 write 和 read 方法。例如,FileInputStream 和 FileOutputStream 也提供了 read 和 write 方法。

3、缓冲高效流:
通过在内存中维护一个缓冲区来减少与外部设备的交互次数,提高 I/O 操作的效率。
BufferedInputStream 和 BufferedOutputStream:分别用于字节输入流和字节输出流的缓冲。
BufferedReader 和 BufferedWriter:分别用于字符输入流和字符输出流的缓冲。

4、转换流:

用于在字节流和字符流之间进行转换,处理字符编码问题。
InputStreamReader:将字节输入流转换为字符输入流。
OutputStreamWriter:将字符输出流转换为字节输出流。
5、序列化与反序列化:
序列化:将对象转换为字节流,以便存储或传输。
反序列化:将字节流转换回对象。
ObjectOutputStream 和 ObjectInputStream:分别用于对象的序列化和反序列化。

二、字节流

2.1 字节输出流

包含的方法:

  • public void close()关闭输出流并释放与此流相关联的任何系统资源。
  • public void flush():刷新此输出流并强制任何缓冲的输出字节被写出。
  • public void write(byte[] b):将b.length的字节从指定的字节数组写入此输出流
  • public void write(byte[] b,int off,int len):从指定的字节数组写入 len 字节,从偏移量 off 开始输出到此输出流
  • public abstract void write(int b):将指定的字节写入此输出流。 (一个字节)
  • close()关闭流对象,但是先刷新一次缓冲区,关闭之后,流对象不可以继续再使用了。
  • flush()仅仅是刷新缓冲区(一般写字符时要用,因为字符是先进入的缓冲区),流对象还可以继续使用。

关于flush方法

1)自动刷新:
FileOutputStream 会在每次调用 write 方法时立即将数据写入到文件中,因为它没有内置的缓冲机制。因此,即使你不调用 flush 方法,数据也会立即写入到文件中。
2)关闭流时的刷新:
当你调用 close 方法时,FileOutputStream 会自动调用 flush 方法(但一般是在1-10M左右刷一次,而不是说每write()一次就flush()一次,那样也会使效率变低),确保所有未写入的数据都被写入到文件中,然后再关闭流。

什么时候需要显式调用 flush 方法?
1)确保数据立即写入:
如果你需要确保数据立即写入到文件中,而不是等待流被关闭,可以显式调用 flush 方法。例如,在日志记录或实时数据处理中,你可能希望数据立即写入到文件中,以防止数据丢失。
2)使用缓冲流时:
当使用 BufferedOutputStream 时,数据会先写入到内存中的缓冲区,而不是立即写入到文件中。为了确保缓冲区中的数据被写入到文件中,你需要显式调用 flush 方法。

示例

 public static void outStream() throws IOException {byte[] bytes = {97, 98, 97, 99, 101, 102};FileOutputStream fos = new FileOutputStream("F:\\javaIO流Out类测试文件.txt");//这里会把字节数组写入输出流指定的文件fos.write(bytes);
//        fos.flush();fos.close();}

还可以定义字节录入位置和长度

public static void partOutsTream() throws IOException {byte[] bytes = {97, 98, 97, 99, 101, 102};FileOutputStream fos = new FileOutputStream("F:\\javaIO流Out类测试文件.txt");//定义字节录入位置和长度fos.write(bytes, 0, 2);fos.close();}

2.2 字节输入流

常用方法:

  • int read()从该输入流读取一个字节的数据。 读取完成后最后会返回一个-1
  • int read(byte[] b) 从该输入流读取最多 b.length个字节的数据为字节数组。
  • void close()关闭此文件输入流并释放与流相关联的任何系统资源。
  • 还有其他的…
public static void FileInputStreamTest() throws IOException {int i = 0;FileInputStream fis = new FileInputStream("F:\\javaIO流Out类测试文件.txt");//判断文件是否为空,若不空,则读取。这里其实是读取到的一个个字节 ACSLL 码值到了变量i,然后打印while ((i = fis.read()) != -1) {System.out.print(i + ",");}fis.close();}

一次读取多个字节并转成字符串

public static void FileInputStreamTest2() throws IOException {int i = 0;FileInputStream fis = new FileInputStream("F:\\javaIO流Out类测试文件.txt");//定义字节数组,大小是2的倍数最好byte[] bytes = new byte[1024];//调用read方法取字节存储到字节数组中,并将有效字节数返回并赋值给iwhile ((i = fis.read(bytes)) != -1) {//将字节数组中的值取出来用String的构造函数转换成字符串,取值范围是0到i(i为有效值)System.out.print(new String(bytes, 0, i));}fis.close();}

然后还可以输入输出流结合实现文件赋值

public static void inputAndOutputStream() throws IOException {//首先输入到字节数组,即用输入类FileInputStream fis = new FileInputStream("F:\\javaIO流Out类测试文件.txt");//其次输出到磁盘,即用输出类FileOutputStream fos = new FileOutputStream("F:\\javaIO流Out类测试文件2.txt");int i;byte[] bytes = new byte[1024];//i返回的是有效文件个数while ((i = fis.read(bytes)) != -1) {fos.write(bytes, 0, i);}//先关文件输出流fos.close();fis.close();System.out.println("--------");}

三、字符流

3.1 、字符输入流

输入流Reader 子类 FileReader 继承自InputStreamReader,InputStreamReader继承自Reader
包含的方法:

  • int read() 读一个字符
  • int read(char[] cbuf) 将字符读入数组。
  • abstract int read(char[] cbuf, int off, int len) 将字符读入数组的一部分。
  • abstract void close() 关闭流并释放与之相关联的任何系统资源。

示例

public static void fileReaderTest() throws IOException {FileReader fr = new FileReader("F:\\字符测试文件.txt");int len;while ((len = fr.read()) != -1) {System.out.println((char) len);}System.out.println("-------------");}

字符输入流 ,转字符串

public static void fileReaderTranlateTest() throws IOException {FileReader fr = new FileReader("F:\\字符测试文件.txt");int len;char[] chars = new char[1024];while ((len = fr.read(chars)) != -1) {System.out.println(new String(chars, 0, len));}}

3.2、字符输出流

Writer 子类FileWriter 继承 OutputStreamWriter 继承 Writer
包含的方法:

  • abstract void close() 关闭流,先刷新。
  • abstract void flush() 刷新流。
  • void write(char[] cbuf) 写入一个字符数组。
  • abstract void write(char[] cbuf, int off, int len) 写入字符数组的一部分。
  • void write(int c) 写一个字符。
  • void write(String str) 写一个字符串。
  • void write(String str, int off, int len) 写一个字符串的一部分。

示例

public static void fileWriteTest() throws IOException {FileWriter fw = new FileWriter("F:\\字符测试文件.txt");fw.write("知识点");fw.flush();//刷新缓冲区数据到文件中fw.close();}

四、缓冲流

4.1、字节输出缓冲流

BufferedOutputStream(OutputStream out) 继承 OutputStream
构造方法:

  • BufferedOutputStream(OutputStream out) 创建一个新的缓冲输出流,以将数据写入指定的底层输出流
  • BufferedOutputStream(OutputStream out,int size) 创建一个新的缓冲输出流,以将具有指定缓冲区大小的

数据写入指定的底层输出流

示例

public static void bufferOutPutStreamTest() throws IOException {FileOutputStream fos = new FileOutputStream("F:\\缓冲流测试.txt");BufferedOutputStream bos = new BufferedOutputStream(fos);bos.write("测试缓冲流".getBytes());bos.flush();bos.close();}

4.2、字节输入缓冲流

BufferedInputStream继承自InputStream

构造方法:

  • BufferedInputStream(InputStream in) 创建一个BufferedInputStream并保存其参数,输入流 in ,供以后使用。
  • BufferedInputStream(InputStream in, int size) 创建BufferedInputStream具有指定缓冲区大小,并保存其参数,输入流 in ,供以后使用。

示例

public static void bufferInPutStreamTest() throws IOException {FileInputStream fis = new FileInputStream("F:\\缓冲流测试.txt");BufferedInputStream bis = new BufferedInputStream(fis);int len;byte[] bytes = new byte[1024];System.out.println("---------------");while ((len = bis.read(bytes)) != -1) {System.out.println(new String(bytes));}bis.close();}

4.3字符缓冲输出流

BufferedWriter继承自Write

构造方法:

  • BufferedWriter(Writer out) 创建使用默认大小的输出缓冲区的缓冲字符输出流。
  • BufferedWriter(Writer out, int sz) 创建一个新的缓冲字符输出流,使用给定大小的输出缓冲区。
  • 成员方法(特有): void newLine() 写一行行分隔符。
public static void bufferedWriterTest() throws IOException {FileWriter fw = new FileWriter("F:\\缓冲流测试文件.txt");BufferedWriter bw = new BufferedWriter(fw);bw.write("测试缓冲字符流");bw.newLine();bw.write("shd");bw.flush();bw.close();}

4.4、字符缓冲输入流

BufferedReader继承自Reader

构造方法:

  • BufferedReader(Reader in) 创建使用默认大小的输入缓冲区的缓冲字符输入流。
  • BufferedReader(Reader in, int sz) 创建使用指定大小的输入缓冲区的缓冲字符输入流。
  • 特有的成员方法:String readLine() 读一行文字。以换行符(‘\n’),回传(‘\r’)或者回车后直接跟着换行(\r\n)作为结束行的标志,如果读取到的这一行无数据了,会返回null值,其他时候返回的是读取的数据(但是不会读取行的终止符合,即如果本来有换行,读取后是不会读取换行符)
public static void bufferedReaderTest() throws IOException {BufferedReader br = new BufferedReader(new FileReader("F:\\缓冲流测试文件.txt"));//读的是一行,所以只有一字符串为类型接收数据String str;while ((str = br.readLine()) != null) {System.out.println(str);}HashMap a = new HashMap();}

五、转换流

作用: 转换流(Conversion Streams)是用于处理字符编码转换的一类流,它们主要用于将字节流转换为字符流,或者将字符流转换为字节流。这在处理不同编码格式的文本文件时特别有用。Java中主要的转换流包括InputStreamReader和OutputStreamWriter。

在Java中,IO流提供了读写数据的功能。转换流(Conversion Streams)是用于处理字符编码转换的一类流,它们主要用于将字节流转换为字符流,或者将字符流转换为字节流。这在处理不同编码格式的文本文件时特别有用。Java中主要的转换流包括InputStreamReaderOutputStreamWriter

5.1、InputStreamReader

InputStreamReader是一个桥接器,它将一个字节输入流转换为一个字符输入流。它使用指定的字符集(如UTF-8, GBK等)来解码字节。如果没有明确指定字符集,那么将使用平台默认的字符集。

使用示例:

import java.io.*;public class InputStreamReaderExample {public static void main(String[] args) {StringBuilder contentBuilder = new StringBuilder();try (InputStream is = new FileInputStream("input.txt");InputStreamReader isr = new InputStreamReader(is, "UTF-8")) { // 指定字符集为UTF-8int c;while ((c = isr.read()) != -1) {contentBuilder.append((char) c);}} catch (IOException e) {e.printStackTrace();}// 将内容转换为字符串String content = contentBuilder.toString();// 打印或进一步处理内容System.out.println(content); // 如果需要打印}
}

5.2、OutputStreamWriter

OutputStreamWriter同样是一个桥接器,但它的作用与InputStreamReader相反,它将一个字符输出流转换为一个字节输出流。它使用指定的字符集来编码字符。

使用示例:

import java.io.*;public class OutputStreamWriterExample {public static void main(String[] args) {try (OutputStream os = new FileOutputStream("output.txt");OutputStreamWriter osw = new OutputStreamWriter(os, "UTF-8")) { // 指定字符集为UTF-8String content = "Hello, World!";osw.write(content);osw.flush();} catch (IOException e) {e.printStackTrace();}}
}

六、序列化与反序列化

在Java中,序列化(Serialization)和反序列化(Deserialization)是将对象的状态转换为字节流以便于存储或传输,以及从字节流恢复对象状态的过程。这是Java提供的一种强大的机制,用于在网络通信、文件存储等方面实现对象的持久化。

6.1、序列化(Serialization)

序列化是指将对象的状态信息转换为可以存储或传输的形式的过程。在Java中,可以通过实现 Serializable 接口来使一个类的对象能够被序列化。

实现 Serializable 接口

要使一个类的对象可以被序列化,该类需要实现 Serializable 接口。这个接口是一个标记接口,没有任何方法需要实现,但它告诉Java虚拟机(JVM)该类的对象可以被序列化。

import java.io.Serializable;public class Person implements Serializable {private static final long serialVersionUID = 1L; // 可选,但推荐使用private String name;private int age;public Person(String name, int age) {this.name = name;this.age = age;}// Getters and Setterspublic String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "Person{name='" + name + "', age=" + age + "}";}
}

序列化对象

使用 ObjectOutputStream 类可以将对象序列化并写入到一个输出流中,例如文件或网络连接。

import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.io.IOException;public class SerializationExample {public static void main(String[] args) {Person person = new Person("Alice", 30);//编译并运行 SerializationExample 类,将 Person 对象序列化到 person.ser 文件中。try (FileOutputStream fos = new FileOutputStream("person.ser");ObjectOutputStream oos = new ObjectOutputStream(fos)) {oos.writeObject(person);System.out.println("Object has been serialized.");} catch (IOException e) {e.printStackTrace();}}
}

6.2、反序列化(Deserialization)

反序列化是指将字节流恢复为对象的过程。在Java中,可以通过 ObjectInputStream 类从输入流中读取字节流并恢复对象。

反序列化对象

使用 ObjectInputStream 类可以从输入流中读取字节流并恢复对象。

import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.io.IOException;public class DeserializationExample {public static void main(String[] args) {Person person = null;//从文件读取序列化得对象try (FileInputStream fis = new FileInputStream("person.ser");ObjectInputStream ois = new ObjectInputStream(fis)) {person = (Person) ois.readObject();System.out.println("Object has been deserialized: " + person);} catch (IOException | ClassNotFoundException e) {e.printStackTrace();}}
}

注意事项

  1. serialVersionUID: 建议为每个实现了 Serializable 接口的类定义一个 serialVersionUID。这个字段用于版本控制,如果类的结构发生变化,可以通过修改 serialVersionUID 来防止反序列化时出现兼容性问题。
  2. 瞬态字段: 使用 transient 关键字可以标记某些字段不被序列化。这些字段在序列化时会被忽略,反序列化时会恢复为默认值(例如数字类型为0,引用类型为null)。
  3. 安全性: 序列化和反序列化可能会带来安全风险,特别是当处理不受信任的数据时。应确保只从可信来源读取序列化的数据,并考虑使用其他安全措施。

http://www.mrgr.cn/news/67670.html

相关文章:

  • Web Workers 学习笔记
  • k8s的发展历史
  • 利用全排列解决LeetCode第3343题“统计平衡排列的数目”问题
  • ONLYOFFICE 8.2深度体验:高效协作与卓越性能的完美融合
  • 2024了现在学习网络安全还来得及吗?
  • foreach 遍历List不产生GC的原因
  • 【Spring】——SpringBoot项目创建
  • 人类行为的恒定因素
  • 深度解析:特力康|电缆隧道综合在线监测系统的革新与应用
  • Java 代码编辑器 IDEA 使用技巧(涵盖快捷键、插件、推荐设置)
  • arm linux gcc
  • 基于STM32的智能充电桩:集成RTOS、MQTT与SQLite的先进管理系统设计思路
  • 从pg_depend和pg_class开始了解MogDB/openGauss/postgresql的系统元数据设计
  • nuxt3安装pinia报错500[vite-node] [ERR_LOAD_URL]问题解决
  • “requirements.txt“ 文件生成和使用
  • 有的网站是通过js控制页面新打开一个tab页的,但是我想通过注入js脚本修改为在当前页面打开
  • C++关键字:mutable
  • 立冬到了,选择Codigger暖心陪伴
  • ElasticSearch:使用dsl语句同时查询出最近2小时、最近1天、最近7天、最近30天的数量
  • glibc 内存分配与释放机制详解
  • 前端关闭控制台打印信息
  • 25源码编译安装软件
  • Android 开发 Java中 list实现 按照时间格式 yyyy-MM-dd HH:mm 顺序
  • 导游职业资格考试真题题库
  • 给应用添加通知和提醒 习题答案 <HarmonyOS第一课>>
  • 基于微信小程序实现个人健康管理系统