大家好,我是哪吒。
很多朋友问我,如何才能学好IO流,对各种流的概念,云里雾里的,不求甚解。用到的时候,现百度,功能虽然实现了,但是为什么用这个?不知道。更别说效率问题了~
下次再遇到,再百度,“良性循环”。
今天,我就用一天的时间,整理一下关于Java I/O流的知识点,分享给大家。
每一种IO流,都配有示例代码,大家可以跟着敲一遍,找找感觉~
本篇文章介绍Java NIO以及其它的各种奇葩流。
Java NIO (New I/O) 是 Java 1.4 引入的,在 Java 7 中又进行了一些增强。NIO 可以提高 I/O 操作的效率,它的核心是通道 (Channel) 和缓冲区 (Buffer)。
Channel 是一种新的 I/O 抽象,它与传统的 InputStream 和 OutputStream 不同,Channel 可以同时进行读和写操作,而且可以对其进行更细粒度的控制。Java NIO 中最基本的 Channel 包括:
使用FileChannel从源文件中读取内容并将其写入到目标文件。
import java.io.FileInputStream; // 引入 FileInputStream 类import java.io.FileOutputStream; // 引入 FileOutputStream 类import java.nio.ByteBuffer; // 引入 ByteBuffer 类import java.nio.channels.FileChannel; // 引入 FileChannel 类public class FileChannelExample { public static void main(String[] args) { String sourceFile = "source.txt"; String targetFile = "target.txt"; try { // 使用 FileInputStream 和 FileOutputStream 打开源文件和目标文件 FileInputStream fileInputStream = new FileInputStream(sourceFile); FileOutputStream fileOutputStream = new FileOutputStream(targetFile); // 获取 FileChannel 对象 FileChannel sourceChannel = fileInputStream.getChannel(); FileChannel targetChannel = fileOutputStream.getChannel(); // 创建 ByteBuffer 对象 ByteBuffer buffer = ByteBuffer.allocate(1024); // 从源文件中读取内容并将其写入目标文件 while (sourceChannel.read(buffer) != -1) { buffer.flip(); // 准备写入(flip buffer) targetChannel.write(buffer); // 向目标文件写入数据 buffer.clear(); // 缓冲区清空(clear buffer) } // 关闭所有的 FileChannel、FileInputStream 和 FileOutputStream 对象 sourceChannel.close(); targetChannel.close(); fileInputStream.close(); fileOutputStream.close(); // 打印成功信息 System.out.println("文件复制成功!"); } catch (Exception e) { e.printStackTrace(); } }}
用于 UDP 协议的数据读写操作。
使用DatagramChannel从一个端口读取数据并将数据发送到另一个端口。
import java.io.IOException; // 引入 IOException 类import java.InetSocketAddress; // 引入 InetSocketAddress 类import java.nio.ByteBuffer; // 引入 ByteBuffer 类import java.nio.channels.DatagramChannel; // 引入 DatagramChannel 类public class DatagramChannelExample { public static void main(String[] args) { int receivePort = 8888; int sendPort = 9999; try { // 创建 DatagramChannel 对象 DatagramChannel receiveChannel = DatagramChannel.open(); // 绑定接收端口 receiveChannel.socket().bind(new InetSocketAddress(receivePort)); System.out.println("接收端口 " + receivePort + " 正在等待数据..."); // 创建数据缓冲区对象 ByteBuffer receiveBuffer = ByteBuffer.allocate(1024); // 从 receiveChannel 接收数据 receiveChannel.receive(receiveBuffer); // 显示收到的数据 System.out.println("收到的数据是:" + new String(receiveBuffer.array())); // 关闭 receiveChannel 对象 receiveChannel.close(); // 创建 DatagramChannel 对象 DatagramChannel sendChannel = DatagramChannel.open(); // 创建数据缓冲区对象 ByteBuffer sendBuffer = ByteBuffer.allocate(1024); // 向数据缓冲区写入数据 sendBuffer.clear(); sendBuffer.put("Hello World".getBytes()); sendBuffer.flip(); // 发送数据到指定端口 sendChannel.send(sendBuffer, new InetSocketAddress("localhost", sendPort)); System.out.println("数据已发送到端口 " + sendPort); // 关闭 sendChannel 对象 sendChannel.close(); } catch (IOException e) { e.printStackTrace(); } }}
用于 TCP 协议的数据读写操作。
下面是一个简单的示例,演示如何使用 SocketChannel 和 ServerSocketChannel 进行基本的 TCP 数据读写操作。
import java.InetSocketAddress;import java.nio.ByteBuffer;import java.nio.channels.ServerSocketChannel;import java.nio.channels.SocketChannel;public class TCPExample { public static void main(String[] args) throws Exception { // 创建 ServerSocketChannel 并绑定端口 ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.socket().bind(new InetSocketAddress(8888)); serverSocketChannel.configureBlocking(false); // 创建一个 ByteBuffer 用于接收数据 ByteBuffer buf = ByteBuffer.allocate(1024); // 等待客户端连接 while (true) { SocketChannel socketChannel = serverSocketChannel.accept(); if (socketChannel != null) { // 客户端已连接,从 SocketChannel 中读取数据 int bytesRead = socketChannel.read(buf); while (bytesRead != -1) { // 处理读取到的数据 System.out.println(new String(buf.array(), 0, bytesRead)); // 清空 ByteBuffer,进行下一次读取 buf.clear(); bytesRead = socketChannel.read(buf); } } } }}
示例代码说明:
需要注意的点:
如果想要向客户端发送数据,可以使用以下代码:
// 创建一个 ByteBuffer 用于发送数据ByteBuffer buf = ByteBuffer.wrap("Hello, world!".getBytes());// 向客户端发送数据socketChannel.write(buf);
Buffer 是一个对象,它包含一些要写入或要读出的数据。在 NIO 中,Buffer 可以被看作为一个字节数组,但是它的读取和写入操作比直接的字节数组更加高效。NIO 中最常用的 Buffer 类型包括:
字节缓冲区,最常用的缓冲区类型,用于对字节数据的读写操作。
import java.nio.ByteBuffer;public class ByteBufferExample { public static void main(String[] args) { // 创建一个新的字节缓冲区,初始容量为10个字节 ByteBuffer buffer = ByteBuffer.allocate(10); // 向缓冲区中写入4个字节 buffer.put((byte) 1); buffer.put((byte) 2); buffer.put((byte) 3); buffer.put((byte) 4); // 输出缓冲区中的内容 buffer.flip(); // 将缓冲区切换成读模式 System.out.println(buffer.get()); // 输出1 System.out.println(buffer.get()); // 输出2 System.out.println(buffer.get()); // 输出3 System.out.println(buffer.get()); // 输出4 // 将缓冲区清空并重新写入数据 buffer.clear(); buffer.put((byte) 5); buffer.put((byte) 6); buffer.put((byte) 7); buffer.put((byte) 8); // 输出缓冲区中的内容,方法同上 buffer.flip(); System.out.println(buffer.get()); // 输出5 System.out.println(buffer.get()); // 输出6 System.out.println(buffer.get()); // 输出7 System.out.println(buffer.get()); // 输出8 }}
示例代码说明:
字符缓冲区,用于对字符数据的读写操作。
import java.nio.CharBuffer;public class CharBufferExample { public static void main(String[] args) { // 创建一个新的字符缓冲区,初始容量为10个字符 CharBuffer buffer = CharBuffer.allocate(10); // 向缓冲区中写入4个字符 buffer.put('a'); buffer.put('b'); buffer.put('c'); buffer.put('d'); // 输出缓冲区中的内容 buffer.flip(); // 将缓冲区切换成读模式 System.out.println(buffer.get()); // 输出a System.out.println(buffer.get()); // 输出b System.out.println(buffer.get()); // 输出c System.out.println(buffer.get()); // 输出d // 将缓冲区清空并重新写入数据 buffer.clear(); buffer.put('e'); buffer.put('f'); buffer.put('g'); buffer.put('h'); // 输出缓冲区中的内容,方法同上 buffer.flip(); System.out.println(buffer.get()); // 输出e System.out.println(buffer.get()); // 输出f System.out.println(buffer.get()); // 输出g System.out.println(buffer.get()); // 输出h }}
示例代码说明:
import java.nio.*;public class BasicBufferExample { public static void main(String[] args) { // 创建各种基本数据类型的缓冲区,初始容量为10 ShortBuffer shortBuf = ShortBuffer.allocate(10); IntBuffer intBuf = IntBuffer.allocate(10); LongBuffer longBuf = LongBuffer.allocate(10); FloatBuffer floatBuf = FloatBuffer.allocate(10); DoubleBuffer doubleBuf = DoubleBuffer.allocate(10); // 向缓冲区中写入数据 shortBuf.put((short) 1); intBuf.put(2); longBuf.put(3L); floatBuf.put(4.0f); doubleBuf.put(5.0); // 反转缓冲区,切换到读模式 shortBuf.flip(); intBuf.flip(); longBuf.flip(); floatBuf.flip(); doubleBuf.flip(); // 读取缓冲区中的数据 System.out.println(shortBuf.get()); // 输出1 System.out.println(intBuf.get()); // 输出2 System.out.println(longBuf.get()); // 输出3 System.out.println(floatBuf.get()); // 输出4.0 System.out.println(doubleBuf.get()); // 输出5.0 }}
示例代码说明:
Selector 是 Java NIO 类库中的一个重要组件,它用于监听多个 Channel 的事件。在一个线程中,通过 Selector 可以监听多个 Channel 的 IO 事件,并实现了基于事件响应的架构。Selector 可以让单个线程处理多个 Channel,因此它可以提高多路复用的效率。
import java.io.IOException;import java.InetSocketAddress;import java.nio.ByteBuffer;import java.nio.channels.*;import java.util.Iterator;import java.util.Set;public class SelectorExample { public static void main(String[] args) throws IOException { // 创建一个ServerSocketChannel,监听本地端口 ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.socket().bind(new InetSocketAddress("localhost", 8080)); serverSocketChannel.configureBlocking(false); // 创建一个Selector,并将serverSocketChannel注册到Selector上 Selector selector = Selector.open(); serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); System.out.println("Server started on port 8080"); while (true) { // 如果没有任何事件发生,则阻塞等待 selector.select(); // 处理事件 Set<SelectionKey> selectedKeys = selector.selectedKeys(); Iterator<SelectionKey> keyIterator = selectedKeys.iterator(); while (keyIterator.hasNext()) { SelectionKey key = keyIterator.next(); if (key.isAcceptable()) { // 处理新的连接请求 ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel(); SocketChannel clientChannel = serverChannel.accept(); clientChannel.configureBlocking(false); System.out.println("Accepted connection from " + clientChannel.getRemoteAddress()); clientChannel.register(selector, SelectionKey.OP_READ); } else if (key.isReadable()) { // 处理读事件 SocketChannel clientChannel = (SocketChannel) key.channel(); ByteBuffer buffer = ByteBuffer.allocate(1024); int bytesRead = clientChannel.read(buffer); String message = new String(buffer.array(), 0, bytesRead); System.out.println("Received message from " + clientChannel.getRemoteAddress() + ": " + message); // 回写数据 ByteBuffer outputBuffer = ByteBuffer.wrap(("Echo: " + message).getBytes()); clientChannel.write(outputBuffer); } // 从待处理事件集合中移除当前事件 keyIterator.remove(); } } }}
ZipInputStream 和 ZipOutputStream 可以用于处理 ZIP 文件格式,ZipInputStream 可以从 ZIP 文件中读取数据,ZipOutputStream 可以向 ZIP 文件中写入数据。
import java.io.*;import java.util.zip.ZipEntry;import java.util.zip.ZipOutputStream;public class ZipExample { public static void main(String[] args) throws IOException { // 输入文件路径和输出压缩文件路径 String inputFile = "/path/to/input/file"; String outputFile = "/path/to/output/file.zip"; // 创建ZipOutputStream,并设置压缩级别 ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(outputFile)); zipOutputStream.setLevel(9); // 读取需要压缩的文件到文件输入流 FileInputStream fileInputStream = new FileInputStream(inputFile); BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream); // 设置压缩文件内部的名称 ZipEntry zipEntry = new ZipEntry(inputFile); zipOutputStream.putNextEntry(zipEntry); // 写入压缩文件 byte[] buf = new byte[1024]; int len; while ((len = bufferedInputStream.read(buf)) > 0) { zipOutputStream.write(buf, 0, len); } bufferedInputStream.close(); zipOutputStream.closeEntry(); zipOutputStream.close(); System.out.println("File compressed successfully"); }}
示例代码说明:
import java.io.*;import java.util.zip.ZipEntry;import java.util.zip.ZipInputStream;public class UnzipExample { public static void main(String[] args) throws IOException { // 输入压缩文件路径和输出文件路径 String inputFile = "/path/to/input/file.zip"; String outputFile = "/path/to/output/file"; // 创建ZipInputStream ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(inputFile)); // 循环读取压缩文件中的条目 ZipEntry zipEntry = zipInputStream.getNextEntry(); while (zipEntry != null) { // 如果是目录,则创建空目录 if (zipEntry.isDirectory()) { new File(outputFile + File.separator + zipEntry.getName()).mkdirs(); } else { // 如果是文件,则输出文件 FileOutputStream fileOutputStream = new FileOutputStream(outputFile + File.separator + zipEntry.getName()); byte[] buf = new byte[1024]; int len; while ((len = zipInputStream.read(buf)) > 0) { fileOutputStream.write(buf, 0, len); } fileOutputStream.close(); } zipInputStream.closeEntry(); zipEntry = zipInputStream.getNextEntry(); } zipInputStream.close(); System.out.println("File uncompressed successfully"); }}
示例代码说明:
GZIPInputStream 和 GZIPOutputStream 可以用于进行 GZIP 压缩,GZIPInputStream 可以从压缩文件中读取数据,GZIPOutputStream 可以将数据写入压缩文件中。
import java.io.*;import java.util.zip.GZIPOutputStream;public class GzipExample { public static void main(String[] args) throws IOException { // 输入文件路径和输出压缩文件路径 String inputFile = "/path/to/input/file"; String outputFile = "/path/to/output/file.gz"; // 创建GZIPOutputStream,并设置压缩级别 GZIPOutputStream gzipOutputStream = new GZIPOutputStream(new FileOutputStream(outputFile)); gzipOutputStream.setLevel(9); // 读取需要压缩的文件到文件输入流 FileInputStream fileInputStream = new FileInputStream(inputFile); BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream); // 写入压缩文件 byte[] buf = new byte[1024]; int len; while ((len = bufferedInputStream.read(buf)) > 0) { gzipOutputStream.write(buf, 0, len); } bufferedInputStream.close(); gzipOutputStream.close(); System.out.println("File compressed successfully"); }}
示例代码说明:
import java.io.*;import java.util.zip.GZIPInputStream;public class GunzipExample { public static void main(String[] args) throws IOException { // 输入压缩文件路径和输出文件路径 String inputFile = "/path/to/input/file.gz"; String outputFile = "/path/to/output/file"; // 创建GZIPInputStream GZIPInputStream gzipInputStream = new GZIPInputStream(new FileInputStream(inputFile)); // 输出文件 FileOutputStream fileOutputStream = new FileOutputStream(outputFile); byte[] buf = new byte[1024]; int len; while ((len = gzipInputStream.read(buf)) > 0) { fileOutputStream.write(buf, 0, len); } gzipInputStream.close(); fileOutputStream.close(); System.out.println("File uncompressed successfully"); }}
示例代码说明:
ByteArrayInputStream 和 ByteArrayOutputStream 分别是 ByteArrayInputStream 和 ByteArrayOutputStream 类的子类,它们可以用于对字节数组进行读写操作。
import java.io.ByteArrayInputStream;import java.io.ByteArrayInputStream;import java.io.IOException;public class ByteArrayInputStreamExample { public static void main(String[] args) throws IOException { // 用字符串初始化一个字节数组,作为输入数据源 String input = "Hello, world!"; byte[] inputBytes = input.getBytes(); // 创建一个ByteArrayInputStream,使用输入数据源 ByteArrayInputStream inputStream = new ByteArrayInputStream(inputBytes); // 读取并输出输入流中的数据 byte[] buf = new byte[1024]; int len; while ((len = inputStream.read(buf)) != -1) { System.out.println(new String(buf, 0, len)); } // 关闭输入流 inputStream.close(); }}
示例代码说明:
import java.io.ByteArrayOutputStream;import java.io.IOException;public class ByteArrayOutputStreamExample { public static void main(String[] args) { String input = "Hello World!"; ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); byte[] output; try { outputStream.write(input.getBytes()); output = outputStream.toByteArray(); System.out.println(new String(output)); } catch (IOException e) { System.out.println("Error: " + e.getMessage()); } finally { try { outputStream.close(); } catch (IOException e) { System.out.println("Error: " + e.getMessage()); } } }}
示例代码说明:
本文为您讲解了 Java I/O、NIO 以及其他一些流的基本概念、用法和区别。Java I/O 和 NIO 可以完成很多复杂的输入输出操作,包括文件操作、网络编程、序列化等。其他流技术可以实现压缩、读写字节数组等功能。在进行开发时,根据具体需求选择不同的流技术可以提高程序效率和开发效率。
本文转载自微信公众号「哪吒编程」,可以通过以下二维码关注。转载本文请联系哪吒编程公众号。
本文链接:http://www.28at.com/showinfo-26-150-0.html一文搞定Java NIO,以及各种奇葩流
声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com