【问题标题】:How to manage streams of bytes and when to close the streams如何管理字节流以及何时关闭流
【发布时间】:2013-02-13 12:22:50
【问题描述】:

每当我尝试执行我的代码时,我都会遇到 java.lang.OutOfMemoryError: Java heap space。但是,如果我在某些情况下关闭流,错误就会消失,但由于我的流过早关闭,我会丢失数据。

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

【问题讨论】:

  • 合并后的文件有多大?
  • 不超过 5 - 10 Mb。
  • 哦..合并。我不知道。我正在对一个目录运行我的程序,读入每个文件的字节,对这些字节做一些事情,然后将文件名和一个对这些字节做一些事情的对象存储到一个映射中。
  • 阅读完毕后,您应该关闭所有流。请注意,当您读取目录中的文件时,流并未关闭。
  • 您应该在操作后关闭handleFile函数中的Inputstream fis

标签: java file-io inputstream out-of-memory


【解决方案1】:

首先,不要读取内存中的整个流。读写时使用缓冲区。

仅当您确定要读取非常小的流(您需要将其数据重新用于某些操作)并且将数据保存在内存中确实有意义时,才使用 ByteArrayInputStreamByteArrayInputStream .否则,您将很快(或意外)耗尽内存。

在 try-catch 块之外定义流并在 finally 块中关闭它们(如果它们不为空)。例如:

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(...) 方法到底应该做什么?

【讨论】:

  • carlspring,感谢您提供的信息量很大的帖子!我肯定会对这些字节做一些事情,因为它们将用于实例化一个对这些字节进行计算的类。然后将该类的对象保存到地图中。
  • 哦,handleFile 方法也将接受一个流,因为在另一个方法(我没有输入)中,我递归地检查存档文件并将它们的流传递给 handleFile 方法。
  • 好吧,您显示的代码看起来不错。据我了解,您打算进行解压缩。查看ByteBuffer 中的ByteBuffer 和内存映射类可能更有意义@ 987654326@。您正在做的问题是您需要在启动 JVM 之前知道您希望使用哪种内存。例如,如果您知道这将是一个读取不大于 X mb 文件的单线程应用程序,那么使用 -XmxYm 以 Y=X+{a-bit-more-ram} 之类的方式启动 JVM 是有意义的(例如:-Xmx1024m)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-28
  • 1970-01-01
  • 2022-09-29
  • 1970-01-01
  • 2022-01-14
  • 2014-04-07
相关资源
最近更新 更多