1. I/O系统
I/O:
输入输出,其实就是一套API,通过它可以从硬盘、网络、键盘等地方读取数据,也可以将内容写入到硬盘、网络、屏幕等地方。
I/O是程序获取和交换数据的主要渠道,I/O很容易成为性能瓶颈。
Java在I/O上一直在做持续的优化,1.4开始引入了非阻塞I0(NIO,其实网络IO是同步非阻塞的,文件IO依旧是同步阻塞的),1.7引入了异步IO(AIO)
-
IO:
同步阻塞的BIO
BIO是面向流的、阻塞式的、串行的一个过程。
阻塞是线程的一种状态,当线程执行了IO相关的读写方法后,在操作系统处理IO前,当前线程是否可以继续向下执行。
(比如:程序请求资源时主线程会停下来,此时即为阻塞状态。)同步是指线程是否需要主动的去获取读写的结果。
(当线程为阻塞状态时,程序会等待资源的响应。)不管是磁盘I/O还是网络I/O数据在写入OutputStream或者从InputStream读取时都有可能会发生阻塞,一旦有线程阻塞将会失去CPU的使用权,而且线程占用的资源不能被释放,大量浪费了CPU和线程占用的内存资源。
-
NIO:
同步非阻塞的NIO
BIO中的阻塞是指当需要有20个资源请求时,需要有对应的20个线程;非阻塞是指资源请求时主线程不会停下来,而是当有响应时来调用一个方法
常用工具类
1)File
对文件或目录进行一系列描述或者操作以及读取文件的属性(即是否存在)。
//小括号中的路径可以是相对路径也可以是绝对路径
File file = new File("f:/test.txt"|"test.txt");
相关方法
getName 获取文件名
createNewFile 新建文件
delete 删除文件
length 文件大小
2)Path
表示、解析文件或目录的路径。
Path是一个接口。
//小括号中的路径可以是相对路径也可以是绝对路径。
Path path = Paths.get("f:/test.txt"|"test.txt");
3)Files
对文件或目录进行一系列操作,读取文件的属性以及读写文件内容。
//判断是否是可执行文件,如.exe
Files.isExecutable(path);
2. IO流
流是一组有序的、有起点和终点的字节集合,是对数据传输的总称或抽象。
分类
-
按流向分:输入流、输出流
-
按功能分:节点流、处理流
-
按单位分:字节流、字符流
字节输入流
InputStream
该抽象类是表示字节输入流的所有类的超类。
读取方法有read
使用完需要用close方法
FileInputStream
关于读取文件的一个类,可以从文件系统中的某个文件中获得原始字节流。
//只负责提供字节数据
FileInputStream in = new FileInputStream(path);
int content = 0;
//此时用do while循环结构是最合适的
try{
do{
content = in.read(); //通过read方法返回字节,-1表示读取结束
}while(content!=-1);
}finally{
//保证资源一定会被关闭
in.close();
}
字节输出流
OutputStream
该抽象类是表示输出字节流的所有类的超类;
FileOutputStream
关于写出字节流文件的一个类。
示例:
//使用字节流写入一个文件
OutputStream out = new FileOutputStream("d:/demos.txt",true);//true表示追加写入
String content = "你好";
out.write(content.getBytes("utf-8"));
out.flush();
out.close();
字符输入流
如果读取的是字节文件,则需要用二进制流,即字节输入/输出流(InputStream、OutputStream)
如果读取的是字符文件,就可以直接使用字符流,如Writer
Reader
InputStreamReader(适配器模式)
是字节流通向字符流的桥梁,可以使用指定的字符编码将字节文件解码为对应的字符
FileReader
BufferedReader
//InputStreamReader可以指定字符编码
Reader reader = new InputStreamReader(new FileInputStream,charset);
//FileReader默认字符编码,打印的是Unicode字符编号
FileReader fileReader = new FileReader(fileName);
//BufferedReader
BufferedReader bur = new BufferedReader(new FileReader(fileName));
BufferedReader bur = new BufferedReader(new InputStreamReader(new FileInputStream(fileName));
获取默认字符编码
Charset.defaultCharset().name()
字符输出流
Writer
写入字符流的抽象类
OutputStreamWriter
适配器模式,是字符流通向字节流的桥梁,可以使用指定的charset将要写入流中的字符编码成字节
FileWriter
用于写入字符文件的便捷类
BufferedWriter
缓冲流,装饰者模式
PrintWriter
是一种过滤流,也叫处理流,可以对字节流和字符流进行处理,
可以在传入Writer时指定字符编码
public class Sample {
public static void main(String[] args) throws IOException{
//可以在传入Writer时指定字符编码,true表示刷新缓存
PrintWriter writer =
new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(filePath),utf-8)),true);
//不换行不刷新缓存
writer.print("不换行不刷新");
//换行刷新缓存
writer.println("换行刷新");
}
}
示例:
1.字节流复制文件
public static void copy1() throws IOException{
//1.创建字节文件输入流、输出流
InputStream in = new FileInputStream(infilepath);
OutputStream out = new FileOutputStream(outfilePath)''
//2.读、写
byte[] buf = new byte[1024*4]; //4g
int length = 0;
while((length=in.read(buf)!=-1){
//buf缓冲区,0指从第一个位置写,length是写的长度
out.write(buf,0,length);
}
//3.关闭
in.close();
out.close();
}
2.字符流复制文件
public static void copy2(){
//1.创建字符文件的输入流、输出流
Reader reader = new FileReader(readFilePath);
Writer writer = new FileWriter(writeFilePath);
//2.读写
char[] buf = new char[1024*4];
int length = 0;
while((length=reader.read(buf)!=-1){
writer.write(buf,0,length);
}
//3.关闭
reader.close();
writer.flush();//刷新
writer.close();
}
字节流和字符流的区别
字节流读取二进制数据文件,其实是可以读取任何形式的文件。
字符流读取字符文件,可以多行读取。
对象流
ObjectInputStream:对象输入流;(反序列化)
ObjectOutputStream:对象输出流;(序列化)
对象序列化
是指将内存中的对象转换为可以输出的二进制格式,主要用于对象传输和对象持久化,这个过程的逆向操作称为反序列化。
注意:
序列化的对象所属的类必须实现Serializable接口
序列化会传递一个序列化ID,在反序列化时会对比两个序列化ID如果不一致则不会进行按序列化操作。
示例:
class Demo{
public static void main(String[] args){
method();
method2();
}
//通过ObjectInputStream进行反序列化
public static void readPerson(){
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(path));
Person person = (Person)ois.readObject();
}
//通过ObjectOutputStream进行序列化
public static void writePerson(){
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(path);
oos.writeObject(new Person());
}
}
//该类需要实现Serializable接口
class Person implements Serializable{
private static int age = 100;
private static String name = null;
public Person(int age,String name){
this.age = age;
this.name = name;
}
}
过滤流
【装饰者模式】
过滤输入流BufferedInputStream
示例:使用缓存输入流读取二进制数据
/**
* 如果不使用缓冲流,则每次调用read方法都会从硬盘中读取数据,
* 而使用了缓冲流则会 一次性读取8921个字节放入缓存,read方法只是在获取缓存中的数据
* 缓存数据不够时才回去硬盘中读取数据
* */
public class Sample1{
public static void readForByte() throws IOException {
BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream("filePath"));
int content = 0;
do {
content = inputStream.read();
//转换为字节
System.out.println(Integer.toBinaryString(content));
} while (content != -1);
}
}
过滤输出流BufferedOutputStream
public class Sample2{
public static void readForByte() throws IOException {
//true表示是内容否追加
BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream("filePath",true));
//转为字节,且字符编码为utf-8
outputStream.write("需要写出的内容".getBytes(StandardCharsets.UTF_8));
//刷新
outputStream.flush();
//关闭
outputStream.close();
字符缓冲流
BufferedReader
public class Sample3{
public static void readForByte() throws IOException {
BufferedReader reader = new BufferedReader(new FileReader("filePath"));
String contents = null;
do {
contents = reader.readLine();
} while (contents != null);
}
}
BufferedWrier
public class Sample3{
public static void readForByte() throws IOException {
BufferedWriter writer = new BufferedWriter(new FileWriter("filePath"));
writer.write("需要写出的内容");
//刷新、关闭
writer.flush();
writer.close();
}
}