Java IO
文章目录
教程
java.io 包教程, 英文 https://www.tutorialspoint.com/java/io/index.htm
输入输出, 中文视频教程 https://www.w3cschool.cn/minicourse/play/java_io_my#menulist
文件与路径
File 类
- 用于文件本身属性和操作(增删改查)
Java 7 新包
java.nio.file https://blog.csdn.net/qq877728715/article/details/104499687/
Files 类
- 文件复制,linux 属性 rwx 等高级功能
Path 类
- 新工具,用来取代 java.io.file.File 类
相对路径
使用 Path.relativize()
- your_base.relativize(your_want_to_compare)
1 2 3 4 5 6 7 8 9 10 11 12 13import java.nio.file.Path; import java.nio.file.Paths; public class Test { public static void main(String[] args) { Path pathAbsolute = Paths.get("/var/data/stuff/xyz.dat"); Path pathBase = Paths.get("/var/data"); Path pathRelative = pathBase.relativize(pathAbsolute); System.out.println(pathRelative); } }
路径的 join
| |
序列化 <<序列化概念>>
概念
- 所谓的序列化就是将对象流化,就是将对象变成字节
相关类
前提
- 必须实现 java.io.Serializable 接口
- ObjectInputStream
ObjectOutputStream
注意
- 存在安全隐患,因为不需要构造函数创建对象(ObjectInputStream)
- 更推荐使用 json 序列化
增删改查
注意
- 除掉 查询,其它都发生了数据的改变
字节流
https://www.w3cschool.cn/minicourse/play/java_io_my?cp=4790
- 按 byte 类型读写
类的命名特点
一般以 InputStream 或 OutputStream 结尾,
- eg: FileOutputStream
用途
复制文件
- 因为是以字节为单位读写,相当于没有发生转码的原始数据
- 读写只是数据本身的复刻
特点
- 相当于 python: open("your_file", "rb")
文件流
FileOutputStream
文件字节输出流
1fout.write(String.getBytes());bool write(byte[] arr)
- 返回值
- 表示是否写入成功
FileInputStream
- 文件字节输入流
方法
- int read();
- 一次只读取一个字节 byte
- 文件结束,返回 -1
导致的问题
- 双字节字符(如:中文),对返回值 (char) ret_val 导致乱码
BufferedOutputStream
- 继承了 FileOutputStream
使用
- 对 FileOutputStream 进行包装
- 在构造函数中传入 FileOutputStream 对象
| |
bool write(byte [] arr, int start_pos, int to_write_len)
- 对输入数据 arr, 写入一段
关闭问题
- 先关闭
BufferedOutputStream
- 后关闭
FileOutputStream
- 穿脱原理
- 类似 C++ 析构过程
BufferedInputStream
| |
int read(byte[] array)
- 返回值
- 实际接收大小
特殊值:-1
表示到文件结尾
- 作用
- 使用 byte [] array 批量接收内容
对象流
注意
被读写对象
- 需要实现 Serializable 接口
Serializable 其实是一个空接口,只是用来标记而已
- 辅助唯一化工具:final 属性 serialVersionUID
- 可以使用 IDE 自动生成
| |
作用机理
static 属性 是 类属性,它又是 final 属性
- 这样就 决定了, serialVersionUID 和 类是 一一对应关系
特点
- 一个文件只能对应一个对象(个人见解)
一个文件保存多个对象
- 实现方法
- 把多个对象保存到容器中,如: HashMap
把这个容器,序列化到文件中
- 序列化 详解
ObjectOutputStream
使用
- 需要包装 FileOutputStream
ObjectInputStream
字符流
命名惯例
以 Reader 或 Writer 结尾
- eg: FileReader, FileWriter
FileWriter
类似 FileOutputStream
- 只不过,处理的对象,换成了单个“字符”
方法
- void write(int c)
- void write(String str)
- void write(String str, int offset, int len)
FileReader
方法
int len = fileReader.read()
- 读取单个字符
- 返回 -1, 表示终止
int len = fileReader.read(char[] arr)
- 向 字符数组 arr 读取
- len:
- 表示有效读取数量
返回 -1: 表示终止
1 2 3 4 5 6 7FileReader fr2 = new FileReader("FileWrite_test.txt"); char[] buf = new char[6]; int len; while((len=fr2.read(buf)) != -1){ String str = new String(buf,0,len); System.out.print(str); }
BufferedWriter
- 继承了 FileWriter
- 类似 BufferedOutputStream
方法
- bufferedWriter.write("your_words")
bufferedWriter.newLine()
- 跨平台换行符
- linxu –> "\n"
- windows –> "\r\n"
- macos –> "\r"
BufferedReader
方法
String str = bufferedReader.readLine()
- 终止判断
- null –> 终止
- "" –> 空串
字节流 输入输出乱码问题
视频教程 https://www.w3cschool.cn/minicourse/play/java_io_my?cp=4797&gid=0
乱码根源
- 没有设置好编码
默认编码在做怪
- 而,一般的 输入输出流,不能指定编码
解决办法
写入时
方法一
- 编码写入数据源
- buffferOutputStream.write("你好,写入".getBytes("utf-8"))
方法二
- 创建指定了编码的类
- 好处: 这样不用每次都对数据源进行编码
- OutputStreamWriter(fileOutputStream, "UTF-8")
outputStreamWriter.write("你好,写入")
多级包裹,实现编码
- BufferedWriter(OutputStream(FileOutputStream("your_file"), "utf-8"))
读取时
https://stackoverflow.com/questions/14918188/reading-text-file-with-utf-8-encoding-using-java
bufferedInputStream.read(char [] arr)
- arr.
多级包裹,实现编码
- BufferedReader(InputStream(FileInputStream("your_file"), "utf-8"))
PrintStream 和 InputStrean
PrintStream
教程
- 对别的流,进行封装
继承关系
- –> FilterOutputStream –> OutputStream
- 属于字节流
提供高级功能
- println
- format
- 可以指定编码
特殊实例
- System.out
- System.err
InputStream
- 基类
特殊实例
- System.in
Scanner
异常出现问题
读取文件
new FileInputStream("/our/file")
- FileNotFoundException
input.read()
- IOException
读取完成
- read() == -1
关闭流
手动法
1 2 3 4 5 6 7 8try{ } finally { if (input != null) input.close() }自动法
注:需要实现 java.lang.AutoClosable 接口
1 2 3try( InputStream input = new FileInputStream("/my/file.txt")) { }
阻塞
- strea.read() 会发生阻塞
输入基类
独写
- 以 byte[] 快速成批独写
数据转换
参考
String ==> byte[]
1myStr.getBytes("encoding") --> byte[]byte[] ==> String
1String(ourBytes, StandardCharsets.UTF_8)注意:
- outBytes.toString()
获取的是地址
- 直接输出 outBytes
- 输出的是地址
输入输出字节流
InputStream
FileInputStream
- read()
ByteArrayInputStream
- 构造
new ByteArrayInputStream(byte[] outBytes)
OutputStream
FileOutputStream
- write()
- flush
- close()
ByteArrayOutputStream
- 方法
- output.toByteArray()
衍生输入流 方式
参考
类型
数据源衍生类
- FileInputStream
- ByteArrayInputStream
- ServletInputStream
功能组件衍生类
- FilterInputStream
解说
Filter 模式,或者说装饰器模式:Decorator
- 作用:在运行期,增加功能
- 注:可以自己写一个 FilterInputStream 衍生类
再衍生
- BufferedInputStream
- DataInputStream
- CheckedInputStream
读取文件作为 byte[]
传统方法
1 2 3 4 5 6 7 8InputStream input = new FileInputStream("myfile.txt"); ByteArrayOutputStream buffer = new ByteArrayOutputStream(); int n; while ((n = input.read()) != -1){ buffer.write(n) } return buffer.toByteArray()注意
- 为什么使用 ByteArrayOutputStream
- 这里 ByteArrayOutputStream 大小可变
防止文件在打开后大小改变(其它程序修改文件)
以免起初创建的 byte[] buffer 被挤爆
1byte[] buffer = new byte[ourFile.getLength()]- 错误:预先设定 buffer 大小
新方法 nio
1byte[] buffer = Files.readAllBytes(Paths.get("myFile.txt"));注意
- 陷阱:文件太大,会发生内存溢栈
读取 classpath 中文件
参考
好处
- 避免不同操作系统,路径存储方式不同的问题
例子
1 2 3try (InputStream input = getClass().getResourceAsStream("/default.properties")) { // TODO: }注意
- 文件不存在,input 得到 null
字符流
参考
基类
- java.io.Reader
- java.io.Writer
读写单位
char
- 注意
- 字节流,读写 byte
文件读写
FileReader
构造:—> 可以指定编码
1Reader = new FileReader("/my/file.txt", "utf-8")- 注意
- 指定 编码 的 重载构造函数,在 jdk 11 之后才有
早期 jdk8, 使用 new InputStreamReader(input, "utf-8") 指定
方法
- int read()
结束,返回 -1
- int read(byte[] buffer)
- FileWriter
字符数组 char[] 读写
- CharArrayReader
- CharArrayWriter
String 读写
- StringReader
- StringWriter
转换 字节流 —> 字符流
InputStreamReader
作用:
- 包裹 InputStream 变成 Reader 字符流
| |
- OutputStreamWriter
高阶输出工具
- 一种 Filter 工具
PrintStream
- 输出字节流 byte
方法
- print(int)
- print(boolean)
- print(String)
- print(Object)
- …
- println(…)
比较 OutputStream
- 只有 write(byte) 和 write(byte[])
实例
- System.out
特点
- 不抛出 IOException
PrintWriter
输出字符流
1 2 3 4 5 6 7 8 9 10 11public class Main { public static void main(String[] args) { StringWriter buffer = new StringWriter(); try (PrintWriter pw = new PrintWriter(buffer)) { pw.println("Hello"); pw.println(12345); pw.println(true); } System.out.println(buffer.toString()); } }特点
- 类似 PrintStream
- 但是,输出字符流
- 一个 Filter 工具
文章作者
上次更新 2022-03-07 (de34a70)