Java 讀取檔案
Java 提供多種方式讀取檔案,適用於不同的使用場景。
使用 Files(推薦)
Java 7+ 的 Files 類別提供簡潔的 API:
讀取全部內容
import java.nio.file.Files;
import java.nio.file.Paths;
// 讀取為字串(Java 11+)
String content = Files.readString(Paths.get("file.txt"));
// 讀取為位元組陣列
byte[] bytes = Files.readAllBytes(Paths.get("file.txt"));
String content = new String(bytes, StandardCharsets.UTF_8);
// 讀取所有行
List<String> lines = Files.readAllLines(Paths.get("file.txt"));
List<String> lines = Files.readAllLines(Paths.get("file.txt"), StandardCharsets.UTF_8);
使用 Stream 逐行讀取
// 適合大檔案
try (Stream<String> lines = Files.lines(Paths.get("file.txt"))) {
lines.forEach(System.out::println);
}
// 處理每一行
try (Stream<String> lines = Files.lines(Paths.get("file.txt"))) {
long count = lines.filter(line -> line.contains("error"))
.count();
}
使用 BufferedReader
適合逐行讀取大型文字檔案:
import java.io.BufferedReader;
import java.io.FileReader;
try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
// 指定編碼
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(new FileInputStream("file.txt"), StandardCharsets.UTF_8))) {
// ...
}
// 使用 Files.newBufferedReader(推薦)
try (BufferedReader reader = Files.newBufferedReader(Paths.get("file.txt"))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
使用 FileInputStream
讀取二進位檔案:
import java.io.FileInputStream;
// 逐個位元組讀取
try (FileInputStream fis = new FileInputStream("image.png")) {
int data;
while ((data = fis.read()) != -1) {
// 處理每個位元組
}
}
// 使用緩衝區
try (FileInputStream fis = new FileInputStream("image.png")) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = fis.read(buffer)) != -1) {
// 處理 buffer 中的 bytesRead 個位元組
}
}
使用 Scanner
方便解析文字:
import java.util.Scanner;
// 讀取檔案
try (Scanner scanner = new Scanner(new File("file.txt"))) {
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
System.out.println(line);
}
}
// 讀取數值
try (Scanner scanner = new Scanner(new File("numbers.txt"))) {
while (scanner.hasNextInt()) {
int number = scanner.nextInt();
System.out.println(number);
}
}
// 使用分隔符
try (Scanner scanner = new Scanner(new File("data.csv"))) {
scanner.useDelimiter(",");
while (scanner.hasNext()) {
String token = scanner.next();
}
}
使用 FileReader
簡單的字元讀取:
import java.io.FileReader;
try (FileReader reader = new FileReader("file.txt")) {
int ch;
while ((ch = reader.read()) != -1) {
System.out.print((char) ch);
}
}
// 使用緩衝區
try (FileReader reader = new FileReader("file.txt")) {
char[] buffer = new char[1024];
int charsRead;
while ((charsRead = reader.read(buffer)) != -1) {
String content = new String(buffer, 0, charsRead);
}
}
讀取資源檔案
讀取 classpath 中的資源:
// 使用 ClassLoader
InputStream is = getClass().getClassLoader().getResourceAsStream("config.properties");
try (BufferedReader reader = new BufferedReader(new InputStreamReader(is))) {
// ...
}
// 使用 Class
InputStream is = MyClass.class.getResourceAsStream("/config.properties");
// 讀取為字串
String content = new String(
getClass().getClassLoader().getResourceAsStream("file.txt").readAllBytes(),
StandardCharsets.UTF_8
);
實際範例
讀取設定檔
public Properties loadProperties(String filename) throws IOException {
Properties props = new Properties();
try (InputStream is = new FileInputStream(filename)) {
props.load(is);
}
return props;
}
// 使用
Properties config = loadProperties("config.properties");
String host = config.getProperty("database.host", "localhost");
讀取 CSV
public List<String[]> readCSV(String filename) throws IOException {
List<String[]> records = new ArrayList<>();
try (BufferedReader reader = Files.newBufferedReader(Paths.get(filename))) {
String line;
while ((line = reader.readLine()) != null) {
String[] values = line.split(",");
records.add(values);
}
}
return records;
}
讀取 JSON(使用 Jackson)
public <T> T readJson(String filename, Class<T> clazz) throws IOException {
ObjectMapper mapper = new ObjectMapper();
return mapper.readValue(new File(filename), clazz);
}
// 使用
User user = readJson("user.json", User.class);
計算檔案行數
public long countLines(String filename) throws IOException {
try (Stream<String> lines = Files.lines(Paths.get(filename))) {
return lines.count();
}
}
搜尋檔案內容
public List<String> searchInFile(String filename, String keyword) throws IOException {
try (Stream<String> lines = Files.lines(Paths.get(filename))) {
return lines.filter(line -> line.contains(keyword))
.collect(Collectors.toList());
}
}
讀取大檔案的特定行
public String readLine(String filename, int lineNumber) throws IOException {
try (Stream<String> lines = Files.lines(Paths.get(filename))) {
return lines.skip(lineNumber - 1)
.findFirst()
.orElse(null);
}
}
方法比較
| 方法 | 適用場景 | 特點 |
|---|---|---|
Files.readString() | 小型文字檔 | 最簡潔 |
Files.readAllLines() | 小型文字檔 | 回傳 List |
Files.lines() | 大型文字檔 | Stream,延遲讀取 |
BufferedReader | 大型文字檔 | 逐行讀取 |
FileInputStream | 二進位檔案 | 位元組讀取 |
Scanner | 解析資料 | 方便解析 |
注意事項
處理編碼
// 明確指定編碼
BufferedReader reader = new BufferedReader(
new InputStreamReader(new FileInputStream("file.txt"), StandardCharsets.UTF_8)
);
// Files 預設使用 UTF-8
List<String> lines = Files.readAllLines(Paths.get("file.txt"));
處理大檔案
// ✗ 不要一次讀取全部
String content = Files.readString(Paths.get("huge.txt")); // 可能 OutOfMemory
// ✓ 使用 Stream 或 BufferedReader
try (Stream<String> lines = Files.lines(Paths.get("huge.txt"))) {
lines.forEach(this::processLine);
}
關閉資源
// ✓ 使用 try-with-resources
try (BufferedReader reader = Files.newBufferedReader(path)) {
// ...
}
// ✓ Stream 也需要關閉
try (Stream<String> lines = Files.lines(path)) {
// ...
}
重點整理
- 小檔案:使用
Files.readString()或Files.readAllLines() - 大檔案:使用
Files.lines()或BufferedReader - 二進位:使用
FileInputStream或Files.readAllBytes() - 一定要使用 try-with-resources 關閉資源
- 明確指定編碼避免亂碼