一、File类

1. File类概述

是什么?

  • java.io.File类是文件和目录路径名的抽象表示

  • 用于创建、删除、重命名、查询文件和目录

  • 注意:File类不能访问文件内容本身,需要IO流

路径表示:

  • 相对路径:相对于当前项目的路径

  • 绝对路径:从盘符开始的完整路径

  • 路径分隔符:

    • Windows:\` 或/`

    • Linux/Unix:/

    • 通用:File.separator

2. 构造方法

// 1. 通过路径字符串创建
File file1 = new File("D:/test/test.txt");
File file2 = new File("test.txt");  // 相对路径

// 2. 通过父路径和子路径字符串创建
File file3 = new File("D:/test", "test.txt");

// 3. 通过父File对象和子路径字符串创建
File parentDir = new File("D:/test");
File file4 = new File(parentDir, "test.txt");

3. 常用方法

创建功能
// 创建目录
boolean mkdir();      // 创建单级目录,父目录必须存在
boolean mkdirs();     // 创建多级目录,父目录不存在会自动创建

// 创建文件
boolean createNewFile();  // 创建新文件,文件不存在才创建

// 示例
File dir = new File("D:/a/b/c");
if (!dir.exists()) {
    boolean result = dir.mkdirs();  // 创建多级目录
    System.out.println("目录创建结果:" + result);
}

File file = new File("D:/a/b/c/test.txt");
if (!file.exists()) {
    boolean result = file.createNewFile();  // 创建文件
    System.out.println("文件创建结果:" + result);
}
判断功能
boolean exists();         // 文件或目录是否存在
boolean isDirectory();    // 是否是目录
boolean isFile();         // 是否是文件
boolean isHidden();       // 是否是隐藏文件
boolean canRead();        // 是否可读
boolean canWrite();       // 是否可写
boolean canExecute();     // 是否可执行
boolean isAbsolute();     // 是否是绝对路径
获取功能
String getAbsolutePath();     // 获取绝对路径
String getPath();            // 获取相对路径
String getName();            // 获取文件或目录名
String getParent();          // 获取父目录路径
File getParentFile();        // 获取父目录File对象
long length();              // 获取文件大小(字节),目录返回0
long lastModified();        // 获取最后修改时间(毫秒值)

// 目录相关
String[] list();                     // 获取目录下所有文件和目录名
File[] listFiles();                  // 获取目录下所有文件和目录的File对象
File[] listFiles(FileFilter filter); // 使用过滤器获取
File[] listFiles(FilenameFilter filter);

// 示例:遍历目录
File dir = new File("D:/test");
if (dir.exists() && dir.isDirectory()) {
    File[] files = dir.listFiles();
    for (File f : files) {
        System.out.println(f.getName());
    }
}
删除和重命名功能
boolean delete();  // 删除文件或空目录
boolean renameTo(File dest);  // 重命名或移动文件

// 注意:delete()方法
// 1. 删除目录时,目录必须为空
// 2. 删除操作不进回收站
// 3. 返回布尔值表示删除是否成功

二、IO流体系结构

1. IO流分类

按数据流向分:
    输入流:读取数据(从文件/网络到内存)
    输出流:写入数据(从内存到文件/网络)

按数据类型分:
    字节流:以字节为单位(8位),可处理所有类型文件
    字符流:以字符为单位(16位),只能处理文本文件

按功能分:
    节点流:直接从数据源/目的地读写
    处理流(包装流):对节点流进行包装,提供缓冲等功能

2. 完整体系结构

字节流(Byte Streams - 处理所有类型文件)
    InputStream(抽象类)
        ├─ FileInputStream(文件字节输入流)
        ├─ ByteArrayInputStream(字节数组输入流)
        ├─ FilterInputStream(过滤流)
        │    ├─ BufferedInputStream(缓冲字节输入流)
        │    ├─ DataInputStream(数据输入流)
        │    └─ PushbackInputStream(回退输入流)
        ├─ ObjectInputStream(对象输入流)
        ├─ PipedInputStream(管道输入流)
        └─ SequenceInputStream(序列输入流)

    OutputStream(抽象类)
        ├─ FileOutputStream(文件字节输出流)
        ├─ ByteArrayOutputStream(字节数组输出流)
        ├─ FilterOutputStream(过滤流)
        │    ├─ BufferedOutputStream(缓冲字节输出流)
        │    ├─ DataOutputStream(数据输出流)
        │    └─ PrintStream(打印流)
        ├─ ObjectOutputStream(对象输出流)
        └─ PipedOutputStream(管道输出流)

字符流(Character Streams - 处理文本文件)
    Reader(抽象类)
        ├─ FileReader(文件字符输入流)
        ├─ InputStreamReader(字节流转字符流)
        │    └─ BufferedReader(缓冲字符输入流)
        ├─ CharArrayReader(字符数组输入流)
        ├─ StringReader(字符串输入流)
        ├─ PipedReader(管道字符输入流)
        └─ FilterReader
             └─ PushbackReader(回退字符输入流)

    Writer(抽象类)
        ├─ FileWriter(文件字符输出流)
        ├─ OutputStreamWriter(字节流转字符流)
        │    └─ BufferedWriter(缓冲字符输出流)
        ├─ CharArrayWriter(字符数组输出流)
        ├─ StringWriter(字符串输出流)
        ├─ PipedWriter(管道字符输出流)
        └─ FilterWriter
             └─ PrintWriter(打印字符流)

三、字节流详解

1. InputStream(抽象类)

核心方法:

int read();                          // 读取一个字节,返回-1表示结束
int read(byte[] b);                  // 读取到字节数组,返回读取字节数
int read(byte[] b, int off, int len); // 读取指定长度到字节数组
void close();                        // 关闭流
int available();                     // 返回可读字节数
long skip(long n);                   // 跳过n个字节
void mark(int readlimit);           // 标记当前位置
void reset();                       // 重置到标记位置
boolean markSupported();            // 是否支持标记

2. FileInputStream

// 构造方法
FileInputStream(File file)
FileInputStream(String name)
FileInputStream(FileDescriptor fdObj)

// 示例1:读取单个字节
try (FileInputStream fis = new FileInputStream("test.txt")) {
    int data;
    while ((data = fis.read()) != -1) {
        System.out.print((char) data);
    }
} catch (IOException e) {
    e.printStackTrace();
}

// 示例2:读取到字节数组(推荐,效率高)
try (FileInputStream fis = new FileInputStream("test.txt")) {
    byte[] buffer = new byte[1024];
    int len;
    while ((len = fis.read(buffer)) != -1) {
        System.out.println(new String(buffer, 0, len));
    }
} catch (IOException e) {
    e.printStackTrace();
}

3. OutputStream(抽象类)

核心方法:

void write(int b);                    // 写入一个字节
void write(byte[] b);                 // 写入字节数组
void write(byte[] b, int off, int len); // 写入字节数组的一部分
void close();                         // 关闭流
void flush();                         // 刷新缓冲区

4. FileOutputStream

// 构造方法
FileOutputStream(File file)
FileOutputStream(File file, boolean append)  // append=true表示追加
FileOutputStream(String name)
FileOutputStream(String name, boolean append)

// 示例1:写入单个字节
try (FileOutputStream fos = new FileOutputStream("output.txt")) {
    String str = "Hello, World!";
    for (char c : str.toCharArray()) {
        fos.write(c);
    }
} catch (IOException e) {
    e.printStackTrace();
}

// 示例2:写入字节数组
try (FileOutputStream fos = new FileOutputStream("output.txt", true)) {
    String str = "Hello, World!\n";
    fos.write(str.getBytes());
} catch (IOException e) {
    e.printStackTrace();
}

5. 字节流文件复制

// 基本复制
try (FileInputStream fis = new FileInputStream("source.jpg");
     FileOutputStream fos = new FileOutputStream("copy.jpg")) {
    byte[] buffer = new byte[8192];  // 8KB缓冲区
    int len;
    while ((len = fis.read(buffer)) != -1) {
        fos.write(buffer, 0, len);
    }
    System.out.println("文件复制完成");
} catch (IOException e) {
    e.printStackTrace();
}

四、字符流详解

1. Reader(抽象类)

核心方法:

int read();                          // 读取一个字符
int read(char[] cbuf);               // 读取到字符数组
int read(char[] cbuf, int off, int len);
void close();
long skip(long n);
boolean ready();                     // 是否准备好读取
void mark(int readAheadLimit);
void reset();
boolean markSupported();

2. FileReader

// 构造方法
FileReader(File file)
FileReader(String fileName)
FileReader(FileDescriptor fd)

// 示例
try (FileReader fr = new FileReader("test.txt")) {
    char[] buffer = new char[1024];
    int len;
    while ((len = fr.read(buffer)) != -1) {
        System.out.println(new String(buffer, 0, len));
    }
} catch (IOException e) {
    e.printStackTrace();
}

3. Writer(抽象类)

核心方法:

void write(int c);                    // 写入一个字符
void write(char[] cbuf);              // 写入字符数组
void write(char[] cbuf, int off, int len);
void write(String str);               // 写入字符串
void write(String str, int off, int len);
void close();
void flush();                        // 刷新缓冲区

4. FileWriter

// 构造方法
FileWriter(File file)
FileWriter(File file, boolean append)
FileWriter(String fileName)
FileWriter(String fileName, boolean append)
FileWriter(FileDescriptor fd)

// 示例
try (FileWriter fw = new FileWriter("output.txt", true)) {
    fw.write("Hello, World!\n");
    fw.write("这是第二行\n");
    fw.flush();  // 立即刷新缓冲区
} catch (IOException e) {
    e.printStackTrace();
}

五、处理流(包装流)

1. 缓冲流

特点:​ 自带缓冲区,提高读写效率

BufferedInputStream
// 构造方法
BufferedInputStream(InputStream in)
BufferedInputStream(InputStream in, int size)  // 指定缓冲区大小

// 示例
try (BufferedInputStream bis = new BufferedInputStream(
        new FileInputStream("largefile.dat"))) {
    byte[] buffer = new byte[8192];
    int len;
    while ((len = bis.read(buffer)) != -1) {
        // 处理数据
    }
} catch (IOException e) {
    e.printStackTrace();
}
BufferedOutputStream
// 构造方法
BufferedOutputStream(OutputStream out)
BufferedOutputStream(OutputStream out, int size)

// 示例
try (BufferedOutputStream bos = new BufferedOutputStream(
        new FileOutputStream("output.dat"))) {
    byte[] data = "Hello".getBytes();
    bos.write(data);
    bos.flush();  // 确保数据写入
} catch (IOException e) {
    e.printStackTrace();
}
BufferedReader
// 构造方法
BufferedReader(Reader in)
BufferedReader(Reader in, int sz)

// 特有方法
String readLine();  // 读取一行,返回null表示结束

// 示例:逐行读取
try (BufferedReader br = new BufferedReader(
        new FileReader("test.txt"))) {
    String line;
    while ((line = br.readLine()) != null) {
        System.out.println(line);
    }
} catch (IOException e) {
    e.printStackTrace();
}
BufferedWriter
// 构造方法
BufferedWriter(Writer out)
BufferedWriter(Writer out, int sz)

// 特有方法
void newLine();  // 写入换行符,跨平台

// 示例
try (BufferedWriter bw = new BufferedWriter(
        new FileWriter("output.txt"))) {
    bw.write("第一行");
    bw.newLine();  // 跨平台换行
    bw.write("第二行");
    bw.flush();
} catch (IOException e) {
    e.printStackTrace();
}

2. 转换流

作用:​ 字节流和字符流之间的桥梁

InputStreamReader
// 构造方法
InputStreamReader(InputStream in)
InputStreamReader(InputStream in, String charsetName)  // 指定编码
InputStreamReader(InputStream in, Charset cs)

// 示例:解决乱码问题
try (InputStreamReader isr = new InputStreamReader(
        new FileInputStream("test.txt"), "GBK")) {
    char[] buffer = new char[1024];
    int len;
    while ((len = isr.read(buffer)) != -1) {
        System.out.println(new String(buffer, 0, len));
    }
} catch (IOException e) {
    e.printStackTrace();
}
OutputStreamWriter
// 构造方法
OutputStreamWriter(OutputStream out)
OutputStreamWriter(OutputStream out, String charsetName)
OutputStreamWriter(OutputStream out, Charset cs)

// 示例
try (OutputStreamWriter osw = new OutputStreamWriter(
        new FileOutputStream("output.txt"), "UTF-8")) {
    osw.write("Hello, 世界!");
} catch (IOException e) {
    e.printStackTrace();
}

3. 数据流

作用:​ 读写基本数据类型

DataInputStream
try (DataInputStream dis = new DataInputStream(
        new FileInputStream("data.dat"))) {
    int intValue = dis.readInt();
    double doubleValue = dis.readDouble();
    boolean boolValue = dis.readBoolean();
    String strValue = dis.readUTF();
} catch (IOException e) {
    e.printStackTrace();
}
DataOutputStream
try (DataOutputStream dos = new DataOutputStream(
        new FileOutputStream("data.dat"))) {
    dos.writeInt(100);
    dos.writeDouble(3.14);
    dos.writeBoolean(true);
    dos.writeUTF("Hello");
} catch (IOException e) {
    e.printStackTrace();
}

4. 对象流

作用:​ 序列化和反序列化对象

ObjectOutputStream
// 序列化
class Person implements Serializable {
    private static final long serialVersionUID = 1L;
    private String name;
    private int age;
    // 构造方法、getter、setter省略
}

try (ObjectOutputStream oos = new ObjectOutputStream(
        new FileOutputStream("person.dat"))) {
    Person person = new Person("张三", 20);
    oos.writeObject(person);
} catch (IOException e) {
    e.printStackTrace();
}
ObjectInputStream
// 反序列化
try (ObjectInputStream ois = new ObjectInputStream(
        new FileInputStream("person.dat"))) {
    Person person = (Person) ois.readObject();
    System.out.println(person.getName());
} catch (IOException | ClassNotFoundException e) {
    e.printStackTrace();
}

5. 打印流

特点:​ 不会抛出IOException,自动flush

PrintStream
// System.out就是PrintStream
PrintStream ps = new PrintStream("log.txt");
ps.println("日志信息");
ps.printf("当前时间:%tF %<tT%n", new Date());
ps.close();
PrintWriter
try (PrintWriter pw = new PrintWriter(
        new FileWriter("output.txt"))) {
    pw.println("第一行");
    pw.printf("价格:%.2f元%n", 99.99);
} catch (IOException e) {
    e.printStackTrace();
}

六、NIO.2(JDK7+)

1. Path接口

// 创建Path
Path path1 = Paths.get("D:/test/test.txt");
Path path2 = Paths.get("D:", "test", "test.txt");
Path path3 = FileSystems.getDefault().getPath("D:/test/test.txt");

// 常用方法
System.out.println(path1.getFileName());  // 文件名
System.out.println(path1.getParent());     // 父目录
System.out.println(path1.getRoot());       // 根目录
System.out.println(path1.getNameCount());  // 名称元素数量
System.out.println(path1.getName(0));      // 第i个名称元素

2. Files工具类

// 文件操作
Path source = Paths.get("source.txt");
Path target = Paths.get("target.txt");

// 复制文件
Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);

// 移动文件
Files.move(source, target, StandardCopyOption.REPLACE_EXISTING);

// 删除文件
Files.deleteIfExists(target);

// 判断文件属性
boolean exists = Files.exists(path);
boolean isDir = Files.isDirectory(path);
boolean isHidden = Files.isHidden(path);
boolean isReadable = Files.isReadable(path);
boolean isWritable = Files.isWritable(path);

// 读取文件
byte[] bytes = Files.readAllBytes(path);
List<String> lines = Files.readAllLines(path, StandardCharsets.UTF_8);

// 写入文件
Files.write(path, "内容".getBytes());
Files.write(path, Arrays.asList("第一行", "第二行"), 
           StandardCharsets.UTF_8);

// 遍历目录
try (Stream<Path> stream = Files.list(Paths.get("D:/test"))) {
    stream.forEach(System.out::println);
}

七、IO流使用总结

1. 选择流的准则

文本文件:使用字符流
二进制文件:使用字节流
需要缓冲:使用缓冲流
需要特定编码:使用转换流
读写基本数据类型:使用数据流
读写对象:使用对象流
需要序列化:实现Serializable接口

2. 性能优化建议

// 1. 使用缓冲区
try (BufferedInputStream bis = new BufferedInputStream(
        new FileInputStream("file.dat"));
     BufferedOutputStream bos = new BufferedOutputStream(
        new FileOutputStream("copy.dat"))) {
    // 处理逻辑
}

// 2. 选择合适的缓冲区大小(通常8KB-32KB)
byte[] buffer = new byte[8192];  // 8KB

// 3. 使用try-with-resources自动关闭资源
try (FileInputStream fis = new FileInputStream("file.txt")) {
    // 自动关闭
}

// 4. 批量读写,减少IO操作次数

3. 编码问题处理

// 指定编码读取
try (BufferedReader br = new BufferedReader(
        new InputStreamReader(
            new FileInputStream("file.txt"), 
            "UTF-8"))) {
    // 读取
}

// 指定编码写入
try (BufferedWriter bw = new BufferedWriter(
        new OutputStreamWriter(
            new FileOutputStream("file.txt"), 
            "UTF-8"))) {
    // 写入
}

4. 常见问题解决

// 文件复制优化
public static void copyFile(String src, String dest) throws IOException {
    try (InputStream in = new BufferedInputStream(
            new FileInputStream(src));
         OutputStream out = new BufferedOutputStream(
            new FileOutputStream(dest))) {
        
        byte[] buffer = new byte[8192];
        int length;
        while ((length = in.read(buffer)) > 0) {
            out.write(buffer, 0, length);
        }
        out.flush();
    }
}

// 读取大文件
public static void readLargeFile(String filename) throws IOException {
    try (BufferedReader br = new BufferedReader(
            new FileReader(filename))) {
        String line;
        while ((line = br.readLine()) != null) {
            // 处理每一行
        }
    }
}

八、常见面试题

  1. File类的作用是什么?

  2. 字节流和字符流的区别?

  3. 为什么要使用缓冲流?

  4. 如何选择IO流?

  5. 序列化和反序列化是什么?

  6. 如何解决中文乱码问题?

  7. try-with-resources的好处?

  8. NIO和传统IO的区别?

  9. 如何提高IO性能?

  10. Files类相比File类有什么优势?

这个IO流总结详细介绍了Java IO体系的所有重要类和方法,包括文件操作、各种流的使用、性能优化和常见问题的解决方案,适合发布到CSDN等技术博客平台。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐