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

JAVA基础-I/O

File

  • java.io.File类是专门用来操作文件/目录的类,可以对文件/目录进行查找、删除、修改等操作
  • File类的注意点:
    • 一个File对象就代表硬盘中的一个文件/目录
    • File类的构造器并不会检查文件/目录是否存在。因此无论文件/目录是否存在,都不会影响File对象的创建
    • File对象可以对文件/目录进行查找、删除、修改等操作,但是不能对文件内容进行读写操作
    • File.separator来获取路径分隔符,避免跨平台运行问题
/*** 文件搜索* @param file  需要搜索的文件目录* @param fileName  文件名*/
public static void searchFile(File file, String fileName) {if(file == null || !file.exists() || file.isFile()) {return;}//获取当前目录下的一级文件或文件夹File[] files = file.listFiles();if(files == null || files.length == 0){for (File f : files) {if(f.isFile()){if(f.getName().equals(fileName)){System.out.println(f.getAbsolutePath());}}else{searchFile(f, fileName);}}}
}
Hutool FileUtil 类
  • FileUtil 类包含以下几类操作工具: 
    • 文件操作:包括文件目录的新建、删除、复制、移动、改名等 
    • 文件判断:判断文件或目录是否非空,是否为目录,是否为文件等等。 
    • 绝对路径:针对 ClassPath 中的文件转换为绝对路径文件。 
    • 文件名:主文件名,扩展名的获取 
    • 读操作:包括 getReader、readXXX 操作 
    • 写操作:包括 getWriter、writeXXX 操作
  • FileUtil.move(file, dest, true);
  • FileUtil.del(file);
  • FileUtil.rename(file, "FileUtilDemo3.java", true);
  • FileUtil.readLines(file, "UTF-8").forEach(System.out::println);

RandomAccessFile

  • 设计Java中访问文件的类,它允许随机访问文件,即可以在文件中的任何位置进行读取和写入操作
  • 访问模式:
    • 'r':只读模式
    • 'rw':读写模式,如果文件不存在,将被创建
    • 'rws':同步读写模式,要求在本地设备上的文件内容或元数据的每次更新都同步写入底层存储设备,
    • 'rwd':同步读写模式,要求在本地设备上的文件内容的每次更新都同步写入底层存储设备

按传输方式分

字节流
  • 一切文件(图片、音频、视频等)都是以二进制的形式存储的,传输的时候也是。所以字节流可以传输任意类型的文件数据
字节输入流:
  • java.io.InputStream是字节输入流的超类
  • close():关闭此流并释放相关资源
  • int read():从输入流读取数据的下一个字节
  • int read(byte[] b):从输入流中读取若干个字节,并将它们存储在缓冲区数组b中,返回值:读入缓冲区的总字节数,或者如果因为已到达流的末尾而没有更多数据,则为 -1 。
  • int read(byte[] b, int off, int len):b:数组读取缓冲区、off:数组b中数据写入的起始偏移量、len:最多可读取的字节数
字节输出流:
  • java.io.OutputStream是字节输出流的超类
  • close():关闭此流并释放相关资源
  • flush():刷新此输出流并强制缓冲区的字节被写入到目的地
  • write(byte[] b):将b.length个字节从指定的字节数组写入此输出流
  • write(byte[] b,int off,int len):在指定字节数组从偏移量off开始,写入len个字节到此输出流
字符流
  • 在使用时需要注意字符集编码,StandardCharsets
字符输入流:
  • java.io.Reader字符输入流的超类
  • close():关闭此流并释放相关资源
  • int read():读取的字符,作为 0 到 65535( 0x00-0xffff )范围内的整数,或者如果已到达流末尾则为-1
  • int read(char[] cbuf):将字符读入数组,读取的字符数,如果到达流末尾则为-1
字符输出流:
  • java.io.Writer字符输出流的超类
  • close():关闭此流并释放相关资源
  • write(int c):写入单个字符
  • write(char[] cbuf):写入一个字符数组
  • write(char[] cbuf, int off, int len):写入字符数组的一部分
  • write(String str):写入一个字符串
  • write(String str, int off, int len):写入字符串的一部分

按功能类型分

文件
FileInputStream文件字节输入流
  • 构造方法:
    • FileInputStream(String name):name 路径名
    • FileInputStream(File file):file 指定的file对象
  • 常用方法:
    • close():关闭此流并释放相关资源
    • FileChannel getChannel():返回与文件输入流相关联的唯一FileChannel对象
    • read()、read(byte[] b)、read(byte[] b,int off,int len)从输入流中读取字节数据
    • long skip(long n):跳过并丢弃输入流中的n个字节的数据
 @Test
public void test() throws Exception {try (FileInputStream fs = new FileInputStream(path);){int len;byte[] bytes = new byte[1024];while((len = fs.read(bytes)) != -1){System.out.print(new String(bytes,0, len));}}
}
FileOutputStream文件字节输出流
  • 构造函数:
    • FileOutputStream(File file)创建一个文件输出流,写入指定的file对象
    • FileOutputStream(File file, boolean append)创建一个文件输出流,写入指定的file对象,append为true则表示字节被写入文件的末尾而不是开头
    • FileOutputStream(String name)
    • FileOutputStream(String name, boolean append)
  • 常用方法:
    • close():关闭此流并释放相关资源
    • FileChannel getChannel():返回与文件输出流相关联的唯一FileChannel对象
    • write(byte[] b)、write(byte[] b,int off,int len)、write(int b)将数据写入输出流
 @Test
public void test1() throws Exception {try (FileOutputStream fileOutputStream = new FileOutputStream(path,true);) {fileOutputStream.write("字节输出流".getBytes());}
}
FileReader文件字符输入流
  • 继承自InputStreamReader
  • 使用默认缓冲区大小从字符文件中读取文本。字节到字符的解码使用指定的字符集或平台的默认字符集。
  • 构造函数:
    • FileReader(File file)使用平台默认的字符集,根据给定的file创建的输入流
    • FileReader(File file, Charset charset)根据指定的file和字符集常见输入流
    • FileReader(String fileName)
    • FileReader(String fileName, Charset charset)
  • 常用方法:使用的是父类的方法,并没有重写
@Test
public void test3() throws Exception {try (FileReader fileReader = new FileReader(path);) {int len;char[] chars = new char[1024];while ((len = fileReader.read(chars)) != -1) {System.out.print(new String(chars, 0, len));}}
}
FileWriter文件字符输出流
  • 继承自InputStreamWriter
  • 使用默认缓冲区大小将文本写入字符文件。字符到字节的编码使用指定的字符集或平台的默认字符集。
  • 构造函数:
    • FileWriter(File file)使用平台默认字符集,根据给定file创建输出流
    • FileWriter(File file, boolean append)使用平台默认字符集,根据给定file创建输出流,append为true,则字节将被写入文件的末尾而不是开头
    • FileWriter(File file, Charset charset)根据指定的file和编码,创建输出流
    • FileWriter(File file, Charset charset, boolean append)
    • FileWriter(String fileName)
    • FileWriter(String fileName, boolean append)
    • FileWriter(String fileName, Charset charset)
    • FileWriter(String fileName, Charset charset, boolean append)
  • 常用方法:使用的是父类的方法,并没有重写
@Test
public void test4() throws Exception {try( FileWriter fileWriter = new FileWriter(path,true);){fileWriter.write("字符输出流");fileWriter.write("\n");}
}
  • 文件复制
 @Test
public void test5() throws Exception {try (FileReader fileReader = new FileReader(path, StandardCharsets.UTF_8);FileWriter fileWriter = new FileWriter(new_path,StandardCharsets.UTF_16);){int len;char[] chars = new char[1024];while ((len = fileReader.read(chars)) != -1) {fileWriter.write(chars, 0, len);}} catch (IOException e) {throw new RuntimeException(e);}
}
数组
  • 作为文件处理的中间层
  • 能够实现在内存中暂存,不需要创建临时文件
  • 需要注意OOM的问题
ByteArrayInputStream字节数组输入流:
  • 将内存中的字节数组包装成输入流
  • 当需要InputStream但是文件已经在内存中,比如ObjectInputStream
ByteArrayOutputStream字节数组输出流
  • 将数据流的形式写入内部的字节数组中
  • 配合ObjectInputStream从内存中获取数据
CharArrayReader字符数组输入流
  • 针对字符数据,功能同字节数组输入流
CharArrayWriter字符数组输入流
  • 针对字符数据,功能同字节数组输出流
管道
  • Piped流提供了一种线程间通信的机制,允许一个线程向管道写入数组,另一个线程从管道读取数据
  • 分为字节流和字符流
  • 共同特点:
    • 线程通信:转为跨线程数据交换设计
    • 先进先出:保持数据的写入顺序
    • 阻塞机制:读操作在无数据时阻塞,写操作在缓冲区满时阻塞
    • 必须连接:输入输出流需要先连接才能使用
  • 内部缓冲区:
    • 默认缓冲区:字节流:1024字节,字符流:1024字符
    • 可以通过构造函数调整大小
基本数据类型
  • DataInputStreamDataOutputStream 提供了对基本数据类型和字符串的格式化读写功能
  • DataOutputStream
    • 构造方法:
      • DataOutputStream(OutputStream in)
    • 基本数据类型序列化:将Java基本数据类型转为字节流写入
    • UTF-8字符串支持
    • 平台无关格式:保证不同平台读取一致性
// 基本类型写入
void writeBoolean(boolean v)
void writeByte(int v)
void writeShort(int v)
void writeChar(int v)
void writeInt(int v)
void writeLong(long v)
void writeFloat(float v)
void writeDouble(double v)// 特殊写入
void writeUTF(String str)  // 使用UTF-8修改版编码
void writeBytes(String s)  // 按字节写入(截断字符)
void writeChars(String s)  // 按字符写入(UTF-16BE)
  • DataInputStream
    • 构造方法:
      • DataInputStream(InputStream in)
    • 反序列化基本类型:从字节流重建Java基本类型
    • 精确匹配写入格式:必须与写入顺序严格对应
    • EOF检测:读取时可能抛出EOFException
// 基本类型读取
boolean readBoolean()
byte readByte()
short readShort()
char readChar()
int readInt()
long readLong()
float readFloat()
double readDouble()// 特殊读取
String readUTF()  // 读取UTF-8修改版编码字符串	
@Test
public void test6() throws Exception {try (DataOutputStream dos = new DataOutputStream(new FileOutputStream( path))) {dos.writeInt(123456);dos.writeUTF("你好");dos.writeDouble(3.1415926);dos.writeBoolean(true);}try (DataInputStream dis = new DataInputStream(new FileInputStream(path))) {int i = dis.readInt();String s = dis.readUTF();double d = dis.readDouble();boolean b = dis.readBoolean();System.out.println(i);System.out.println(s);System.out.println(d);System.out.println(b);}
}
缓冲
  • 缓冲流式对字节流和字符流的一种封装,通过在内存中开辟缓冲区来提高I/O的操作效率
  • 缓冲流的工作原理是将数据写入缓冲区,当缓冲区满时在一次性写入文件或输出流,或者当缓冲区为空时一次性从文件或输入流中读取一定量的数据
字节缓冲流
  • 构造方法:
    • BufferedInputStream(InputStream in) :创建一个缓冲区默认大小8k的字节输入流
    • BufferedInputStream(InputStream in,int size):创建一个指定缓冲区大小的字节输入流
    • BufferedOutputStream(OutputStream out): 创建一个缓冲区默认大小8k的字节输出流
    • BufferedOutputStream(OutputStream out,int size): 创建一个指定缓冲区大小的字节输出流
  • 为什么字节缓冲流能够提升效率?
    • 传统的I/O是阻塞模式:读/写->等待->读/写->等待
    • 减少物理I/O操作次数:将多次小I/O操作合并为一次大I/O操作
    • 减少上下文切换
  • public synchronized int read(byte b[], int off, int len)
    • 检查流是否已关闭及参数校验
    • 循环读取数据:
      • 调用read1()尝试读取数据
      • 如果返回值≤0(表示EOF或者错误):返回负数或者返回读取到的字节数
      • 累加已读取的字节数
      • 如果字节数≥期望值,则返回已读取的字节数
      • 检查地城输入流是否还有可用数据,如果没有,则返回当前已读取的字节数
  • private int read1(byte[] b, int off, int len)
    • 检查缓冲区是否还有可用数据,avail <= 0,说明缓冲区没有可用数据,需要从底层流填充缓冲区
      • 如果请求读取长度≥缓冲区且不需要知识reset,则直接返回请求读取长度的数据块
      • 反之填充缓冲区,
    • 执行实际的数据复制,返回实际读取的字节数
  • public synchronized void write(byte b[], int off, int len)
    • 如果len≥缓冲区,
      • 先刷新缓冲区已有数据
      • 直接将数组数据写入底层输出流,绕过缓冲区,避免大数组写入时不必要的缓冲区复制操作
    • 如果缓冲区空间不足,刷新当前缓冲区,为新数据腾出空间
    • 将数据写入缓冲区
字符缓冲流
  • BufferedReader类继承自Reader类,提供了一些便捷的方法,例如redLine()方法可以一次读取一行数据,而不是一个字符一个字符的读取
  • BufferedWriter类继承自Writer类,提供了一些便捷的方法,例如newLine()方法可以写入一个特定的行分隔符
  • 构造方法:
    • BufferedReader(Reader in)创建一个默认缓冲区8k大小的字符输入流
    • BufferedReader(Reader in, int sz)创建一个指定缓冲区大小的字符输入流
    • BufferedWriter(Writer out)创建一个默认缓冲区8k大小的字符输出流
    • BufferedWriter(Writer out, int sz)创建一个指定缓冲区大小的字符输出流
@Test
public void test8() throws Exception {ArrayList<String> strings = new ArrayList<>();strings.add("锄禾日当午");strings.add("汗滴禾当午");strings.add("谁知盘中餐");strings.add("粒粒皆辛苦");try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(path));){for (String string : strings) {bufferedWriter.write(string);bufferedWriter.newLine();}}
}@Test
public void test7() throws Exception {try (BufferedReader bufferedReader = new BufferedReader(new FileReader(path));){String line;while ((line = bufferedReader.readLine()) != null){System.out.println(line);}}
}
转换
  • 转换流可以将一个字节流转换为字符流,这种转换通常用于处理文件数据,如读取文本文件或数据从网络传输到应用程序
  • 用途:Java10之前用于解决编码问题
序列化
public static <T> T deepCopy(T obj) throws IOException, ClassNotFoundException {try (ByteArrayOutputStream bos = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(bos)) {oos.writeObject(obj);try (ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());ObjectInputStream ois = new ObjectInputStream(bis)) {return (T) ois.readObject();}}
}
  • Java中有两种序列化方式,
    • Serializable自动序列化,static和transient修改的字段不能被序列化
    • Externalizable自定义序列化,Externalizable 接口的 writeExternal 和 readExternal 方法由类实现
public class ExternalizableTest implements Externalizable {private transient String content = "是的,我将会被序列化,不管我是否被transient关键字修饰";@Overridepublic void writeExternal(ObjectOutput out) throws IOException {out.writeObject(content);}@Overridepublic void readExternal(ObjectInput in) throws IOException,ClassNotFoundException {content = (String) in.readObject();}public static void main(String[] args) throws Exception {ExternalizableTest et = new ExternalizableTest();ObjectOutput out = new ObjectOutputStream(new FileOutputStream(new File("test")));out.writeObject(et);ObjectInput in = new ObjectInputStream(new FileInputStream(new File("test")));et = (ExternalizableTest) in.readObject();System.out.println(et.content);out.close();in.close();}
}
http://www.xdnf.cn/news/17201.html

相关文章:

  • el-image-viewer组件在el-table使用时层级异常问题解决
  • Vue3 基本语法
  • 【Android笔记】Android 自定义 TextView 实现垂直渐变字体颜色(支持 XML 配置)
  • 【密码学】6. 消息认证和哈希函数
  • latex in overleaf快速通关论文排版
  • vue3 el-select 加载触发
  • list类
  • 设计模式中的行为模式
  • 【Unity输入系统】自定义与双击不冲突的单击Interaction
  • 零基础-动手学深度学习-9.3. 深度循环神经网络
  • 深度学习(2):自动微分
  • 数据结构——栈、队列
  • STM32——STM32CubeMX
  • Keil MDK-ARM V5.42a 完整安装教程
  • Git Status 命令深度指南:洞悉仓库状态的核心艺术
  • 【YOLOv8改进 - C2f融合】C2f融合SFS-Conv(空间 - 频率选择卷积)提升特征多样性,同时减少参数和计算量
  • cuda编程笔记(13)--使用CUB库实现基本功能
  • 一个自动定位并查询天气的工具(c语言)
  • Liberica JDK 和普通JDK(如Oracle JDK、OpenJDK等)的差异
  • 经营帮:重构企业经营全流程,打造产业互联网新生态
  • Spring IoC 容器核心流程(面试必懂)
  • QT项目 -仿QQ音乐的音乐播放器(第五节)
  • 光伏电站巡检的智能化转型
  • 《算法导论》第 10 章 - 基本数据结构
  • Spark Memory 内存设计的核心组件、对比Flink内存配置
  • Moses工具的配置和小语种平行语料训练SMT完整实现
  • iptables封堵实验
  • NFS 服务器
  • 贪心+矩阵算法
  • Go语言Ebiten坦克大战