← 返回首页

Java NIO详解

📂 java ⏱ 3 min 519 words

什么是NIO

Java NIO(New IO)是JDK 1.4引入的非阻塞IO框架,提供了与标准IO不同的工作方式。NIO支持面向缓冲区的、基于通道的IO操作。

Buffer(缓冲区)

Buffer是数据容器,用于存储和操作数据。

import java.nio.ByteBuffer;
import java.nio.CharBuffer;

public class BufferDemo {
    public static void main(String[] args) {
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        System.out.println("容量: " + buffer.capacity());
        System.out.println("限制: " + buffer.limit());
        System.out.println("位置: " + buffer.position());

        buffer.put((byte) 'H');
        buffer.put((byte) 'e');
        buffer.put((byte) 'l');
        System.out.println("写入后位置: " + buffer.position());

        buffer.flip();
        System.out.println("flip后位置: " + buffer.position());
        System.out.println("flip后限制: " + buffer.limit());

        while (buffer.hasRemaining()) {
            System.out.print((char) buffer.get());
        }
        System.out.println();

        buffer.clear();
        System.out.println("clear后位置: " + buffer.position());
    }
}

Buffer类型

import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.DoubleBuffer;
import java.nio.IntBuffer;

public class BufferTypesDemo {
    public static void main(String[] args) {
        IntBuffer intBuffer = IntBuffer.allocate(10);
        intBuffer.put(10);
        intBuffer.put(20);
        intBuffer.put(30);
        intBuffer.flip();
        while (intBuffer.hasRemaining()) {
            System.out.print(intBuffer.get() + " ");
        }
        System.out.println();

        CharBuffer charBuffer = CharBuffer.wrap("Hello NIO");
        char[] chars = new char[5];
        charBuffer.get(chars, 0, 5);
        System.out.println(new String(chars));

        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(1024);
        System.out.println("Direct Buffer: " + byteBuffer.isDirect());
    }
}

Channel(通道)

Channel是NIO中用于IO操作的连接点。

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class ChannelDemo {
    public static void main(String[] args) {
        String source = "source.txt";
        String target = "target.txt";

        try (FileInputStream fis = new FileInputStream(source);
             FileOutputStream fos = new FileOutputStream(target);
             FileChannel inChannel = fis.getChannel();
             FileChannel outChannel = fos.getChannel()) {

            ByteBuffer buffer = ByteBuffer.allocate(1024);
            while (inChannel.read(buffer) != -1) {
                buffer.flip();
                outChannel.write(buffer);
                buffer.clear();
            }
            System.out.println("文件复制完成");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Scatter/Gather操作

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class ScatterGatherDemo {
    public static void main(String[] args) {
        try (FileOutputStream fos = new FileOutputStream("scatter.txt");
             FileChannel channel = fos.getChannel()) {

            ByteBuffer header = ByteBuffer.allocate(128);
            ByteBuffer body = ByteBuffer.allocate(1024);

            header.put("Header Content".getBytes());
            header.flip();

            body.put("Body Content".getBytes());
            body.flip();

            ByteBuffer[] buffers = {header, body};
            channel.write(buffers);

            System.out.println("Scatter写入完成");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

文件通道复制

import java.io.*;
import java.nio.channels.FileChannel;

public class FileChannelCopyDemo {
    public static void main(String[] args) {
        String source = "large_file.dat";
        String target = "copy_file.dat";

        try (FileInputStream fis = new FileInputStream(source);
             FileOutputStream fos = new FileOutputStream(target);
             FileChannel inChannel = fis.getChannel();
             FileChannel outChannel = fos.getChannel()) {

            long size = inChannel.size();
            long transferred = 0;

            while (transferred < size) {
                transferred += inChannel.transferTo(transferred, size - transferred, outChannel);
            }
            System.out.println("文件复制完成,大小: " + size + " bytes");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

内存映射文件

import java.io.*;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

public class MemoryMappedFileDemo {
    public static void main(String[] args) {
        String fileName = "mapped.txt";

        try (RandomAccessFile raf = new RandomAccessFile(fileName, "rw");
             FileChannel channel = raf.getChannel()) {

            MappedByteBuffer buffer = channel.map(
                FileChannel.MapMode.READ_WRITE, 0, 1024);

            buffer.put("Hello Memory Mapped File".getBytes());
            buffer.flip();

            byte[] data = new byte[buffer.remaining()];
            buffer.get(data);
            System.out.println("读取内容: " + new String(data));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

NIO文件操作

import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.List;
import java.util.stream.Stream;

public class NIOFileDemo {
    public static void main(String[] args) {
        Path path = Paths.get("test_dir");

        try {
            Files.createDirectories(path);
            System.out.println("目录创建成功");
        } catch (IOException e) {
            e.printStackTrace();
        }

        try {
            Files.createFile(path.resolve("file1.txt"));
            Files.createFile(path.resolve("file2.txt"));
            System.out.println("文件创建成功");
        } catch (IOException e) {
            e.printStackTrace();
        }

        try (Stream<Path> stream = Files.list(path)) {
            stream.forEach(System.out::println);
        } catch (IOException e) {
            e.printStackTrace();
        }

        try {
            Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
                    System.out.println("文件: " + file);
                    return FileVisitResult.CONTINUE;
                }
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

NIO vs IO

  1. 面向流 vs 面向缓冲:IO面向流,NIO面向缓冲区
  2. 阻塞 vs 非阻塞:IO是阻塞的,NIO支持非阻塞
  3. 选择器:NIO支持Selector实现多路复用

总结

Java NIO提供了更高效、更灵活的IO操作方式。理解Buffer、Channel和内存映射的概念,能帮助你构建高性能的IO密集型应用。