IO流
最后一定要关闭流,防止资源泄露
字节流
一次读取1字节,8比特
FileInputStream
import org.junit.jupiter.api.Test;import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;public class CopyBytes {public static void main(String[] args) throws IOException {}//单个字节的读取@Testpublic void test1() throws IOException{FileInputStream in = null;FileOutputStream out = null;String path="src\\single\\in.txt";String dpath="src\\single\\out.txt";try {in = new FileInputStream(path);//String,boolean true追加;false覆盖,默认out = new FileOutputStream(dpath,true);int datacode;//read()一次读取一个字节,返回读取字节的ASCII码,返回-1,表示读取完毕while ((datacode = in.read()) != -1) {System.out.println(datacode);//输出ASCII码 例如 a 是97 ;一个汉字是3个字节System.out.println((char)datacode);out.write(datacode);}} finally {if (in != null) {in.close();}if (out != null) {out.close();}}}@Testpublic void test2() throws IOException{FileInputStream in = null;FileOutputStream out = null;String path="src\\single\\in.txt";String dpath="src\\single\\out.txt";try {in = new FileInputStream(path);out = new FileOutputStream(dpath);//一次读取多个字节,返回读取字节的长度byte[] buf=new byte[2];int datalen=0;while((datalen=in.read(buf))!=-1){System.out.println(datalen);System.out.println(new String(buf,0,datalen));out.write(buf,0,datalen);}} finally {if (in != null) {in.close();}if (out != null) {out.close();}}}
}
字符流
FileReader
package file;import org.junit.jupiter.api.Test;import java.io.*;public class FileReader_ {public static void main(String[] args) {}//单个字符@Testpublic void readFile01() {String filePath = "src\\file\\in.txt";String dPath="src\\file\\out.txt";FileReader fileReader = null;FileWriter fileWriter=null;int datacode = 0;//1. 创建 FileReader 对象try {fileReader = new FileReader(filePath);fileWriter=new FileWriter(dPath);//循环读取 使用 read, 单个字符读取while ((datacode = fileReader.read()) != -1) {System.out.print(datacode);System.out.println((char) datacode);fileWriter.write(datacode);}} catch (IOException e) {e.printStackTrace();} finally {try {if (fileReader != null) {fileReader.close();}if(fileWriter!=null){//这里一定要关闭,才会写入 或者flush //close 等价于 flush + close//底层还是字节流fileWriter.close();}} catch (IOException e) {e.printStackTrace();}}}@Testpublic void readFile02() {String filePath = "src\\file\\in.txt";String dPath="src\\file\\out.txt";FileReader fileReader = null;FileWriter fileWriter=null;int readLen = 0;char[] buf = new char[8];//1. 创建 FileReader 对象try {fileReader = new FileReader(filePath);fileWriter=new FileWriter(dPath,true);//循环读取 使用 read(buf), 返回的是实际读取到的字符数//如果返回-1, 说明到文件结束while ((readLen = fileReader.read(buf)) != -1) {System.out.print(new String(buf, 0, readLen));fileWriter.write(buf,0,readLen);}} catch (IOException e) {e.printStackTrace();} finally {try {if (fileReader != null) {fileReader.close();}if(fileWriter!=null){fileWriter.close();}} catch (IOException e) {e.printStackTrace();}}}
}
处理流
BufferedReader
处理流以节点流为基础,提供了更加强大的功能
package file;import java.io.*;/*** @author 韩顺平* @version 1.0* 演示 bufferedReader 使用*/
public class BufferedReader_ {public static void main(String[] args) {String filePath = "src\\file\\in.txt";String dPath="src\\file\\out.txt";//创建 bufferedReaderBufferedReader bufferedReader =null; BufferedWriter bufferedWriter=null;try {bufferedReader=new BufferedReader(new FileReader(filePath));bufferedWriter=new BufferedWriter(new FileWriter(dPath));//读取String line; //按行读取, 效率高//说明//1. bufferedReader.readLine() 是按行读取文件//2. 当返回 null 时,表示文件读取完毕while ((line = bufferedReader.readLine()) != null) {System.out.println(line);bufferedWriter.write(line);}} catch (Exception e) {e.printStackTrace();}finally {//关闭流, 这里注意,只需要关闭 BufferedReader ,因为底层会自动的去关闭 节点流try {if(bufferedReader!=null) {bufferedReader.close();}if(bufferedWriter!=null){bufferedWriter.close();}} catch (IOException e) {e.printStackTrace();}}}
}
打印流
PrintWriter
也是一种处理流
打印流只有输出流,没有输入流
打印到显示器或文件
PrintStream out = System.out;
//在默认情况下,PrintStream 输出数据的位置是 标准输出,即显示器
/*
public void print(String s) {
if (s == null) {
s = "null";
}
write(s);
}
*/
out.print("john, hello");
//因为 print 底层使用的是 write , 所以我们可以直接调用 write 进行打印/输出
out.write("韩顺平,你好".getBytes());//我们可以去修改打印流输出的位置/设备
//1. 输出修改成到 "e:\\f1.txt"
//2. "hello, 韩顺平教育~" 就会输出到 e:\f1.txt
//3. public static void setOut(PrintStream out) {
// checkIO();
// setOut0(out); // native 方法,修改了 out
// }
System.setOut(new PrintStream("e:\\f1.txt"));
System.out.println("hello, 韩顺平教育~");out.close();//flush + 关闭流, 才会将数据写入到文件.
标准输入输出流
System.in
System.out
System.in System.out System.err
程序启动时创建,退出时关闭。
不需要程序员关闭
package single;import org.junit.jupiter.api.Test;import java.util.Scanner;public class TestClass {public static void main(String[] args) {}@Testpublic void test1(){Scanner scanner = new Scanner(System.in);/*System.inSystem 的public final static InputStream in = null;编译类型InputStream运行类型BufferedInputStream标准输入是键盘*/System.out.println();/*System.outSystem 的 public final static PrintStream out = null;编译类型PrintStream运行类型PrintStream标准输出是屏幕*/}}
ObjectOutputStream
对象处理流
序列化:
是将对象的状态信息转换为可以存储或传输的二进制形式的过程。
就是在保存数据的时候,保存数据的值和数据类型
反序列化:
将在序列化过程中所生成的二进制字节流的过程转换成数据结构或者对象的过程
就是在恢复数据的时候,恢复数据的值和数据类型
需要让某个对象支持序列化机制,则必须让其类是可序列化的,为了让某个类是可序列化的,该类必须实现如下两个接口之一:
- Serializable //这是一个标记接口(没有方法),推荐
- Externalizable //有方法,他也实现了Serializable
@Testpublic void objectoutputstream() throws Exception{//序列化后的文本格式,是按他自己的方式String path="D:\\IDEA_file\\Learn_8\\src\\file\\Files\\file5.dat";ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream(path));oos.write(100);//int->Integer,实现了Serializableoos.writeBoolean(false);//boolean->Boolean,实现了Serializableoos.writeChar('7');//char->Character,实现了Serializableoos.writeDouble(9.8);//double->Double,实现了Serializableoos.writeUTF("china");//String,实现了Serializableoos.writeObject(new Dog("wnag",19));//关闭流oos.close();}}//要想数据可序列化,必须继承Serializableclass Dog implements Serializable {String name;int age ;public Dog(String name, int age) {this.name = name;this.age = age;}}
如果有些字段不想进行序列化,
对于不想进行序列化的变量,使用 transient
关键字修饰。
transient
关键字的作用是:阻止实例中那些用此关键字修饰的的变量序列化;当对象被反序列化时,被 transient
修饰的变量值不会被持久化和恢复。
关于 transient
还有几点注意:
transient
只能修饰变量,不能修饰类和方法。transient
修饰的变量,在反序列化后变量值将会被置成类型的默认值。例如,如果是修饰int
类型,那么反序列后结果就是0
。static
变量因为不属于任何对象(Object),所以无论有没有transient
关键字修饰,均不会被序列化。
serialVersion
- serialVersionUID作用是什么以及如何生成的? - 腾讯云开发者社区-腾讯云 (tencent.com)
- serialVersionUID 是干什么的? - 知乎 (zhihu.com)
- (46条消息) idea如何一键自动生成序列化serialVersionUID_秋竹的博客-CSDN博客_idea 生成serialversionuid
序列化运行时与每个可序列化类关联一个版本号(称为 serialVersionUID),该版本号在反序列化期间用于验证序列化对象的发送方和接收方是否已加载与序列化兼容的类。如果接收方为对象加载了一个类,该类的串行版本UID与相应发送方的类的类不同,则反序列化将导致无效类异常,可序列化类可以通过声明一个名为 的字段来显式声明自己的串行VersionUID,该字段必须是静态的、最终的和类型:
ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;
不能被继承
转换流
inputStremReader
把字节流转换成字符流
字节流可以指定编码格式,可以处理中文乱码等情况
public class InputStreamReader_ {
public static void main(String[] args) throws IOException {
String filePath = "e:\\a.txt";
//解读
//1. 把 FileInputStream 转成 InputStreamReade
//2. 指定编码 gbk
//InputStreamReader isr = new InputStreamReader(new FileInputStream(filePath), "gbk");
//3. 把 InputStreamReader 传入 BufferedReader
//BufferedReader br = new BufferedReader(isr);
//将 2 和 3 合在一起
BufferedReader br = new BufferedReader(new InputStreamReader(
new FileInputStream(filePath), "gbk"));
//4. 读取
String s = br.readLine();
System.out.println("读取内容=" + s);
//5. 关闭外层流
br.close();