2013-04-06 55 views
10

63000行(3.5MB)のテキストファイル(XStreamで作成されたXML)があります。あなたは読み出し速度を測定するために、私の試みを見ることができます。ここJavaの長いテキストファイルの読み込みが非常に遅い

   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(); 

:私は、バッファリーダーを使用して、それを読むことをしようとしています。そしてそれは非常に低いです。 10000行後に1000行を読み込むには数秒かかります。私は明らかに何か間違っているが、理解できない。あなたの助けを前にありがとう。

+0

このファイルを解析する予定はありますか? Xerces/SAX /その他の解析ツールを使って読み込むのはなぜですか? –

+10

文字列が大きい場合、文字列 '+'と 'concat'は非常に非効率です。 'StringBuilder'を使うか、' InputStream'/'Reader'をXMLパーサーに直接渡してください。 –

+0

本当に必要な場合は、次のようなものを使用してください。http://commons.apache.org/proper/commons-io/javadocs/api-2.4/org/apache/commons/io/IOUtils.html#readLines%28java .io.Reader%29。 –

答えて

4

@PaulGrimeが正しいです。ループが行を読み取るたびに文字列をコピーしています。文字列が大きくなると(10,000行が大きいと)、そのコピーを行うために多くの作業が行われています。

これを試してみてください:

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

s = sb.toString(); 

注:ストリッピングなぜ改行の下のポールの答えを読んで、このファイルを読み込むための悪い方法になります。また、質問のコメントに記載されているように、XStreamはファイルを読み取る方法を提供していますが、そうでない場合でもIOUtils.toString(リーダー)はファイルを安全に読み取る方法になります。

+0

ありがとう!本当にスピードアップ。 – lozga

+1

-1パフォーマンスペナルティはただコピーしていないだけですが、Stringbuilderはドキュメントでアドバイスされたものです。 'PaulGrime is right'は本当に受け入れられる回答ではありません...そして10000?どうして? – UmNyobe

+0

私は「10,000行」と言った。「10,000行が大きいときなど」を意味する。ポールが正しい理由を説明し、コード例を示しました。また、「コピーするだけではない」という意味を明確にしてください。 –

4

あなたが行うことができますいくつかの即時の改善:

  • 代わりconcat+StringBuilderを使用してください。 +concatを使用すると、特にループで使用されたときにパフォーマンスに実際に影響する可能性があります。
  • ディスクへのアクセスを減らしてください。 large buffer

    BufferedReader br =新しいBufferedReader(新しいFileReader( "someFile.txt")、SIZE);を使用すると、これを行うことができます。

1

あなたはStringBuilderStringとして連結が小さくても、文字列のための極めて遅い使用する必要があります。

また、BufferedReaderではなくNIOを使用してください。

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(); 
     } 
    } 
} 

バッファーサイズがまだ遅すぎる場合は調整することができます。バッファーサイズはシステムによって大きく左右されます。私にとっては、バッファが1Kまたは4Kであれば、それほど大きな違いはありませんが、私が知っている他のシステムでは、スピードを1桁上げるために変化があります。

1

XMLの使用方法によっては、既に記述されていることに加えて、行末を破棄するため、コードが誤っている可能性があります。例えば、このコード:

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; 
     } 
    } 
} 

及び(クラスと同じパッケージ内の)クラスパスにこのxml.xmlファイル:

<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> 

は、以下の出力を生成します。最初の2行は、行末が削除されたことを示しているため、CDATAセクションのJavascriptが無効になっています(JS行がマージされているため、

----------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; 
    } 
} 
... 
関連する問題