Java基础篇7
一、概览
java的I/O大概分成以下几类:
- 磁盘操作:File;
- 字节操作:InputStream 和 OutputStream;
- 字符操作:Reader 和 Writer;
- 对象操作:Serializable;
- 网络操作:Socket;
- 新的输入/输出:NIO。
二、磁盘操作
File类用于表示文件和目录的信息,但是不表示文件的内容(类似指针)。
三、字节操作
// 注意相对路径的起始位置:src目录开始
public static void copyFile(String src, String dist) throws IOException{
// 不接收File对象也行
FileInputStream in = new FileInputStream(src);
FileOutputStream out = new FileOutputStream(dist);
byte[] buffer = new byte[20*1024];
int cnt;
// eof表示文件尾
while((cnt = in.read(buffer, 0, buffer.length)) != -1){
out.write(buffer, 0, cnt);
}
in.close();
out.close();
}
I/O使用装饰者模式(允许向一个现有的对象添加新功能,同时不改变其结构)来实现。对于InputStream:
FileInputStream为InputStream的子类,提供了字节流的输入操作;
FilterInputStream为抽象装饰者,装饰者用于装饰组件,并为组件提供额外的功能。使用时,只需要在外层套上一层装饰组件即可。
FileInputStream fileInputStream = new FileInputStream(filePath);
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
四、字符操作
编码与解码
编码把字符转换为字节,而解码是把字节重新组合成字符。
Unicode标准只规定代码点对应的字符,没有规定代码点该怎么存储(UTF系列为具体实现方式)
GBK编码中,中文字符占2个字节,英文占1字节;
UTF-8中,中文编码占3-4字节,英文占1字节;
UTF-16中,中文占3-4字节,英文占2字节;
UTF-32中,任何字符都占4字节。
Java内存编码使用的是UTF-16be(大端),中文英文都占用2字节(一个char空间)。
程序中的操作一般是字符形式的数据,因此需要提供对字符操作的方法:
- InputStreamReader 实现从字节流解码成字符流;
- OutputStreamWriter 实现字符流编码为字节流。
五、对象操作
序列化就是将一个对象转换成字节序列,方便存储和传输。
序列化: ObjectOutputStream.writeObject();
反序列化:ObjectInputStream.readObject()。
自定义类如果需要支持序列化,需要实现Serializable接口(一个标准,无实现方法需要实现)。
private static class A implements Serializable{
private int x;
private String y;
A(int x, String y){
this.x = x;
this.y = y;
}
@Override
public String toString() {
return "A{" +
"x=" + x +
", y='" + y + '\'' +
'}';
}
}
public static void main(String[] args) throws IOException, ClassNotFoundException {
A a1 = new A(12, "ba");
String objectFile = "src\\basement\\foundation\\IOtest\\file\\a1_object";
// 将对象序列化并写入文件(顺序相反?)
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(objectFile));
objectOutputStream.writeObject(a1);
objectOutputStream.close();
// 从文件读取并反序列化
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(objectFile));
A a2 = (A) objectInputStream.readObject();
objectInputStream.close();
System.out.println(a2);
}
使类中的某一些属性不被序列化的方法:添加 transient关键字。
六、网络操作
Java 中网络的支持方式:
- InetAddress:用于表示网络上的硬件资源,即IP;
- URL:统一资源定位符;
- Socket:使用TCP协议实现网络通信;(客户端服务器端使用InputStream与OutputStream进行输入输出)
- Datagram:使用UDP协议实现网络通信。
七、新的输入/输出
于JDK1.4引入,提供了高速的、面向块的I/O。
两者的区别
I/O以流的方式处理数据,而NIO以块的方式处理数据,并且NIO是非阻塞的。
通道与缓冲区
通道是双向的,可以同时用于读写,流是单向的,只能在一个方向上移动。需要注意的是,不能直接对通道进行数据的读写,需要缓冲区来保存数据。
通道类型
- FileChannel:从文件中读写;
- DatagramChannel:通过UDP读写;
- SocketChannel:通过TCP读写;
- ServerSocketChannel:监听新进来的TCP连接,对每一个进来的连接创建一个SocketChannel。
同步与异步(本人询问,老板回复的方式)
同步:如果有多个任务或事件要发生,这些任务或事件必须逐个执行,一个任务或事件的执行会导致整个流程的暂时等待。
异步:事件可以并发地执行,一个任务或事件的执行不会导致整个流程的暂时等待。
同步和异步关注的是消息的通信机制。
对于同步IO:用户发出IO请求操作后,如果数据没有就绪,需要通过用户线程或者内核不断地轮询数据是否就绪,当数据就绪时,再将数据内核拷贝到用户线程;
对于异步IO:只有IO请求操作的发出是由用户线程进行的,IO操作的两个阶段都由内核自动完成(两个阶段都能干别的事情),然后告知用户线程操作已经完成。
同步IO与异步IO的关键区别反映在数据拷贝阶段是由用户线程完成还是由内核来完成。
阻塞与非阻塞(本人后续的操作)
阻塞:当某个任务或事件在执行过程中,发出一个请求操作,但是由于该操作需要的条件不满足,就会一直在那里等待,直到条件满足。
非阻塞:当某个任务或事件在执行过程中,发出一个请求操作,但是由于该操作需要的条件不满足,就会立即返回一个标志信息告知不满足,不会进行等待。
阻塞和非阻塞关注的是程序在等待调用结果时的状态。
对于一个IO请求,一般包括两个阶段:
- 查看数据是否就绪;
- 进行数据的拷贝(内核将数据拷贝到用户线程)。
阻塞IO与非阻塞IO的区别在于第一个阶段,阻塞会一直等待,非阻塞则直接返回标志信息。