8、Java核心API系列(六)

七、 文件与IO

1、文件和目录操作(File类)

Java中的File类位于java.io包中,主要用于处理文件和目录的基本操作,如创建、删除、复制、移动文件或目录,以及获取文件的属性。

1. 创建文件或目录
  • 创建文件:使用File类的构造器并调用createNewFile()方法。
  • 创建目录:使用mkdir()方法创建单层目录,使用mkdirs()方法创建多层目录。

示例

import java.io.File;  
import java.io.IOException;  

public class FileOperations {  
    public static void main(String[] args) {  
        // 创建文件  
        File file = new File("example.txt");  
        try {  
            if (file.createNewFile()) {  
                System.out.println("文件创建成功!");  
            }  
        } catch (IOException e) {  
            System.out.println("创建文件失败:" + e.getMessage());  
        }  

        // 创建单层目录  
        File dir = new File("singleDir");  
        if (dir.mkdir()) {  
            System.out.println("单层目录创建成功!");  
        } else {  
            System.out.println("单层目录创建失败!");  
        }  

        // 创建多层目录  
        File multiDir = new File("multi/dir1/dir2");  
        if (multiDir.mkdirs()) {  
            System.out.println("多层目录创建成功!");  
        } else {  
            System.out.println("多层目录创建失败!");  
        }  
    }  
}  
2. 删除文件或目录
  • 删除文件:调用delete()方法。
  • 删除目录:调用delete()方法,但需要确保目录为空,否则删除会失败。

示例

public class FileDeletion {  
    public static void main(String[] args) {  
        File file = new File("example.txt");  
        if (file.delete()) {  
            System.out.println("文件删除成功!");  
        } else {  
            System.out.println("文件删除失败!");  
        }  

        File dir = new File("singleDir");  
        if (dir.delete()) {  
            System.out.println("目录删除成功!");  
        } else {  
            System.out.println("目录删除失败!可能目录不为空或不存在。");  
        }  
    }  
}  
3. 复制和移动文件
  • 复制文件:可以使用Files.copy()方法,需要导入java.nio.file.Files
  • 移动文件:使用File类的renameTo()方法。

示例

import java.io.File;  
import java.io.IOException;  
import java.nio.file.Files;  
import java.nio.file.Path;  
import java.nio.file.Paths;  
import java.nio.file.StandardCopyOption;  

public class FileCopyMove {  
    public static void main(String[] args) {  
        File sourceFile = new File("source.txt");  
        File targetFile = new File("target.txt");  

        // 复制文件  
        try {  
            Path sourcePath = Paths.get(sourceFile.getAbsolutePath());  
            Path targetPath = Paths.get(targetFile.getAbsolutePath());  
            Files.copy(sourcePath, targetPath, StandardCopyOption.REPLACE_EXISTING);  
            System.out.println("文件复制成功!");  
        } catch (IOException e) {  
            System.out.println("文件复制失败:" + e.getMessage());  
        }  

        // 移动文件  
        File newLocation = new File("moved.txt");  
        if (sourceFile.renameTo(newLocation)) {  
            System.out.println("文件移动成功!");  
        } else {  
            System.out.println("文件移动失败!");  
        }  
    }  
}  
4. 判断文件类型和获取文件属性
  • 判断文件类型:使用isFile()方法。
  • 判断目录类型:使用isDirectory()方法。
  • 获取文件名:使用getName()方法。
  • 获取文件路径:使用getPath()方法。
  • 获取绝对路径:使用getAbsolutePath()方法。
  • 获取文件大小:使用length()方法。
  • 获取最后修改时间:使用lastModified()方法。

示例

import java.io.File;  

public class FileAttributes {  
    public static void main(String[] args) {  
        File file = new File("example.txt");  

        System.out.println("文件是否存在:" + file.exists());  
        System.out.println("是否是文件:" + file.isFile());  
        System.out.println("是否是目录:" + file.isDirectory());  
        System.out.println("文件名:" + file.getName());  
        System.out.println("文件路径:" + file.getPath());  
        System.out.println("绝对路径:" + file.getAbsolutePath());  
        System.out.println("文件大小(字节):" + file.length());  
        System.out.println("最后修改时间(毫秒):" + file.lastModified());  
    }  
}  

2、流的基础

Java中的流(Stream)用于处理数据的流动。主要有四种基本的流类型:

  • InputStream:字节输入流,用于从源读取数据。
  • OutputStream:字节输出流,用于将数据写入目的地。
  • Reader:字符输入流,用于从源读取字符数据。
  • Writer:字符输出流,用于将字符数据写入目的地。

这些流是Java IO操作的基础,所有的具体流都要继承自这些抽象类。

InputStream 和 OutputStream

这两个类是字节流的基础,用于处理字节数据。常用的实现类包括FileInputStreamFileOutputStream

Reader 和 Writer

这两个类是字符流的基础,用于处理字符数据。常用的实现类包括FileReaderFileWriter

3、 文件读写流

1. FileInputStream 和 FileOutputStream

FileInputStream用于以字节形式读取文件,FileOutputStream用于以字节形式写入文件。

示例

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

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

        try (FileInputStream in = new FileInputStream(source);  
             FileOutputStream out = new FileOutputStream(target)) {  

            byte[] buffer = new byte[1024];  
            int bytesRead;  
            while ((bytesRead = in.read(buffer)) != -1) {  
                out.write(buffer, 0, bytesRead);  
            }  
            System.out.println("文件复制成功!");  
        } catch (IOException e) {  
            System.out.println("文件操作失败:" + e.getMessage());  
        }  
    }  
}  
2. FileReader 和 FileWriter

FileReader用于以字符形式读取文件,FileWriter用于以字符形式写入文件。

示例

import java.io.FileReader;  
import java.io.FileWriter;  
import java.io.IOException;  

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

        try (FileReader reader = new FileReader(source);  
             FileWriter writer = new FileWriter(target)) {  

            char[] buffer = new char[1024];  
            int charsRead;  
            while ((charsRead = reader.read(buffer)) != -1) {  
                writer.write(buffer, 0, charsRead);  
            }  
            System.out.println("文件复制成功!");  
        } catch (IOException e) {  
            System.out.println("文件操作失败:" + e.getMessage());  
        }  
    }  
}  

4、高效的文件处理流

为了提高文件读写的效率,通常使用缓冲流(Buffered Streams)来包装原始流。缓冲流在内部维护一个缓冲区,减少与底层设备的IO次数,从而提高性能。

1. BufferedInputStream 和 BufferedOutputStream

示例

import java.io.BufferedInputStream;  
import java.io.BufferedOutputStream;  
import java.io.FileInputStream;  
import java.io.FileOutputStream;  
import java.io.IOException;  

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

        try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(source));  
             BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(target))) {  

            byte[] buffer = new byte[1024];  
            int bytesRead;  
            while ((bytesRead = in.read(buffer)) != -1) {  
                out.write(buffer, 0, bytesRead);  
                out.flush(); // 确保数据及时写出  
            }  
            System.out.println("文件复制成功!");  
        } catch (IOException e) {  
            System.out.println("文件操作失败:" + e.getMessage());  
        }  
    }  
}  
2. BufferedReader 和 BufferedWriter

BufferedReaderBufferedWriter分别用于字符数据的高效读写。

示例

import java.io.BufferedReader;  
import java.io.BufferedWriter;  
import java.io.FileReader;  
import java.io.FileWriter;  
import java.io.IOException;  

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

        try (BufferedReader reader = new BufferedReader(new FileReader(source));  
             BufferedWriter writer = new BufferedWriter(new FileWriter(target))) {  

            char[] buffer = new char[1024];  
            int charsRead;  
            while ((charsRead = reader.read(buffer)) != -1) {  
                writer.write(buffer, 0, charsRead);  
                writer.flush(); // 确保数据及时写出  
            }  
            System.out.println("文件复制成功!");  
        } catch (IOException e) {  
            System.out.println("文件操作失败:" + e.getMessage());  
        }  
    }  
}  
3. 最佳实践
  • 使用缓冲区大小:可以通过构造函数指定缓冲区的大小,合理选择以提高性能。
  • 自动刷新(Auto-Flush):在某些情况下,可以启用自动刷新功能,例如BufferedWriterwrite方法可以接受一个布尔参数来控制是否自动刷新缓冲区。
  • 资源管理:使用try-with-resources语句确保流在使用后自动关闭,避免资源泄漏。

5、序列化与反序列化(Serializable接口)

Java的序列化机制允许将对象转换为字节流,以便存储或传输。实现Serializable接口的对象可以被序列化。

1. 实现Serializable接口

示例:Person类实现Serializable

import java.io.Serializable;  

public class Person implements Serializable {  
    private static final long serialVersionUID = 1L;  
    private String name;  
    private int age;  

    public Person(String name, int age) {  
        this.name = name;  
        this.age = age;  
    }  

    public String getName() {  
        return name;  
    }  

    public int getAge() {  
        return age;  
    }  

    @Override  
    public String toString() {  
        return "Person{" +  
                "name='" + name + '\'' +  
                ", age=" + age + '}';  
    }  
}  
2. 序列化(写入对象)

使用ObjectOutputStream将对象写入文件。

示例:

import java.io.FileOutputStream;  
import java.io.ObjectOutputStream;  
import java.io.IOException;  

public class SerializationDemo {  
    public static void main(String[] args) {  
        Person person = new Person("John Doe", 30);  
        String fileName = "person.ser";  

        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(fileName))) {  
            oos.writeObject(person);  
            System.out.println("对象序列化成功,保存为 " + fileName);  
        } catch (IOException e) {  
            System.out.println("序列化失败:" + e.getMessage());  
        }  
    }  
}  
3. 反序列化(读取对象)

使用ObjectInputStream从文件中读取对象。

示例:

import java.io.FileInputStream;  
import java.io.ObjectInputStream;  
import java.io.IOException;  
import java.lang.ClassNotFoundException;  

public class DeserializationDemo {  
    public static void main(String[] args) {  
        String fileName = "person.ser";  

        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(fileName))) {  
            Person person = (Person) ois.readObject();  
            System.out.println("反序列化成功:" + person);  
        } catch (IOException | ClassNotFoundException e) {  
            System.out.println("反序列化失败:" + e.getMessage());  
        }  
    }  
}  
4. 注意事项
  • 版本兼容性:确保serialVersionUID一致,否则可能导致反序列化失败。
  • 安全性:序列化可以漏洞,需谨慎使用,尤其是在处理未受信任的数据时。
  • transient 关键字:若某个字段不需要序列化,可以使用transient关键字标记。

6、RandomAccessFile的使用

RandomAccessFile类允许以随机访问的方式读写文件,支持读取和写入文件的任意位置。

1. 读写操作

示例:

import java.io.RandomAccessFile;  
import java.io.IOException;  

public class RandomAccessFileDemo {  
    public static void main(String[] args) {  
        String fileName = "raf_demo.txt";  
        try (RandomAccessFile raf = new RandomAccessFile(fileName, "rw")) {  
            // 写入数据  
            String content = "Hello, RandomAccessFile!";  
            raf.write(content.getBytes());  
            System.out.println("写入数据成功");  

            // 移动文件指针到开始位置  
            raf.seek(0);  
            byte[] buffer = new byte[1024];  
            int bytesRead = raf.read(buffer);  
            System.out.println("读取到的数据:" + new String(buffer, 0, bytesRead));  
        } catch (IOException e) {  
            System.out.println("RandomAccessFile操作失败:" + e.getMessage());  
        }  
    }  
}  
2. 读写示例

示例:读写整数

import java.io.RandomAccessFile;  
import java.io.IOException;  

public class RandomAccessFileIntDemo {  
    public static void main(String[] args) {  
        String fileName = "raf_int_demo.txt";  
        try (RandomAccessFile raf = new RandomAccessFile(fileName, "rw")) {  
            // 写入整数  
            int number = 12345;  
            raf.writeInt(number);  
            System.out.println("写入整数:" + number);  

            // 移动指针到开始位置  
            raf.seek(0);  
            int readNumber = raf.readInt();  
            System.out.println("读取的整数:" + readNumber);  
        } catch (IOException e) {  
            System.out.println("RandomAccessFile操作失败:" + e.getMessage());  
        }  
    }  
}  
3. 实际应用场景
  • 数据库文件处理:用于需要频繁随机访问的场景,如数据库索引。
  • 大文件处理:适合处理大文件,尤其是需要多次访问不同位置的数据。
  • 二进制数据存储:适合存储需要频繁修改的结构化二进制数据。
4. 注意事项
  • 文件权限:确保程序有足够的权限访问和操作文件。
  • 异常处理:IO操作可能抛出多种异常,需妥善处理。
  • 文件模式RandomAccessFile的构造器支持不同的文件模式,如"r"(只读)、“rw”(读写)。

总结

本模块涵盖了Java中的文件与IO操作,从基本的文件和目录操作到高级的序列化与随机访问文件处理。通过理解和实践这些内容,开发者可以在Java程序中高效、安全地进行文件和IO操作,应对各种实际场景的需求。

你可能感兴趣的:(java,开发语言)