2011-09-13 14 views
1

フラットファイルからレコードを読み取る必要があります。フラットファイルは、それぞれ128バイトが論理レコードを構成します。以下の読者の呼び出しモジュールは、以下のことを行います。このIOコードをどのようにリファクタリングするのですか?

while(iterator.hasNext()){ 
    iterator.next(); 
    //do Something 
} 

は、すべてのhasNext()呼び出しの後next()コールがあることを意味します。

ここで読者になります。

public class FlatFileiteratorReader implements Iterable<String> { 

    FileChannel fileChannel; 

public FlatFileiteratorReader(FileInputStream fileInputStream) { 
    fileChannel = fileInputStream.getChannel(); 
} 

private class SampleFileIterator implements Iterator<String> { 
    Charset charset = Charset.forName("ISO-8859-1"); 
    ByteBuffer byteBuffer = MappedByteBuffer.allocateDirect(128 * 100); 
    LinkedList<String> recordCollection = new LinkedList<String>(); 
    String record = null; 

    @Override 
    public boolean hasNext() { 
     if (!recordCollection.isEmpty()) { 
      record = recordCollection.poll(); 
      return true; 
     } else { 
      try { 
       int numberOfBytes = fileChannel.read(byteBuffer); 
       if (numberOfBytes > 0) { 
        byteBuffer.rewind(); 
        loadRecordsIntoCollection(charset.decode(byteBuffer) 
          .toString().substring(0, numberOfBytes), 
          numberOfBytes); 
        byteBuffer.flip(); 
        record = recordCollection.poll(); 
        return true; 
       } 
      } catch (IOException e) { 
       // Report Exception. Real exception logging code in place 
      } 
     } 
     try { 
      fileChannel.close(); 
     } catch (IOException e) { 
      // TODO Report Exception. Logging 
     } 
     return false; 

    } 

    @Override 
    public String next() { 
     return record; 
    } 

    @Override 
    public void remove() { 
     // NOT required 

    } 

    /** 
    * 
    * @param records 
    * @param length 
    */ 
    private void loadRecordsIntoCollection(String records, int length) { 
     int numberOfRecords = length/128; 
     for (int i = 0; i < numberOfRecords; i++) { 
      recordCollection.add(records.substring(i * 128, (i + 1) * 128)); 
     } 
    } 

} 

    @Override 
    public Iterator<String> iterator() { 
     return new SampleFileIterator(); 
    } 
} 

コードは、Sun JVMと動作しているWindows XPのOSで、7200 RPM HDDを持つマシン上で1.2秒のデータの80メガバイトを読み込みます。しかし、私が書いたコードには満足していません。特に、キャラクタセットのデコードと、読み込まれたバイトだけを取ることは、charset.decode(byteBuffer) .toString().substring(0, numberOfBytes)の部分を意味します。//TODOのものを無視してください)?

+1

これはおそらく、http://codereview.stackexchange.comのより良い質問です。 –

+2

私はこれをcodereviewに載せるべきだとMattに同意します。あなたがそこに投稿するとき、あなたが満足していないものが含まれていることを確認してください。 –

+0

@Matt Ball私はそこでより良い答えが得られるかどうか恐れる。オプションがあれば、ここに質問があります。 – nobody

答えて

1
  1. ここで直接バッファを使用することは特に利点はありません。あなたはJNIの境界を越えてJavaの土地にデータを取得しなければならないので、通常のByteBufferを使うこともできます。ダイレクトバッファは、実際に自分自身を見たくないときにデータをコピーするためのものです。

  2. たとえば512の倍数であるByteBufferを使用します。 8192を使用しているため、I/Oシステムとディスクコントローラをセクタ境界を越えたリードで狂わせることはありません。この場合、私はあなたのレコードの長さに同意するために128 * 512を使用することについて考えます。

  3. .substring(0, numberOfBytes)は不要です。読み込みと巻き戻しの後、ByteBufferの位置はゼロであり、その限界はnumberOfBytesに等しいので、charset.decode()オペレーションはすでに正しい量のデータを提供しています。

  4. あなたは、FileChannel.read()から短い読み込みを取得していないと仮定しています。あなたはそれを仮定することはできません、その仮定をサポートするためにJavadocには何もありません。バッファーがいっぱいになるか、EOFを受け取るまで読む必要があります。

はすべてのことを言って、私はまた、FileInputStreamの周りにInputStreamReaderの周りをBufferedReaderで実験し、ジャストインタイムで128個の文字を読んでいました。より速いのは驚きです。

関連する問題