流与NIO

本课学习Java的流式IO和NIO,了解更底层的文件操作方式。

IO流体系

TEXT
输入流(读取)
InputStream(字节输入流)
├── FileInputStream(文件)
├── BufferedInputStream(缓冲)
├── ByteArrayInputStream(字节数组)
└── DataInputStream(基本类型)

Reader(字符输入流)
├── FileReader(文件)
├── BufferedReader(缓冲)
└── InputStreamReader(转换)

输出流(写入)
OutputStream(字节输出流)
├── FileOutputStream(文件)
├── BufferedOutputStream(缓冲)
└── DataOutputStream(基本类型)

Writer(字符输出流)
├── FileWriter(文件)
├── BufferedWriter(缓冲)
└── OutputStreamWriter(转换)

字节流

FileInputStream读取

JAVA
import java.io.FileInputStream;
import java.io.IOException;

public class FileInputStreamDemo {
    public static void main(String[] args) {
        try (FileInputStream fis = new FileInputStream("test.txt")) {
            int data;
            while ((data = fis.read()) != -1) {
                System.out.print((char) data);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

FileOutputStream写入

JAVA
import java.io.FileOutputStream;
import java.io.IOException;

public class FileOutputStreamDemo {
    public static void main(String[] args) {
        try (FileOutputStream fos = new FileOutputStream("output.txt")) {
            String text = "Hello, World!";
            fos.write(text.getBytes());
            System.out.println("写入成功");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

示例:字节流复制文件

JAVA
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class ByteCopy {
    public static void copy(String src, String dest) throws IOException {
        try (FileInputStream fis = new FileInputStream(src);
             FileOutputStream fos = new FileOutputStream(dest)) {
            
            byte[] buffer = new byte[1024];
            int length;
            while ((length = fis.read(buffer)) != -1) {
                fos.write(buffer, 0, length);
            }
        }
    }
    
    public static void main(String[] args) {
        try {
            copy("source.txt", "dest.txt");
            System.out.println("复制完成");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
▶ 试一试

缓冲流

缓冲流提高IO效率,减少磁盘访问次数。

BufferedInputStream/BufferedOutputStream

JAVA
import java.io.*;

public class BufferedStreamDemo {
    public static void main(String[] args) throws IOException {
        // 写入
        try (BufferedOutputStream bos = new BufferedOutputStream(
                new FileOutputStream("buffered.txt"))) {
            for (int i = 0; i < 1000; i++) {
                bos.write(("Line " + i + "\n").getBytes());
            }
        }
        
        // 读取
        try (BufferedInputStream bis = new BufferedInputStream(
                new FileInputStream("buffered.txt"))) {
            byte[] buffer = new byte[1024];
            int length;
            while ((length = bis.read(buffer)) != -1) {
                System.out.write(buffer, 0, length);
            }
        }
    }
}

数据流

DataInputStream/DataOutputStream可以读写基本类型。

示例:数据流

JAVA
import java.io.*;

public class DataStreamDemo {
    public static void main(String[] args) throws IOException {
        // 写入
        try (DataOutputStream dos = new DataOutputStream(
                new FileOutputStream("data.dat"))) {
            dos.writeInt(100);
            dos.writeDouble(3.14);
            dos.writeUTF("Hello");
        }
        
        // 读取
        try (DataInputStream dis = new DataInputStream(
                new FileInputStream("data.dat"))) {
            int i = dis.readInt();
            double d = dis.readDouble();
            String s = dis.readUTF();
            
            System.out.println("int: " + i);      // 100
            System.out.println("double: " + d);    // 3.14
            System.out.println("string: " + s);    // Hello
        }
    }
}
▶ 试一试

NIO(New IO)

Java NIO提供更高效的IO操作。

Path接口

JAVA
import java.nio.file.Path;
import java.nio.file.Paths;

public class PathDemo {
    public static void main(String[] args) {
        Path path = Paths.get("/home/user/test.txt");
        
        System.out.println("文件名:" + path.getFileName());  // test.txt
        System.out.println("父目录:" + path.getParent());    // /home/user
        System.out.println("根目录:" + path.getRoot());      // /
        System.out.println("路径数:" + path.getNameCount());  // 3
    }
}

Files工具类

JAVA
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;

public class FilesDemo {
    public static void main(String[] args) throws IOException {
        Path path = Paths.get("test.txt");
        
        // 判断
        System.out.println("是否存在:" + Files.exists(path));
        System.out.println("是否是文件:" + Files.isRegularFile(path));
        System.out.println("是否可读:" + Files.isReadable(path));
        
        // 读取所有行
        List<String> lines = Files.readAllLines(path);
        lines.forEach(System.out::println);
        
        // 读取为字节数组
        byte[] bytes = Files.readAllBytes(path);
        System.out.println("大小:" + bytes.length);
        
        // 写入
        Files.write(Paths.get("output.txt"), "Hello".getBytes());
        
        // 创建目录
        Files.createDirectories(Paths.get("newdir/subdir"));
        
        // 复制
        Files.copy(Paths.get("source.txt"), Paths.get("dest.txt"));
        
        // 移动
        Files.move(Paths.get("old.txt"), Paths.get("new.txt"));
        
        // 删除
        Files.deleteIfExists(Paths.get("temp.txt"));
    }
}

文件属性

JAVA
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.FileTime;

public class FileAttributes {
    public static void main(String[] args) throws IOException {
        Path path = Paths.get("test.txt");
        
        BasicFileAttributes attrs = Files.readAttributes(path, BasicFileAttributes.class);
        
        System.out.println("大小:" + attrs.size());
        System.out.println("创建时间:" + attrs.creationTime());
        System.out.println("修改时间:" + attrs.lastModifiedTime());
        System.out.println("是否是目录:" + attrs.isDirectory());
        System.out.println("是否是文件:" + attrs.isRegularFile());
    }
}

文件遍历(NIO)

JAVA
import java.io.IOException;
import java.nio.file.*;
import java.util.stream.Stream;

public class NIODirectoryWalk {
    public static void main(String[] args) throws IOException {
        Path dir = Paths.get(".");
        
        // 遍历目录
        try (Stream<Path> stream = Files.list(dir)) {
            stream.forEach(path -> {
                String type = Files.isDirectory(path) ? "[目录]" : "[文件]";
                System.out.println(type + " " + path.getFileName());
            });
        }
        
        // 递归遍历
        try (Stream<Path> stream = Files.walk(dir, 3)) {  // 最多3层
            stream.forEach(path -> System.out.println(path));
        }
        
        // 查找文件
        try (Stream<Path> stream = Files.find(dir, 10, 
                (path, attrs) -> attrs.isRegularFile() && path.toString().endsWith(".txt"))) {
            stream.forEach(System.out::println);
        }
    }
}

IO vs NIO

特性 IO NIO
模型 面向流 面向缓冲区
阻塞 阻塞IO 非阻塞IO
选择器
API 较旧 较新

选择建议

场景 推荐
简单文件读写 Files工具类
大文件处理 缓冲流
高并发网络 NIO
旧代码维护 IO流

❓ 常见问题

Q 字节流和字符流怎么选?
A 文本文件用字符流,二进制文件用字节流。
Q 缓冲流有什么好处?
A 减少磁盘访问次数,提高IO效率。
Q NIO比IO快吗?
A 不一定。NIO主要优势是非阻塞和选择器,简单文件操作差异不大。

📖 小节

📝 作业

  1. 文件比较: 比较两个文件是否相同
  2. 大文件处理: 分块读取大文件,统计行数
  3. 目录同步: 将一个目录同步到另一个目录

下一课

下一课我们将学习 正则与JSON,了解字符串处理的高级技巧。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏