2013-02-27 3 views
2

java.lang.OutOfMemoryError : 코드를 실행할 때마다 Java 힙 공간이 발생합니다. 그러나 특정 인스턴스에서 스트림을 닫으면 오류가 사라지지만 스트림이 너무 빨리 닫히기 때문에 데이터가 누락됩니다.바이트 스트림을 관리하고 스트림을 닫는 방법

저는 Java에 익숙하지 않아 스트림을 관리하는 방법을 분명히 이해하지 못했습니다. 언제 어떻게 스트림을 닫아야합니까?

private void handleFile(File source) 
{ 
    FileInputStream fis = null; 

    try 
    { 
     if(source.isFile()) 
     { 
      fis = new FileInputStream(source); 
      handleFile(source.getAbsolutePath(), fis); 
     } 
     else if(source.isDirectory()) 
     { 
      for(File file:source.listFiles()) 
      { 
       if(file.isFile()) 
       { 
        fis = new FileInputStream(file); 
        handleFile(file, fis); 
       } 
       else 
       { 
        handleFile(file); 
       } 
      } 
     } 
    } 
    catch(IOException ioe) 
    { 
     ioe.printStackTrace(); 
    } 
    finally 
    { 
     try 
     { 
      if(fis != null) { fis.close(); } 
     } 
     catch(IOException ioe) { ioe.printStackTrace(); } 
    } 
} 

private handleFile(String fileName, InputStream inputStream) 
{ 
    try 
    { 
     byte[] initialBytes = isToByteArray(inputStream); 
     byte[] finalBytes = initialBytes; 

     if(initialBytes.length == 0) return; 

     if(isBytesTypeB(initialBytes)) 
     { 
      finalBytes = getBytesTypeB(startingBytes); 
     } 
     // Other similar method checks 
     // ..... 

     map.put(fileName, finalBytes); 
    } 
    catch(IOException ioe) 
    { 
     ioe.printStackTrace(); 
    } 
} 

private byte[] isToByteArray(InputStream inputStream) 
{ 
    ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
    byte[] buffer = new byte[1024]; 

    int nRead; 
    while((nRead = inputStream.read(buffer)) != -1) 
    { 
     baos.write(buffer, 0, nRead); 
    } 
    return baos.toByteArray(); 
} 

private boolean isBytesTypeB(byte[] fileBytes) 
{ 
    // Checks if these bytes match a particular type 
    if(BytesMatcher.matches(fileBytes, fileBytes.length)) 
    { 
     return true; 
    } 
    return false; 
} 

private byte[] getBytesTypeB(byte[] fileBytes) 
{ 
    //decompress bytes 

    return decompressedBytes; 
} 
+1

파일의 크기는 얼마나됩니까? – Ingo

+0

5 - 10 Mb. –

+0

Ohh .. combined. 나는 잘 모르겠다. 디렉토리에 대해 프로그램을 실행하고, 각 파일의 바이트를 읽고, 그 바이트로 작업 한 다음 fileName과 그 바이트로 이루어진 작업을 맵에 저장합니다. –

답변

2

우선 메모리의 전체 스트림을 읽지 마십시오. 읽고 쓸 때 버퍼를 사용하십시오.

매우 작은 스트림 (일부 작업을 위해 다시 사용해야하는 데이터)을 읽었을 것으로 확신하는 경우에만 ByteArrayInputStreamByteArrayInputStream을 사용하고 데이터를 메모리에 보관하는 것이 좋습니다. 그렇지 않으면 신속하게 (또는 예기치 않게) 메모리가 부족합니다.

try-catch 블록 외부의 스트림을 정의하고 finally 블록에서 스트림을 닫습니다 (null이 아닌 경우). 예를 들면 다음과 같습니다.

void doSomeIOStuff() throws IOException 
{ 
    InputStream is = null; 

    try 
    { 
     is = new MyInputStream(...); 
     // Do stuff 
    } 
    catch (IOException ioExc) 
    { 
     // Either just inform (poor decision, but good for illustration): 
     ioExc.printStackTrace(); 
     // Or re-throw to delegate further on: 
     throw new IOException(ioExc); 
    } 
    finally 
    { 
     if (is != null) 
     { 
      is.close(); 
     } 
    } 
} 

이렇게하면 사용 후 리소스가 항상 올바르게 닫힙니다.

호기심에서 벗어나서 handleFile(...) 방법은 실제로 무엇을 수행해야합니까?

+0

carlspring, 매우 유익한 게시물에 감사드립니다! 그 바이트에 대해 계산을 수행하는 클래스를 인스턴스화하는 데 사용되므로 분명히 해당 바이트를 사용하고 있습니다. 그러면 해당 클래스의 객체가지도에 저장됩니다. –

+0

아, handleFile 메서드는 다른 메서드 (입력하지 않았 음)에서 재귀 적으로 보관 파일을 확인하고 스트림을 handleFile 메서드에 전달하기 때문에 스트림을 받아들입니다. –

+1

글쎄, 보여준 코드가 옳았다. 내가 이해하는 것으로부터, 당신은 감압을하려는 것입니다. 'java.nio'의'ByteBuffer' 클래스와 메모리 매핑 클래스를 살펴 보는 것이 더 의미가 있습니다. 당신이하고있는 것에 대한 문제는 JVM을 시작하기 전에 어떤 종류의 메모리를 사용할지를 알아야한다는 것입니다. 예를 들어 Xmb보다 크지 않은 파일을 읽는 단일 스레드 응용 프로그램이라는 것을 알고 있다면 -XmxYm을 사용하여 Y = X + {a-bit-more-ram}과 같은 것으로 JVM을 시작하는 것이 좋습니다. (예 :'-Xmx1024m'). – carlspring

관련 문제