Java BufferedReader: Hướng dẫn cách đọc một tập tin (có ví dụ)

⚡ Tóm tắt thông minh

Java BufferedReader đọc văn bản từ luồng đầu vào bằng cách đệm các ký tự, giúp việc đọc tệp từng dòng trở nên nhanh chóng và đơn giản. Wrapping một FileReader bên trong BufferedReader và looping Trong hàm `readLine`, cho đến khi nó trả về giá trị null, toàn bộ nội dung tệp sẽ được in ra.

  • ???? Mục đích cốt lõi: BufferedReader bao bọc bất kỳ Reader nào có các thao tác đọc tốn nhiều tài nguyên, giúp giảm số lần đọc riêng lẻ đối với luồng dữ liệu cơ bản.
  • 🔁 Vòng lặp đọc: Hàm readLine trả về một dòng mỗi lần gọi và null khi kết thúc tệp, vì vậy vòng lặp while trên kết quả đó sẽ duyệt toàn bộ tệp.
  • 🧱 Lối thoát hiểm: A Windows đường dẫn bên trong Java Chuỗi cần có dấu gạch chéo ngược kép, nếu không trình biên dịch sẽ từ chối chuỗi thoát không hợp lệ.
  • ♻️ Phát hành tài nguyên: Việc đóng trình đọc sẽ giải phóng bộ điều khiển tệp cơ bản; try-with-resources thực hiện việc đóng đó một cách tự động.
  • ⌨️ Nhập liệu vào bảng điều khiển: Quấnping Việc sử dụng System.in trong InputStreamReader cho phép cùng một lớp đọc dữ liệu nhập từ bàn phím thay vì từ tệp.
  • ⚖️ Độ tương phản của máy quét: BufferedReader nhanh hơn và trả về các dòng thô, trong khi Scanner phân tích cú pháp các token và các kiểu dữ liệu nguyên thủy trực tiếp.
  • 🔤 Lưu ý về mã ký tự: FileReader sử dụng bảng mã ký tự mặc định, vì vậy việc chỉ định một bảng mã ký tự cụ thể sẽ tránh được hiện tượng ký tự bị lỗi trên các máy khác nhau.

BufferedReader ở Java

Cách đọc một tập tin trong Java?

Java Cung cấp một số cơ chế để đọc dữ liệu từ tệp. Gói hữu ích nhất cho việc này là java.io, người có bụngtract Reader Lớp này định nghĩa việc đọc luồng ký tự. java.io.BufferedReader là lớp con cụ thể được sử dụng để đọc dữ liệu theo dòng một cách hiệu quả.

Là gì BufferedReader ở Java?

BufferedReader là một Java Lớp này đọc văn bản từ một luồng đầu vào, chẳng hạn như một tệp, bằng cách đệm các ký tự để các ký tự, mảng và dòng được đọc một cách hiệu quả. Nếu không có bộ đệm, mỗi yêu cầu đọc được thực hiện đối với một Reader sẽ kích hoạt một yêu cầu đọc tương ứng đối với luồng ký tự hoặc byte cơ bản.

Vì vậy nên bọc BufferedReader xung quanh bất kỳ thiết bị đọc sách nào có read() các hoạt động có thể tốn kém, chẳng hạn như FileReaderInputStreamReaderCách sử dụng thông thường là truyền đường dẫn tệp cho trình đọc như sau:

// Note the doubled backslash: a single \ starts an escape sequence
objReader = new BufferedReader(new FileReader("D:\\DukesDiary.txt"));

Thao tác này tải tệp vào objReaderSau đó, bạn lặp qua nội dung của tệp và in từng dòng. Vòng lặp while trong đoạn mã bên dưới sẽ đọc tệp cho đến khi đạt đến cuối tệp.

while ((strCurrentLine = objReader.readLine()) != null) {
    System.out.println(strCurrentLine);
}

strCurrentLine giữ nguyên đường dây hiện tại, và objReader.readLine() Hàm trả về một chuỗi (String). Do đó, vòng lặp sẽ tiếp tục lặp cho đến khi giá trị trả về không phải là null, và dừng lại ở giá trị null đầu tiên, báo hiệu kết thúc tập tin.

BufferVí dụ về edReader

Đoạn mã dưới đây là một đoạn mã hoàn chỉnh. Java BufferVí dụ về edReader:

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

public class ReadFileExample {

    public static void main(String[] args) {
        BufferedReader objReader = null;
        try {
            String strCurrentLine;

            objReader = new BufferedReader(new FileReader("D:\\DukesDiary.txt"));

            while ((strCurrentLine = objReader.readLine()) != null) {
                System.out.println(strCurrentLine);
            }

        } catch (IOException e) {
            e.printStackTrace();

        } finally {
            try {
                if (objReader != null)
                    objReader.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }
}

Lưu ý: finally Khối này rất quan trọng. Nó đảm bảo rằng objReader.close() Chương trình chạy bất kể có ngoại lệ nào được ném ra hay không, giải phóng bộ xử lý tệp cơ bản và giữ nguyên. quản lý bộ nhớ có thể dự đoán được. Thử lồng nhau bên trong finally là cần thiết vì close() Bản thân nó tuyên bố IOException.

BufferVí dụ về edReader JDK7

Từ JDK 7 trở đi, try-with-resources loại bỏ finally chặn hoàn toàn. Bất kỳ tài nguyên nào được khai báo trong dấu ngoặc đơn của try Câu lệnh sẽ tự động đóng khi khối lệnh kết thúc, theo thứ tự ngược lại với thứ tự tạo, ngay cả khi có ngoại lệ xảy ra:

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

public class ReadFileExample_jdk7 {

    private static final String FILENAME = "D:\\DukesDiary.txt";

    public static void main(String[] args) {

        try (BufferedReader br = new BufferedReader(new FileReader(FILENAME))) {

            String strCurrentLine;

            while ((strCurrentLine = br.readLine()) != null) {
                System.out.println(strCurrentLine);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Phiên bản này ngắn gọn và an toàn hơn, vì vậy đây là dạng nên ưu tiên sử dụng trong mã nguồn mới. Việc đọc một tập tin chỉ là một trong những công dụng của lớp này; phần tiếp theo sẽ so sánh nó với phương án thay thế mà hầu hết người mới bắt đầu thường sử dụng đầu tiên.

BufferedReader hay Scanner: Nên dùng loại nào?

Cả hai lớp đều đọc văn bản, và người mới bắt đầu thường chọn một trong hai một cách tùy ý. Chúng giải quyết các vấn đề khác nhau, và sự lựa chọn sai sẽ dẫn đến việc phân tích cú pháp thủ công vụng về hoặc hiệu suất kém khi dữ liệu đầu vào tăng lên đến hàng nghìn dòng. Bảng dưới đây so sánh chúng cạnh nhau.

Yếu tố BufferedReader Máy quét
Hoàn trả Toàn bộ dòng dưới dạng chuỗi Các mã thông báo và phần tử cơ bản đã được phân tích cú pháp
Phân tích cú pháp được tích hợp sẵn Không — bạn tự tách ra hoặc cải đạo. Vâng — nextInt, nextDouble, nextLine
Bộ đệm mặc định 8192 ký tự 1024 ký tự
Tốc độ xử lý các tệp lớn Nhanh hơn Chậm hơn do việc phân tách từ bằng biểu thức chính quy.
An toàn chủ đề Syncđược kim tự hóa Không đồng bộ
Tốt nhất cho Đọc các tệp lớn từng dòng một Ô nhập liệu tương tác nhỏ cần nhập giá trị.

Chọn BufferSử dụng edReader khi mục tiêu là duyệt qua một tập tin nhanh chóng và tự xử lý văn bản, còn Scanner khi bạn muốn nhận các giá trị đã nhập mà không cần viết mã chuyển đổi. Tách mỗi dòng trả về bằng cách sử dụng Phương thức tách chuỗi cho BufferedReader sở hữu hầu hết các tiện ích của Scanner với tốc độ cao hơn.

Cách đọc dữ liệu đầu vào từ bảng điều khiển bằng cách sử dụng BufferedReader

Cùng một lớp này cũng đọc dữ liệu nhập từ bàn phím, điều này hữu ích cho các chương trình dòng lệnh nhỏ và cho việc nhập liệu trong các cuộc thi lập trình. System.in là một luồng byte, vì vậy nó không thể được chuyển giao cho BufferedReader trực tiếp. Một InputStreamReader chuyển đổi byte thành ký tự, và BufferSau đó, edReader bổ sung thêm tính năng đọc dòng hiệu quả lên trên nền tảng đó.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class ReadConsoleExample {

    public static void main(String[] args) throws IOException {

        // Bridge the System.in byte stream to a character stream
        try (BufferedReader reader =
                new BufferedReader(new InputStreamReader(System.in))) {

            System.out.print("Enter your name: ");
            String name = reader.readLine();

            System.out.print("Enter your age: ");
            // readLine always returns text, so convert it explicitly
            int age = Integer.parseInt(reader.readLine().trim());

            System.out.println("Hello " + name + ", age " + age);
        }
    }
}

Có ba chi tiết đáng nhớ. Thứ nhất, readLine() luôn trả về một chuỗi, vì vậy dữ liệu nhập dạng số phải được chuyển đổi bằng Integer.parseInt hoặc tương tự, và việc nhập dữ liệu không phải là số sẽ gây ra lỗi. NumberFormatException — bao bọc quá trình chuyển đổi nếu đầu vào không đáng tin cậy. Thứ hai, gọi .trim() loại bỏ ký tự xuống dòng cuối cùng Windows Các bảng điều khiển thêm vào, một nguyên nhân thường gặp gây ra lỗi phân tích cú pháp. Thứ ba, tránh đóng trình đọc bị kẹt xung quanh System.in nếu chương trình vẫn cần nhập dữ liệu từ console sau này, vì việc đóng trình bao bọc sẽ đóng vĩnh viễn luồng dữ liệu cơ bản cho tiến trình đó.

Đối với các chương trình đọc nhiều giá trị, việc đọc một dòng và tách nó ra sẽ nhanh hơn nhiều so với việc gọi hàm. readLine() Lặp đi lặp lại, vì mỗi lệnh gọi chỉ được thực thi trong hệ điều hành khi bộ đệm trống. Đây là lý do chính khiến các lập trình viên thi đấu ưa chuộng phương pháp này. BufferedReader thay thế máy quét để nhập dữ liệu hàng loạt.

Ngay cả khi mã nguồn chính xác, một số lỗi vẫn xuất hiện lặp đi lặp lại.

Chung BufferCác lỗi của edReader và cách khắc phục chúng

Hầu hết BufferCác lỗi của edReader xuất phát từ đường dẫn tệp, xử lý tài nguyên hoặc mã hóa ký tự chứ không phải từ chính vòng lặp đọc. Mỗi lỗi bên dưới đều nêu rõ ngoại lệ và cách khắc phục.

  • Nhân vật trốn thoát bất hợp pháp: Đường dẫn sử dụng một dấu gạch chéo ngược duy nhất, như trong "D:\DukesDiary.txt". Double nó để "D:\\DukesDiary.txt"hoặc sử dụng dấu gạch chéo, Java chấp nhận trên Windows.
  • FileNotFoundException: Đường dẫn này là đường dẫn tương đối so với thư mục làm việc hiện tại, chứ không phải tệp nguồn. In new File(name).getAbsolutePath() để xem ở đâu Java Thực ra đang quan sát.
  • Lỗi NullPointerException xảy ra khi đọc lần đầu: Đối tượng đọc (reader) chưa bao giờ được gán vì hàm tạo (constructor) đã ném ra ngoại lệ và ngoại lệ đó đã bị bỏ qua. Hãy kiểm tra lại. xử lý ngoại lệ trước vòng lặp.
  • Các ký tự bị xáo trộn hoặc có dấu hỏi: Tệp tin này là UTF-8 nhưng FileReader Đã áp dụng bảng mã ký tự mặc định của nền tảng. Hãy truyền bảng mã ký tự một cách rõ ràng, ví dụ: new InputStreamReader(new FileInputStream(f), StandardCharsets.UTF_8).
  • Luồng phát đã đóng: Trình đọc đã bị đóng bên trong vòng lặp hoặc được sử dụng lại sau khi quá trình thử với tài nguyên kết thúc. Hãy mở một trình đọc mới cho mỗi lần xử lý tệp.

Câu Hỏi Thường Gặp

Đúng vậy. Tham số thứ hai của hàm tạo sẽ thiết lập bộ đệm theo ký tự, ví dụ như... new BufferedReader(reader, 16384)Giá trị mặc định 8192 phù hợp với hầu hết các tập tin; việc tăng giá trị này chỉ hữu ích với các tập tin đọc tuần tự rất lớn.

Đối với các tập tin nhỏ, câu trả lời là có — nó trả về một danh sách các dòng trong một lần gọi. Đối với các tập tin lớn, hãy sử dụng phương pháp khác. Files.newBufferedReader or Files.lines, bởi vì hàm readAllLines giữ toàn bộ nội dung tệp trong bộ nhớ cùng một lúc.

Vâng. AI Các trợ lý sẽ viết lại quá trình dọn dẹp khối finally thành try-with-resources và đề xuất các phương án tương đương của NIO. Sau đó, hãy xác minh bộ mã ký tự và hành vi xử lý ngoại lệ, vì các chuyển đổi được tạo ra thường bỏ qua mã hóa rõ ràng.

Trí tuệ nhân tạo đọc ngăn xếp tracCông cụ này xác định xem nguyên nhân là do thư mục làm việc không chính xác, thiếu quyền truy cập hay không khớp mã hóa. Nó giúp rút ngắn thời gian chẩn đoán, mặc dù việc khắc phục vẫn cần được xác minh lại với tệp thực tế.

Không. Hàm readLine loại bỏ ký tự xuống dòng, vì vậy chuỗi trả về sẽ không chứa ký tự xuống dòng ở cuối. Do đó, một dòng trống trong tệp sẽ trả về một chuỗi trống chứ không phải là null.

Tóm tắt bài viết này với: