Đọc tất cả văn bản từ một tập tin
Java 11 đã thêm phương thức readString () để đọc các tệp nhỏ dưới dạng String
, bảo toàn các đầu cuối dòng:
String content = Files.readString(path, StandardCharsets.US_ASCII);
Đối với các phiên bản giữa Java 7 và 11, đây là một thành ngữ nhỏ gọn, mạnh mẽ, được gói gọn trong một phương thức tiện ích:
static String readFile(String path, Charset encoding)
throws IOException
{
byte[] encoded = Files.readAllBytes(Paths.get(path));
return new String(encoded, encoding);
}
Đọc các dòng văn bản từ một tập tin
Java 7 đã thêm một phương thức tiện lợi để đọc tệp dưới dạng các dòng văn bản, được biểu diễn dưới dạng a List<String>
. Cách tiếp cận này là "mất mát" vì các dấu phân cách dòng bị tước khỏi cuối mỗi dòng.
List<String> lines = Files.readAllLines(Paths.get(path), encoding);
Java 8 đã thêm Files.lines()
phương thức để tạo ra a Stream<String>
. Một lần nữa, phương pháp này là mất mát vì dải phân cách bị tước. Nếu một IOException
gặp phải trong khi đọc tệp, nó được bọc trong một UncheckedIOException
, vì Stream
không chấp nhận lambdas ném ngoại lệ được kiểm tra.
try (Stream<String> lines = Files.lines(path, encoding)) {
lines.forEach(System.out::println);
}
Điều này Stream
không cần một close()
cuộc gọi; đây là tài liệu kém về API và tôi nghi ngờ nhiều người thậm chí không nhận thấy Stream
cóclose()
phương pháp. Hãy chắc chắn sử dụng một khối ARM như được hiển thị.
Nếu bạn đang làm việc với một nguồn khác ngoài một tệp, bạn có thể sử dụng lines()
phương thức BufferedReader
thay thế.
Sử dụng bộ nhớ
Phương thức đầu tiên, bảo toàn ngắt dòng, có thể tạm thời yêu cầu bộ nhớ nhiều lần kích thước của tệp, vì trong một thời gian ngắn, nội dung tệp thô (một mảng byte) và các ký tự được giải mã (mỗi ký tự là 16 bit ngay cả khi được mã hóa như 8 bit trong tệp) nằm trong bộ nhớ cùng một lúc. An toàn nhất là áp dụng cho các tệp mà bạn biết là nhỏ so với bộ nhớ khả dụng.
Phương thức thứ hai, đọc các dòng, thường hiệu quả hơn về bộ nhớ, bởi vì bộ đệm byte đầu vào để giải mã không cần phải chứa toàn bộ tệp. Tuy nhiên, nó vẫn không phù hợp với các tệp rất lớn so với bộ nhớ khả dụng.
Để đọc các tệp lớn, bạn cần một thiết kế khác cho chương trình của mình, một tệp đọc một đoạn văn bản từ một luồng, xử lý nó và sau đó chuyển sang tiếp theo, sử dụng lại khối bộ nhớ có kích thước cố định tương tự. Ở đây, "lớn" phụ thuộc vào thông số kỹ thuật của máy tính. Ngày nay, ngưỡng này có thể là nhiều gigabyte RAM. Phương pháp thứ ba, sử dụng một Stream<String>
là một cách để làm điều này, nếu "bản ghi" đầu vào của bạn là các dòng riêng lẻ. (Sử dụng readLine()
phương pháp BufferedReader
là thủ tục tương đương với phương pháp này.)
Mã hóa ký tự
Một điều còn thiếu từ mẫu trong bài viết gốc là mã hóa ký tự. Có một số trường hợp đặc biệt trong đó mặc định nền tảng là những gì bạn muốn, nhưng chúng rất hiếm và bạn có thể biện minh cho sự lựa chọn của mình.
Các StandardCharsets
lớp định nghĩa một số hằng số cho mã hóa cần thiết của tất cả các runtimes Java:
String content = readFile("test.txt", StandardCharsets.UTF_8);
Giá trị mặc định nền tảng có sẵn từ các Charset
lớp học riêng của mình:
String content = readFile("test.txt", Charset.defaultCharset());
Lưu ý: Câu trả lời này phần lớn thay thế phiên bản Java 6 của tôi. Tiện ích của Java 7 đơn giản hóa mã một cách an toàn và câu trả lời cũ, sử dụng bộ đệm byte được ánh xạ, ngăn không cho tệp đã đọc bị xóa cho đến khi bộ đệm được ánh xạ được thu gom rác. Bạn có thể xem phiên bản cũ thông qua liên kết "đã chỉnh sửa" trong câu trả lời này.