2011-09-13 4 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(); 
    } 
} 

코드는 일 JVM 실행 윈도우 XP OS와, 7200 RPM으로 HDD 시스템에서 1.2 초 80MB의 데이터를 판독한다. 하지만 필자가 작성한 코드에 만족하지는 않습니다. 더 좋은 방법으로 이것을 쓰는 다른 방법이 있습니까 (특히 문자 세트에 대한 디코딩과 읽은 바이트 만 가져 오는 것, 나는 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의 위치는 0이고 제한은 numberOfBytes이므로 charset.decode() 작업은 이미 정확한 양의 데이터를 제공하고 있습니다.

  4. FileChannel.read()에서 짧은 읽지 않은 것으로 가정합니다. 당신은 그 가정을 뒷받침 할 Javadoc에는 아무것도 없다고 생각할 수 없습니다. 버퍼가 가득 차거나 EOF를받을 때까지 읽어야합니다.

내가 또한 FileInputStream에 주위하는 InputStreamReader 주위의 BufferedReader 실험, 그냥 한 번에 128 개 문자를 읽을 것, 모든 것을 가졌어요. 어떤 것이 더 빠르다는 사실에 놀랄 수도 있습니다.

관련 문제