2012-04-22 41 views
14

Trong mỗi lần thực hiện Java tôi thấy đọc từ một tập tin, tôi hầu như luôn luôn nhìn thấy một trình đọc tập tin được sử dụng để đọc từng dòng. Tôi nghĩ rằng điều này sẽ vô cùng hiệu quả bởi vì nó đòi hỏi một cuộc gọi hệ thống trên mỗi dòng.Java - đọc từ một tệp. Đầu vào dòng vs đầu đọc

Điều tôi đã làm thay vào đó là sử dụng luồng đầu vào và lấy trực tiếp các byte. Trong các thí nghiệm của tôi, điều này nhanh hơn đáng kể. Thử nghiệm của tôi là một tệp 1MB.

//Stream method 
    try { 
     Long startTime = new Date().getTime(); 

     InputStream is = new FileInputStream("test"); 
     byte[] b = new byte[is.available()]; 
     is.read(b); 
     String text = new String(b); 
     //System.out.println(text); 

     Long endTime = new Date().getTime(); 
     System.out.println("Text length: " + text.length() + ", Total time: " + (endTime - startTime)); 

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

    //Reader method 
    try { 
     Long startTime = new Date().getTime(); 

     BufferedReader br = new BufferedReader(new FileReader("test")); 
     String line = null; 
     StringBuilder sb = new StringBuilder(); 
     while ((line = br.readLine()) != null) { 
      sb.append(line); 
      sb.append("\n"); 
     } 
     String text = sb.toString(); 

     Long endTime = new Date().getTime(); 
     System.out.println("Text length: " + text.length() + ", Total time: " + (endTime - startTime)); 

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

này đưa ra một kết quả của:

Text length: 1054631, Total time: 9 
Text length: 1034099, Total time: 22 

Vì vậy, tại sao mọi người sử dụng độc giả thay vì suối?

Nếu tôi có phương thức lấy tệp văn bản và trả về một Chuỗi chứa tất cả văn bản, có nhất thiết phải làm điều đó bằng cách sử dụng luồng không?

+0

Mã của bạn không chính xác. Nó không đảm bảo rằng nó sẽ đọc toàn bộ tập tin, xem tài liệu của các phương pháp đọc và sẵn có. – Milo

+1

Bạn đã thử dùng [java.nio.File] (http://docs.oracle.com/javase/7/docs/api/java/nio/file/Files.html) Files.readAllLines của gói (.. .) phương pháp. –

+0

+1 để tìm hiểu điều gì đó mới – panny

Trả lời

10

Bạn đang so sánh táo với chuối. Đọc một dòng tại một thời điểm sẽ kém hiệu quả hơn ngay cả với một bufferedReader hơn là lấy dữ liệu càng nhanh càng tốt. Lưu ý rằng việc sử dụng có sẵn không được khuyến khích vì nó không chính xác trong mọi tình huống. Tôi đã tìm ra điều này khi tôi bắt đầu sử dụng các dòng mật mã.

+0

Điều đó rất thú vị. Có sẵn nguy hiểm khi đọc từ một tệp văn bản thuần túy tồn tại trên hệ thống tệp cục bộ không? – Jeremy

+0

@Jeremy Không bao giờ đúng khi sử dụng ['available'] (http://docs.oracle.com/javase/7/docs/api/java/io/InputStream.html#available()) để cấp phát bộ đệm cho toàn bộ luồng. – Jeffrey

+0

@ Jeffrey Nếu bạn có nó, tôi rất muốn thấy bất kỳ tài nguyên nào bạn có trên đó. Trước đây, tôi đã sử dụng khá sẵn lòng mà không gặp phải bất kỳ vấn đề nào. Tôi tin rằng bạn, nhưng tôi tự hỏi nếu có thực sự là một tình huống mà có sẵn là thích hợp. – Jeremy

3

FileReader thường được sử dụng kết hợp với BufferedReader vì thường xuyên có ý nghĩa để đọc từng dòng tệp, đặc biệt nếu tệp có cấu trúc bản ghi được xác định rõ ràng trong đó mỗi bản ghi tương ứng với một dòng.

Ngoài ra, FileReader thể đơn giản hóa một số công việc để đối phó với bảng mã ký tự và chuyển đổi, như đã nêu trong javadocs: lớp

Thuận tiện cho việc đọc các file nhân vật. Các hàm tạo của lớp này giả định rằng mã hóa ký tự mặc định và kích thước bộ đệm byte mặc định là thích hợp ... FileReader có nghĩa là để đọc các dòng ký tự.

3

Hãy thử tăng BufferedReader kích thước bộ đệm. Ví dụ:

BufferedReader br = new BufferedReader(new FileReader("test"),2000000); 

Nếu bạn chọn kích thước bộ đệm phù hợp, bạn sẽ nhanh hơn.

Sau đó, trong mẫu của bạn với Reader bạn dành nhiều thời gian lấp đầy StringBuilder. Bạn phải đọc từng dòng một nếu bạn cần xử lý các dòng. Nhưng nếu bạn chỉ cần đọc một văn bản trong một chuỗi sau đó đọc đoạn văn bản lớn hơn với public int read(char[] cbuf) và viết các khối trong một StringWriter được khởi tạo với kích thước phù hợp.

Chọn sử dụng InputStream hoặc Reader không phụ thuộc vào hiệu suất. Nói chung, bạn sử dụng Reader khi đọc dữ liệu văn bản, vì với trình đọc, bạn có thể xử lý dễ dàng hơn bộ ký tự.

điểm khác, mã của bạn ở đây

byte[] b = new byte[is.available()]; 
is.read(b); 
String text = new String(b); 

nó không phải là chính xác. documentation cho biết

Lưu ý rằng trong khi một số triển khai InputStream sẽ trả về tổng số byte trong luồng, nhiều người sẽ không. Không bao giờ đúng khi sử dụng giá trị trả về của phương thức này để cấp phát bộ đệm nhằm chứa tất cả dữ liệu trong luồng này.

vì vậy hãy chú ý, bạn cần khắc phục.

+0

Tự cung cấp kích thước bộ đệm dường như tác động tiêu cực đến hiệu suất đối với tôi. – Jeremy

+0

Tệp của bạn lớn đến mức nào? Bạn dành bao nhiêu đống cho JVM của mình? – dash1e

Các vấn đề liên quan