2013-04-06 35 views
10

Tôi có một tệp văn bản (XML được tạo bằng XStream) dài 63.000 dòng (3,5 MB). Tôi đang cố gắng đọc nó bằng cách sử dụng bộ đọc Buffered:Tập tin văn bản dài đọc Java rất chậm

   BufferedReader br = new BufferedReader(new FileReader(file)); 
       try { 
        String s = ""; 
        String tempString; 
        int i = 0; 
        while ((tempString = br.readLine()) != null) { 
         s = s.concat(tempString); 
//      s=s+tempString; 
         i = i + 1; 
         if (i % 1000 == 0) { 
          System.out.println(Integer.toString(i)); 
         } 
        } 
        br.close(); 

Tại đây bạn có thể thấy các nỗ lực của tôi để đo tốc độ đọc. Và nó rất thấp. Phải mất vài giây để đọc 1000 dòng sau 10000 dòng. Tôi đang làm điều gì đó sai, nhưng không thể hiểu được. Cảm ơn trước sự giúp đỡ của bạn.

+0

Mục đích của bạn là phân tích cú pháp tệp này? Tại sao không chỉ tải nó bằng Xerces/SAX/công cụ phân tích cú pháp khác? –

+10

Chuỗi '+' và 'concat' rất không hiệu quả nếu các chuỗi là lớn. Sử dụng 'StringBuilder' hoặc chuyển trực tiếp' InputStream'/'Reader' tới trình phân tích cú pháp xml. –

+0

Hoặc nếu bạn thực sự cần dòng, hãy sử dụng một cái gì đó như thế này - http://commons.apache.org/proper/commons-io/javadocs/api-2.4/org/apache/commons/io/IOUtils.html#readLines%28java .io.Reader% 29. –

Trả lời

4

@PaulGrime là đúng. Bạn đang sao chép chuỗi mỗi lần vòng lặp đọc một dòng. Một khi chuỗi được lớn (nói 10.000 dòng lớn), nó đang làm rất nhiều công việc để làm điều đó sao chép.

Hãy thử điều này:

StringBuilder sb = new StringBuilder(); 
while (...reading lines..){ 
    .... 
    sb.append(tempString); //should add newline 
    ... 
} 

s = sb.toString(); 

Lưu ý: đọc câu trả lời của Paul dưới đây về lý do tại sao tước dòng mới làm cho điều này một cách xấu để đọc trong một tập tin. Ngoài ra, như đã đề cập trong các bình luận câu hỏi, XStream cung cấp một cách để đọc các tập tin và ngay cả khi nó đã không, IOUtils.toString (đọc) sẽ là một cách an toàn hơn để đọc một tập tin.

+0

Cảm ơn! Thực sự tăng tốc tải lên. – lozga

+1

-1 hiệu suất phạt chỉ là không sao chép, Stringbuilder là một trong những tư vấn trong tài liệu, 'PaulGrime là đúng' không thực sự là một câu trả lời xứng đáng được chấp nhận ... và 10000? tại sao? – UmNyobe

+0

Tôi đã nói "10.000" nghĩa là "ví dụ, khi 10.000 dòng lớn". Tôi cũng giải thích tại sao Paul đã đúng và đưa ra một ví dụ về mã. Ngoài ra, vui lòng làm rõ ý của bạn bằng cách "không chỉ sao chép". –

4

Một số cải tiến ngay lập tức bạn có thể làm:

  • Sử dụng một StringBuilder thay vì concat+. Sử dụng +concat thực sự có thể ảnh hưởng đến hiệu suất, đặc biệt khi được sử dụng trong các vòng lặp.
  • Giảm quyền truy cập vào đĩa. Bạn có thể thực hiện việc này bằng cách sử dụng một số large buffer:

    BufferedReader br = new BufferedReader (tệp FileReader mới ("someFile.txt"), SIZE);

1

Bạn nên sử dụng một StringBuilder như String nối là cực kỳ chậm cho chuỗi thậm chí nhỏ.

Hơn nữa, hãy thử sử dụng NIO thay vì BufferedReader.

public static void main(String[] args) throws IOException { 
    final File file = //some file 
    try (final FileChannel fileChannel = new RandomAccessFile(file, "r").getChannel()) { 
     final StringBuilder stringBuilder = new StringBuilder(); 
     final ByteBuffer byteBuffer = ByteBuffer.allocate(1024); 
     final CharsetDecoder charsetDecoder = Charset.forName("UTF-8").newDecoder(); 
     while (fileChannel.read(byteBuffer) > 0) { 
      byteBuffer.flip(); 
      stringBuilder.append(charsetDecoder.decode(byteBuffer)); 
      byteBuffer.clear(); 
     } 
    } 
} 

Bạn có thể điều chỉnh kích thước bộ đệm nếu kích thước bộ đệm quá chậm - phụ thuộc nhiều vào kích thước bộ đệm hoạt động tốt hơn. Đối với tôi, nó tạo ra rất ít sự khác biệt nếu bộ đệm là 1K hoặc 4K nhưng trên các hệ thống khác tôi đã biết rằng thay đổi để tăng tốc độ theo thứ tự độ lớn.

1

Ngoài những gì đã được nói, tùy thuộc vào việc bạn sử dụng XML, mã của bạn có khả năng không chính xác vì nó hủy bỏ kết thúc dòng. Ví dụ, đoạn mã này:

package temp.stackoverflow.q15849706; 

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

import com.thoughtworks.xstream.XStream; 

public class ReadXmlLines { 
    public String read1(BufferedReader br) throws IOException { 
     try { 
      String s = ""; 
      String tempString; 
      int i = 0; 
      while ((tempString = br.readLine()) != null) { 
       s = s.concat(tempString); 
       // s=s+tempString; 
       i = i + 1; 
       if (i % 1000 == 0) { 
        System.out.println(Integer.toString(i)); 
       } 
      } 
      return s; 
     } finally { 
      br.close(); 
     } 
    } 

    public static void main(String[] args) throws IOException { 
     ReadXmlLines r = new ReadXmlLines(); 

     URL url = ReadXmlLines.class.getResource("xml.xml"); 
     String xmlStr = r.read1(new BufferedReader(new InputStreamReader(url 
       .openStream()))); 

     Object ob = null; 

     XStream xs = new XStream(); 
     xs.alias("root", Root.class); 

     // This is incorrectly read/parsed, as the line endings are not 
     // preserved. 
     System.out.println("----------1"); 
     System.out.println(xmlStr); 
     ob = xs.fromXML(xmlStr); 
     System.out.println(ob); 

     // This is correctly read/parsed, when passing in the URL directly 
     ob = xs.fromXML(url); 
     System.out.println("----------2"); 
     System.out.println(ob); 

     // This is correctly read/parsed, when passing in the InputStream 
     // directly 
     ob = xs.fromXML(url.openStream()); 
     System.out.println("----------3"); 
     System.out.println(ob); 
    } 

    public static class Root { 
     public String script; 

     public String toString() { 
      return script; 
     } 
    } 
} 

và tập tin xml.xml này trên classpath (trong gói giống như lớp):

<root> 
    <script> 
<![CDATA[ 
// taken from http://www.w3schools.com/xml/xml_cdata.asp 
function matchwo(a,b) 
{ 
if (a < b && a < 0) then 
    { 
    return 1; 
    } 
else 
    { 
    return 0; 
    } 
} 
]]> 
    </script> 
</root> 

xuất ra như sau. Hai dòng đầu tiên cho thấy kết thúc dòng đã bị loại bỏ, và do đó làm cho Javascript trong phần CDATA không hợp lệ (như nhận xét JS đầu tiên bây giờ nhận xét ra toàn bộ JS, vì các dòng JS đã được hợp nhất).

----------1 
<root> <script><![CDATA[// taken from http://www.w3schools.com/xml/xml_cdata.aspfunction matchwo(a,b){if (a < b && a < 0) then { return 1; }else { return 0; }}]]> </script></root> 
// taken from http://www.w3schools.com/xml/xml_cdata.aspfunction matchwo(a,b){if (a < b && a < 0) then { return 1; }else { return 0; }}  
----------2 


// taken from http://www.w3schools.com/xml/xml_cdata.asp 
function matchwo(a,b) 
{ 
if (a < b && a < 0) then 
    { 
    return 1; 
    } 
else 
    { 
    return 0; 
    } 
} 
... 
Các vấn đề liên quan