首页 热点资讯 义务教育 高等教育 出国留学 考研考公
您的当前位置:首页正文

【Java入门指南 Day13: IO与文件处理】

2023-12-20 来源:化拓教育网

一、IO流系统概述

Java的IO系统像是一个管道系统,负责数据的输入和输出。可以分为:

  • 字节流:处理二进制数据
  • 字符流:处理文本数据

字节流与字符流对比

// 字节流示例:复制图片
public void copyImage(String source, String target) {
    try (FileInputStream fis = new FileInputStream(source);
         FileOutputStream fos = new FileOutputStream(target)) {
        byte[] buffer = new byte[1024];
        int length;
        while ((length = fis.read(buffer)) > 0) {
            fos.write(buffer, 0, length);
        }
    }
}

// 字符流示例:读取文本
public void readText(String fileName) {
    try (FileReader reader = new FileReader(fileName);
         BufferedReader br = new BufferedReader(reader)) {
        String line;
        while ((line = br.readLine()) != null) {
            System.out.println(line);
        }
    }
}

常用流的层次结构

InputStream/OutputStream (字节流)
├── FileInputStream/FileOutputStream
├── BufferedInputStream/BufferedOutputStream
└── DataInputStream/DataOutputStream

Reader/Writer (字符流)
├── FileReader/FileWriter
├── BufferedReader/BufferedWriter
└── InputStreamReader/OutputStreamWriter

二、NIO(New IO)系统

NIO提供了非阻塞IO操作的能力,特别适合高并发场景。

Buffer和Channel

public class NIOExample {
    public void readFile(String fileName) throws IOException {
        // 创建文件通道
        try (FileChannel channel = FileChannel.open(
                Paths.get(fileName), StandardOpenOption.READ)) {
            // 创建缓冲区
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            
            // 读取数据到缓冲区
            while (channel.read(buffer) != -1) {
                buffer.flip();  // 切换到读模式
                while (buffer.hasRemaining()) {
                    System.out.print((char) buffer.get());
                }
                buffer.clear();  // 清空缓冲区
            }
        }
    }
}

非阻塞IO示例

public class NonBlockingServer {
    public void startServer() throws IOException {
        // 创建选择器
        Selector selector = Selector.open();
        
        // 配置服务器通道
        ServerSocketChannel serverChannel = ServerSocketChannel.open();
        serverChannel.bind(new InetSocketAddress(8080));
        serverChannel.configureBlocking(false);
        
        // 注册接受连接事件
        serverChannel.register(selector, SelectionKey.OP_ACCEPT);
        
        while (true) {
            selector.select();
            Set<SelectionKey> selectedKeys = selector.selectedKeys();
            Iterator<SelectionKey> iter = selectedKeys.iterator();
            
            while (iter.hasNext()) {
                SelectionKey key = iter.next();
                if (key.isAcceptable()) {
                    handleAccept(serverChannel, selector);
                }
                iter.remove();
            }
        }
    }
}

三、文件操作最佳实践

文件读写操作

public class FileOperations {
    // 使用try-with-resources确保资源释放
    public List<String> readLines(String fileName) {
        List<String> lines = new ArrayList<>();
        try (BufferedReader reader = Files.newBufferedReader(
                Paths.get(fileName), StandardCharsets.UTF_8)) {
            String line;
            while ((line = reader.readLine()) != null) {
                lines.add(line);
            }
        }
        return lines;
    }
    
    // 使用BufferedWriter提高写入性能
    public void writeLines(String fileName, List<String> lines) {
        try (BufferedWriter writer = Files.newBufferedWriter(
                Paths.get(fileName), StandardCharsets.UTF_8)) {
            for (String line : lines) {
                writer.write(line);
                writer.newLine();
            }
        }
    }
}

文件复制与移动

public class FileUtils {
    // 复制文件
    public void copyFile(Path source, Path target) throws IOException {
        // REPLACE_EXISTING:如果目标文件存在则替换
        // COPY_ATTRIBUTES:复制文件属性
        Files.copy(source, target, 
            StandardCopyOption.REPLACE_EXISTING,
            StandardCopyOption.COPY_ATTRIBUTES);
    }
    
    // 移动文件
    public void moveFile(Path source, Path target) throws IOException {
        Files.move(source, target, StandardCopyOption.REPLACE_EXISTING);
    }
}

四、序列化机制

基本序列化

public class SerializationDemo {
    // 可序列化的类
    public static class Person implements Serializable {
        private static final long serialVersionUID = 1L;
        private String name;
        private int age;
        private transient String password;  // 不会被序列化
    }
    
    // 序列化对象
    public void serialize(Person person, String fileName) {
        try (ObjectOutputStream out = new ObjectOutputStream(
                new FileOutputStream(fileName))) {
            out.writeObject(person);
        }
    }
    
    // 反序列化对象
    public Person deserialize(String fileName) {
        try (ObjectInputStream in = new ObjectInputStream(
                new FileInputStream(fileName))) {
            return (Person) in.readObject();
        }
    }
}

五、Path与Files工具类使用

Path类操作

public class PathDemo {
    public void pathOperations() {
        Path path = Paths.get("/home/user/docs/file.txt");
        
        // 获取文件信息
        System.out.println("文件名: " + path.getFileName());
        System.out.println("父目录: " + path.getParent());
        System.out.println("根目录: " + path.getRoot());
        
        // 路径操作
        Path normalizedPath = path.normalize();
        Path resolvedPath = path.resolve("another.txt");
    }
}

Files工具类

public class FilesDemo {
    public void fileOperations() throws IOException {
        Path path = Paths.get("example.txt");
        
        // 创建文件
        Files.createFile(path);
        
        // 写入内容
        Files.write(path, "Hello, World!".getBytes());
        
        // 读取内容
        byte[] content = Files.readAllBytes(path);
        
        // 检查文件属性
        System.out.println("是否存在: " + Files.exists(path));
        System.out.println("是否可读: " + Files.isReadable(path));
        
        // 遍历目录
        try (Stream<Path> paths = Files.walk(Paths.get("."))) {
            paths.forEach(System.out::println);
        }
    }
}

最佳实践建议 💡

常见陷阱提醒 ⚠️

  1. 资源泄露
// 错误:未正确关闭资源
FileInputStream fis = new FileInputStream("file.txt");
// 使用文件...
fis.close();  // 可能永远不会执行

// 正确:使用try-with-resources
try (FileInputStream fis = new FileInputStream("file.txt")) {
    // 使用文件...
}
  1. 编码问题
// 错误:未指定字符编码
FileReader reader = new FileReader("file.txt");

// 正确:指定字符编码
Reader reader = new InputStreamReader(
    new FileInputStream("file.txt"), StandardCharsets.UTF_8);
  1. 性能问题
// 低效:逐字节读取
int b;
while ((b = inputStream.read()) != -1) {
    // 处理字节...
}

// 高效:使用缓冲区
byte[] buffer = new byte[8192];
int length;
while ((length = inputStream.read(buffer)) != -1) {
    // 处理缓冲区...
}

IO和文件处理是Java应用程序的基础功能。掌握这些知识对于开发高质量的应用程序至关重要。记住要注意资源管理、性能优化和错误处理。

因篇幅问题不能全部显示,请点此查看更多更全内容