顺序读取文件

在 Java 中,如果主要是顺序访问文件,可以使用 FileInputStreamFileOutputStreamFileReaderFileWriter 等类。它们主要用于顺序读写文件,不支持直接的随机访问,适合逐行或逐字节顺序读取或写入文件的场景。

1. FileInputStreamFileOutputStream

FileInputStreamFileOutputStream 是基于字节流的类,适合处理二进制文件(如图片、视频、音频等),也可以用于文本文件。

FileInputStream 用法

用于从文件中逐字节读取数据:

import java.io.FileInputStream;
import java.io.IOException;
 
public class FileInputStreamExample {
    public static void main(String[] args) {
        try (FileInputStream fis = new FileInputStream("example.txt")) {
            int content;
            while ((content = fis.read()) != -1) {
                System.out.print((char) content); // 输出内容
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

FileOutputStream 用法

用于向文件中逐字节写入数据:

import java.io.FileOutputStream;
import java.io.IOException;
 
public class FileOutputStreamExample {
    public static void main(String[] args) {
        String data = "Hello, FileOutputStream!";
        try (FileOutputStream fos = new FileOutputStream("example.txt")) {
            fos.write(data.getBytes()); // 将字符串写入文件
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2. FileReaderFileWriter

FileReaderFileWriter 是基于字符流的类,专门用于处理文本文件,更适合读取和写入字符数据。

FileReader 用法

用于从文件中逐字符读取数据:

import java.io.FileReader;
import java.io.IOException;
 
public class FileReaderExample {
    public static void main(String[] args) {
        try (FileReader fr = new FileReader("example.txt")) {
            int content;
            while ((content = fr.read()) != -1) {
                System.out.print((char) content); // 输出内容
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

FileWriter 用法

用于向文件中逐字符写入数据:

import java.io.FileWriter;
import java.io.IOException;
 
public class FileWriterExample {
    public static void main(String[] args) {
        String data = "Hello, FileWriter!";
        try (FileWriter fw = new FileWriter("example.txt")) {
            fw.write(data); // 将字符串写入文件
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

3. 缓冲流:BufferedReaderBufferedWriter

BufferedReaderBufferedWriter 提供了带缓冲区的字符流类,更适合逐行读取和写入文本文件。可以提高 I/O 操作的效率,尤其是在读取大文件时。

BufferedReader 用法

BufferedReader 提供了 readLine() 方法,可以按行读取文件内容:

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
 
public class BufferedReaderExample {
    public static void main(String[] args) {
        try (BufferedReader br = new BufferedReader(new FileReader("example.txt"))) {
            String line;
            while ((line = br.readLine()) != null) {
                System.out.println(line); // 输出每行内容
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

BufferedWriter 用法

BufferedWriter 提供了 newLine() 方法,可以方便地逐行写入内容:

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
 
public class BufferedWriterExample {
    public static void main(String[] args) {
        try (BufferedWriter bw = new BufferedWriter(new FileWriter("example.txt"))) {
            bw.write("Hello, BufferedWriter!");
            bw.newLine(); // 写入一个新行
            bw.write("This is another line.");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

4. 选择合适的类

  • 处理二进制文件(如图片、音频、视频):FileInputStreamFileOutputStream
  • 处理文本文件的逐字符读写:FileReaderFileWriter
  • 处理文本文件的逐行读写,提高效率:BufferedReaderBufferedWriter

这类顺序访问类适合大多数需要顺序读写文件的场景,如果需要随机访问,则可以考虑 RandomAccessFile


随机读取文件

RandomAccessFile 是 Java 中用于文件的读写操作的类,它允许在文件中读取和写入的同时,可以随意移动文件指针,从而在文件的任意位置进行操作。它支持随机访问,因此在需要频繁地访问文件的不同位置时非常有用。

1. 构造方法

RandomAccessFile 有两个主要构造方法:

RandomAccessFile(String file, String mode)
RandomAccessFile(File file, String mode)

其中,file 是文件路径或 File 对象,mode 是打开文件的模式,常见的模式有:

  • "r":只读模式,文件必须存在。
  • "rw":读写模式,文件可以不存在,不存在时会自动创建。

2. 常用方法

打开文件

RandomAccessFile raf = new RandomAccessFile("example.txt", "rw");

写入数据

raf.writeInt(100);         // 写入一个整数
raf.writeUTF("Hello");     // 写入一个UTF字符串
raf.writeBoolean(true);    // 写入布尔值

读取数据

在读取数据时需要注意数据类型的顺序与写入时一致。

raf.seek(0);               // 移动文件指针到开头
int number = raf.readInt();
String text = raf.readUTF();
boolean flag = raf.readBoolean();

随机访问

通过 seek(long pos) 方法可以将文件指针移动到文件的任意位置。pos 是文件中的字节偏移量,从 0 开始。

raf.seek(8);  // 移动文件指针到第 8 个字节位置

获取文件长度

long length = raf.length();

设置文件长度

可以通过 setLength(long newLength) 来设置文件长度。如果新长度小于当前文件长度,会截断文件。

raf.setLength(100);  // 设置文件长度为 100 字节

获取文件指针位置

long pos = raf.getFilePointer();

关闭文件

使用完成后应关闭文件,以释放资源。

raf.close();

3. 示例代码

以下是一个简单示例,演示如何使用 RandomAccessFile 进行写入、读取和随机访问。

import java.io.*;
 
public class RandomAccessFileExample {
    public static void main(String[] args) {
        try (RandomAccessFile raf = new RandomAccessFile("example.txt", "rw")) {
            // 写入数据
            raf.writeInt(123);
            raf.writeUTF("Hello World");
            raf.writeBoolean(true);
            
            // 读取数据
            raf.seek(0);  // 将指针移动到文件开头
            int num = raf.readInt();
            String str = raf.readUTF();
            boolean bool = raf.readBoolean();
 
            System.out.println("Integer: " + num);
            System.out.println("String: " + str);
            System.out.println("Boolean: " + bool);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

4. 注意事项

  • 使用 RandomAccessFile 时,请确保文件读写的顺序和数据格式一致。
  • 读写文件需要捕获 IOException 异常。
  • RandomAccessFile 适用于文件的随机读写,而不是大量的数据追加操作。

这样就可以在 Java 中实现文件的随机访问,适合一些需要频繁对文件的某个位置进行读写的场景,比如简单的数据库实现。


在 Java 中,I/O 类主要可以分为 字节流字符流 两大类。字节流用于处理所有类型的文件(文本或二进制文件),而字符流专门用于处理文本数据。

1. 字节流

字节流的基本单位是 字节(8 位),因此它适合处理所有类型的数据,包括图片、音频、视频等。Java 提供了两组字节流类:输入字节流和输出字节流,分别从文件中读取或向文件中写入字节数据。

字节流的两大基类

  • InputStream:字节输入流的基类,用于从文件或其他数据源读取字节数据。
  • OutputStream:字节输出流的基类,用于将字节数据写入文件或其他输出目标。

常用字节流类

类名描述
FileInputStream从文件中按字节读取数据
FileOutputStream向文件中按字节写入数据
BufferedInputStream提供带缓冲区的字节输入流,提高读取效率
BufferedOutputStream提供带缓冲区的字节输出流,提高写入效率
DataInputStream包装在其他字节流上,按基本数据类型读取字节数据
DataOutputStream包装在其他字节流上,按基本数据类型写入字节数据
ByteArrayInputStream从字节数组中读取数据,适用于内存中的字节数据
ByteArrayOutputStream写入字节数据到字节数组

字节流的使用示例

// 使用 FileInputStream 读取文件
try (FileInputStream fis = new FileInputStream("example.bin")) {
    int byteData;
    while ((byteData = fis.read()) != -1) {
        System.out.print(byteData + " ");
    }
} catch (IOException e) {
    e.printStackTrace();
}

2. 字符流

字符流的基本单位是 字符(16 位),因此它更适合处理文本数据,因为字符流能够正确处理 Unicode 字符。Java 中字符流的核心是将字节流按字符编码进行解码,并提供按字符操作数据的方法。

字符流的两大基类

  • Reader:字符输入流的基类,用于从文件或其他数据源读取字符数据。
  • Writer:字符输出流的基类,用于将字符数据写入文件或其他输出目标。

常用字符流类

类名描述
FileReader从文件中按字符读取数据
FileWriter向文件中按字符写入数据
BufferedReader提供带缓冲区的字符输入流,支持按行读取
BufferedWriter提供带缓冲区的字符输出流,支持按行写入
InputStreamReader将字节流转为字符流,通常用于指定字符编码
OutputStreamWriter将字符流转为字节流,通常用于指定字符编码
StringReader从字符串中读取字符数据,适用于内存中的字符数据
StringWriter写入字符数据到字符串

字符流的使用示例

// 使用 FileReader 和 BufferedReader 读取文本文件
try (BufferedReader br = new BufferedReader(new FileReader("example.txt"))) {
    String line;
    while ((line = br.readLine()) != null) {
        System.out.println(line);
    }
} catch (IOException e) {
    e.printStackTrace();
}

字节流和字符流的区别

特性字节流字符流
基本单位字节(8 位)字符(16 位)
适用场景二进制数据和文本数据仅文本数据
基类InputStream / OutputStreamReader / Writer
缓冲类BufferedInputStream / BufferedOutputStreamBufferedReader / BufferedWriter
编码支持不处理字符编码支持字符编码,通常为 UTF-8 等

字节流与字符流的转换

可以通过 InputStreamReaderOutputStreamWriter 将字节流与字符流相互转换,以便处理带有编码的文本数据。例如从字节流读取文件并按 UTF-8 编码解码为字符流:

try (InputStreamReader isr = new InputStreamReader(new FileInputStream("example.txt"), "UTF-8");
     BufferedReader br = new BufferedReader(isr)) {
    String line;
    while ((line = br.readLine()) != null) {
        System.out.println(line);
    }
} catch (IOException e) {
    e.printStackTrace();
}

在实际开发中,选择字节流或字符流取决于文件数据的类型以及是否需要处理编码。


Java InputStream 拼接