Java IO(Input/Output)是用于处理输入和输出操作的API,它允许程序与外部世界进行数据交互。
可以从三个不同的维度进行分类:
• 1、按照流的方向(输出输入都是站在程序所在内存的角度划分的)
• 输入流:只能从中读取数据【主要由InputStream和Reader作为基类】
• 输出流:只能向其写入数据【主要由outputStream和Writer作为基类】
• 2、按照流的操作颗粒度划分
• 字节流:以字节为单元,可操作任何数据【主要由InputStream和outPutStream作为基类】
• 字符流:以字符为单元,只能操作纯字符数据,比较方便【主要由Reader和Writer作为基类】
• 3、按照流的角色划分
• 节点流:可以从/向一个特定的IO设备(如磁盘,网络)读/写数据的流,也叫【低级流,主要由】
• 处理流:用于对一个已存在的流进行连接和封装,通过封装后的流来实现数据的读/写功能,也叫【高级流】
BufferedReader br = new BufferedReader(new FileReader("file.txt"));
这里,BufferedReader装饰了FileReader,以提供缓冲读取的功能。
Charset utf8 = Charset.forName("UTF-8");
CharsetEncoder encoder = utf8.newEncoder();
这里,Charset对象充当策略对象,CharsetEncoder则根据不同的策略来执行编码操作。
Path directory = Paths.get("my_directory");
WatchService watchService = FileSystems.getDefault().newWatchService();
directory.register(watchService, StandardWatchEventKinds.ENTRY_CREATE);
这里,WatchService充当观察者,监视文件系统中文件的创建事件。
Java NIO : 同步非阻塞,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。
Java BIO : 同步并阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。
Java AIO(NIO.2) : 异步非阻塞,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理。
同步I/O(Synchronous I/O):
阻塞模式: 在同步I/O中,当一个I/O操作被发起时,调用线程将被阻塞,直到操作完成或出错为止。这意味着线程会一直等待,无法执行其他任务。
顺序执行: 同步I/O操作通常是按照它们的发起顺序依次执行的。每个操作必须等待前一个操作完成才能继续执行。
资源占用: 同步I/O需要分配一个线程来处理每个I/O操作,如果有大量并发连接,将消耗大量线程资源。
异步I/O(Asynchronous I/O):
非阻塞模式: 在异步I/O中,当一个I/O操作被发起后,调用线程不会被阻塞,可以继续执行其他任务,不必等待操作完成。
并发性: 异步I/O允许同时发起多个I/O操作,并在后台进行处理,因此具有更高的并发性。
回调机制: 异步I/O通常使用回调函数来处理I/O操作完成的通知。当I/O操作完成时,系统会调用预先注册的回调函数,而不是等待线程。
复杂性: 异步I/O编程相对更复杂,因为它需要处理回调函数、状态管理等复杂性问题。
阻塞IO:当一个线程执行I/O操作时,它将一直阻塞该线程被一直占用,直到操作完成。
非阻塞IO:调用线程不会被阻塞,可以继续执行其他任务,不必等待操作完成。允许一个线程管理多个通道(连接)。
答:读字节流时,读一个字节后返回一个字节;字节流使用字节流读取一个或多个字节(中文对应的字节数为两个,在 UTF-8 码表中是 3 字节)时间。首先检查指定的编码表,并返回找到的字符。字节流可以处理图片、MP3、AVI视频文件等各种类型的数据,而字符流只能处理字符数据。除了字节流,只要是处理纯文本数据,就要优先使用字符流。字节流主要是操作 byte 类型数据,以 byte 以数组为准,主要操作类别为 OutputStream、Inputstream字符流处理的单元是 2 个字节的 Unicode 字符分别操作字符、字符数组或字符串,字节流处理单元为 1 操作字节和字节数组的字节。因此,字符流是由 Java 将字节转换为虚拟机 2 个字节的 Unicode 字符是单位字符制成的,所以对多国语言有很好的支持!如果是音频文件、图片和歌曲,最好使用字节流。如果与中文(文本)有关,最好使用字符流。在程序中,一个字符等于两个字节,java 提供了 Reader、Writer 两个专门操作字符流的类别。
答:
(1)按流量方向:输入流(inputStream)和输出流(outputStream);
(2)按实现功能划分:节点流(可以从或到特定的地方(节点)读写数据。如 FileReader)和处理流(是对现有流的连接和封装,通过封装流的功能调用实现数据读写。如 BufferedReader。处理流的结构方法总是以其他流对象为参数。一个流对象通过其他流多次包装,称为流链接);
(3)按处理数据的单位: 字节流和字符流。继承字节流 InputStream 和 OutputStrea,InputStreamreader继承字符流 和 OutputStreamWriter 。
答:字节输入流通字符输入流通 InputStreamReader 这种结构函数可以实现并传输 InputStream 对象。
字节输出流字符输出流通过 OutputStreamWriter 这种结构函数可以实现并传输 OutputStream 对象。
答:在 java 能够序列化的类必须先实现 Serializable 接口,没有抽象的方法,只是起到了标记作用。
public class Test {
public static void main(String[] args) throws Exception {
// 对象输出流
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(new File("D://obj")));
objectOutputStream.writeObject(new User("zhangsan", 100));
objectOutputStream.close();
// 对象输入流
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(new File("D://obj")));
User user = (User) objectInputStream.readObject();
System.out.println(user);
objectInputStream.close();
}
}
答:序列化是一种处理对象流的机制。所谓对象流,就是流化对象的内容。流化后的对象可以读写,也可以在网络之间传输。序列化是为了解决对象流读写操作中引起的问题。
答:实现序列化将需要实现序列化类Serializable 界面,界面没有实现的方法,implements Serializable 只是为了标记对象可以序列化,然后使用输出流(如:File Output Stream)来构造一个 Object Output Stream(对象流)对象,然后,使用 Object Output Stream 对象的 write Object(Object obj)该方法可以将参数为 obj 对象写出(即保存其状态),如果要恢复,则使用输入流。
答:Filter Stream是IO流的主要功能,用于为存在的流量增加一些额外的功能,如向目标文件添加源文件中不存在的行数或复制性能。
答:在http://java.主要由四个可用的filter包组成 Stream。两个字节filter stream,两个字符filter stream. 分别是Filter Input Stream, Filter Output Stream, Filter Reader and Filter Writer.这些类别是抽象的,不能实例化。
答:通过实现类 java.io.Serializable 该接口可以启用其序列化功能。未实现此接口的类别将无法使其任何状态序列化或反序列化。
答:有两种方式(1)实现 Cloneable 接口并重写 Object 类中的 clone()方法(2)实现 Serializable 接口可以通过对象的序列化和反序列化来实现真正的深度克隆。
输入流用于从数据源(如文件或网络)读取数据,输出流用于向目标(如文件或网络)写入数据。
分为字符流和字节流。
BIO(Blocking I/O):
阻塞模型: BIO是基于阻塞模型的I/O操作,意味着当一个线程执行I/O操作时,它将一直阻塞,直到操作完成。
同步性: 在BIO中,所有I/O操作都是同步的,一个线程对一个连接进行读或写,直到完成。
适用性: 适用于连接数量较少且每个连接的数据交互频繁的情况,但在高并发环境下性能不佳。
NIO(Non-blocking I/O):
非阻塞模型: NIO采用了非阻塞模型,允许一个线程管理多个通道(连接)。
选择器(Selector): NIO引入了选择器(Selector)的概念,通过选择器一个线程可以监听多个通道上的事件,如读就绪、写就绪等。
缓冲区(Buffer): NIO使用缓冲区来存储数据,可以提高I/O效率。
适用性: 适用于需要处理大量连接且连接数较多,但每个连接的数据交互相对较少的情况,如Web服务器。
AIO(Asynchronous I/O):
异步模型: AIO采用异步模型,允许一个线程在进行I/O操作时不被阻塞,当操作完成后会通知应用程序。
回调机制: AIO使用回调机制来处理I/O操作完成的通知。
适用性: 适用于需要处理大量连接且每个连接的数据交互较少,且希望充分利用CPU的多核性能的情况。
总结各种I/O模型的适用场景:
BIO适用于连接数较少,且每个连接的数据交互频繁的情况,但不适用于高并发环境。
NIO适用于需要处理大量连接,但每个连接的数据交互相对较少的情况,具有更好的性能和资源利用率。
AIO适用于需要处理大量连接,且每个连接的数据交互较少,同时希望充分利用CPU多核性能的情况。
选择适当的I/O模型取决于应用程序的特性和需求,不同的模型提供了不同的性能和可伸缩性。