什么是流?
在Java中所有数据都是使用流读写的。流是一组有顺序的有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备之间的传输称为流,流的本质是传输
IO流的分类类:
File :文件操作流
字节流(8位的字节):Stream (处理为字节的数据,write/read操作byte[] ,或一个byte)
字符流(16位的字节):Reader、Writer (处理为字符的数据,一般用在文本操作,操作byte[] 、byte、char[]、char)
Input / Reader:输入流 (流的方向:读取 / 写入,输入:将数据从各种输入设备(文件、键盘等)读取到内存)
Output / Write:输出流 (输出数据写入到各种输出设备(文件(数据,不是设备)、显示器、磁盘))
Buffered:缓冲流(开辟缓冲区)
特殊:字节字符流转换流 InputStreamReader、OutputStreamWriter(要把字节转换为字符流,需要在中间套上字节字符转换流)
其他:
(1) PrintWriter:打印输出流
(2)StringWriter:字符串输出流
(3)带Object:对象流
创建流:
直接创建
(1)文件 输入/输出 字节流
(2)文件 输入/输出 字符流流可以包裹另外的流
(1) 先创建字节/ 字符流,在外包裹其他流
- 如:new BufferedRead(new FileReader())
(2)如果设计字节流转换为字符流,中间要使用字节字符转换流
- 如:new BufferedReader(new InputStreamReader(new
FileInputStream()))
流的使用
- 字节流操作:write() / read() byte[],byte
- 字符流操作:write() / read() char[],char
----------------- 特殊的字符操作流:println()
注:可以不停的读取输入流,一直到读取结束:如果read返回值为int,读取到-1结束,若返回值为String,以null返回结束
代码:
import java.io.*;
public class FileInput {
public static void main(String[] args) throws IOException {
File file = new File("C:\\Users\\LENOVO\\Documents\\Tencent Files\\1029170395\\FileRecv\\0320.txt");
// //1.文件字节输入流
// FileInputStream fis = new FileInputStream(file);
// //输入流比较固定的写法:读取到一个字节、字符数组,
// // 先定义read的返回值变量,再while循环
// byte[] bytes = new byte[1024];
// int len = 0;
// while ((len = fis.read(bytes)) != -1) { //读取到的长度,数组可能杜曼,可能未读满,当次读取内容,一般使用数组[0,len]
// String str = new String(bytes,0,len); //字节数组转字符串 模拟
// System.out.println(str);
// }
// //使用完一定要关闭,反向关闭(和创建顺序相反)
// fis.close();
// //2.文件的字符输入流
// FileReader fr = new FileReader(file);
// char[] chars = new char[1024];
// int len = 0;
// while ((len = fr.read(chars)) != -1) {
// String str = new String(chars,0,len);
// System.out.println(str);
// }
// fr.close();
// //3.缓冲流缓冲字节输入,缓冲字符输入
// //字符输入流
// //new BufferedReader(new InputStreamReader(new FileInputStream()))
// FileInputStream fis = new FileInputStream(file);
// //字节流转字符流,有一定要经过字节字符流转换操作,转换时可以指定编码
// //和文件格式编码要一致,否则会是乱码,这里默认UTF-8
// InputStreamReader isr = new InputStreamReader(fis);
// BufferedReader br = new BufferedReader(isr);
// String str ;
// while ((str = br.readLine()) != null) {
// System.out.println(str);
// }
// //关闭
// br.close();
// isr.close();
// fis.close();
//4.缓冲的字节输入流
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
//和之前的字节输入流操作类似 操作byte[]
byte[] bytes = new byte[1024];
int len = 0;
while ((len = bis.read(bytes)) != -1) {
String str = new String(bytes,0,len);
System.out.println(str);
}
bis.close();
}
}
注意:缓冲输出流PrintWriter() 输出完需要使用flush() 刷新缓冲区
- 练习1:把a-z换行输出到某个文件(需要考虑文件是否存在的问题)
import java.io.*;
public class FileOutput {
public static void main(String[] args) throws IOException {
//路径上没有该文件,new File不会报错,但是操作输入输出流会抛FileNotFountException
File file = new File("E:/tmp/1.txt");
//把a-z换行输出到某个文件,需要考虑文件是否存在的问题
if(!file.exists()){ //不存在就创建
file.createNewFile();
}
//类似输入的几种写法都是ok
// new FileWriter() 不带缓冲的字符输出流
// new FileOutputStream() 文件字节输出流
// new BufferedWriter() 带缓冲的字符输出流
// new PrintWriter()
//缓冲字符输出流
// BufferedWriter bw = new BufferedWriter(new FileWriter(file));
// bw.write("\n");
//打印输出流
//1.
// PrintWriter pw = new PrintWriter(new FileWriter(file));
//2.
PrintWriter pw = new PrintWriter(new FileOutputStream(file));
//快速打印a-z
for(int i='a'; i<='z'; i++){
pw.println((char)i);
}
pw.flush();
}
}
结果:
- 练习2:文件复制
import java.io.*;
public class FileCopy {
public static void main(String[] args) throws IOException {
//文件复制
File input = new File("E:\\360Downloads\\Software\\VisualStudioCommunity\\ch_zh_language.exe");
File output = new File("E:/tmp/vs.exe");
if(!output.exists()){
output.createNewFile();
}
//定义输入输出流
FileInputStream fis = new FileInputStream(input);
FileOutputStream fos = new FileOutputStream(output);
long start = System.currentTimeMillis(); //开始时间
byte[] bytes = new byte[1024*8];
int len;
//每次从输入流读取到byte[]的内容,直接输出到某个文件,就是复制
while((len = fis.read(bytes)) != -1){
fos.write(bytes, 0, len); //可能读满,可能未读满
}
long end = System.currentTimeMillis(); //结束时间
System.out.println(end-start);
fis.close();
fos.close();
//可以使用缓冲字节输入流、缓冲字节输出流来复制
// new BufferedInputStream(new FileInputStream())
// new BufferedOutputStream(new FileOutputStream())
}
}
序列化和反序列化
- 序列化:把Java对象转换为其他数据格式的过程。
- 反序列化:把其他数据转换为Java对象的过程。
序列化的使用:
- 把内存中的对象状态保存到一个文件中或者数据库的时候
- 用套接字在网络上传送对象的时候
实现序列化的方式:
- Java对象序列化
- JSON序列化
- XML
- Protobuf
- Hession(它基于HTTP协议传输,使用Hessian二进制序列化,对于数据包比较大的情况比较 友好。)
- Dubbo Serialization(阿里dubbo序列化)
- FST(高性能、序列化速度大概是JDK的4-10倍,大小是JDK大小的1/3左右)
深拷贝和浅拷贝
都是拷贝a对象为b对象(对象拷贝)
Java中的浅拷贝:对基本数据类型进行值传递,对引用数据类型进行引用传递般的拷贝。 要求类对象的类实现Clonable接口,使用clone() 复制 有一个缺陷:复杂属性是以复制引用的方式(简单属性回真实复制)
Java中的深拷贝:对基本数据类型进行值传递,对引用数据类型,创建一个新的对象,并复制其内容。
要求类对象的类实现Serializable接口