1

我有一个大小为 32 MB 的文件,我已将其从 DocuShare 服务器下载到 DocuShare 临时文件夹。我正在尝试从中读取文件内容以创建文件。对 base64 内容进行 URL 编码时出现错误。当我在一个简单的 java 应用程序中运行相同的代码时,我没有遇到任何异常。但是当我在 DocuShare 服务中使用相同的代码来获取文档内容时,我得到了异常。HTTP 状态 500 - org.glassfish.jersey.server.ContainerException:java.lang.OutOfMemoryError:Java 堆空间

org.glassfish.jersey.server.ContainerException:java.lang.OutOfMemoryError:Java 堆空间

File file = new File(filePath);
FileInputStream fileInputStreamReader = new FileInputStream(file);
byte[] bytes = new byte[(int)file.length()];
fileInputStreamReader.read(bytes);
String encodedBase64 = String encodedBase64 = java.util.Base64.getEncoder().encodeToString(bytes);
String urlEncoded = URLEncoder.encode(encodedBase64);

如何修复此错误?我需要增加我的 tomcat 堆大小吗?

4

3 回答 3

1

有两种方法可以解决此问题。

  1. 您可以增加堆大小,但 IMO 这是一个糟糕的解决方案,因为如果您收到多个并行请求或尝试处理更大的文件,您将遇到同样的问题。

  2. 您可以优化您的算法 - 您可以以流式方式处理它,而不是将文件的多个副本存储在内存中,因此内存中不会超过几个 KB:

    import java.io.InputStream;
    import java.io.OutputStream;
    import java.nio.file.Files;
    import java.nio.file.Path;
    import java.nio.file.Paths;
    import java.util.Base64;
    
    public class Launcher {
        public static void main(String[] args) throws Exception {
            final Path input = Paths.get("example");
            final Path output = Paths.get("output");
    
            try (InputStream in = Files.newInputStream(input); OutputStream out = Base64.getUrlEncoder().wrap(Files.newOutputStream(output))) {
                final byte[] buffer = new byte[1024 * 8];
    
                for (int read = in.read(buffer); read > 0; read = in.read(buffer)) {
                    out.write(buffer, 0, read);
                }
            }
        }
    }
    

PS:如果你真的需要 URL 编码器,你必须创建它的流版本,但我认为 URL 安全的 base64 就足够了

于 2019-03-25T06:02:35.323 回答
1

Base64 将每 3 个字节转换为 4 个字母。这意味着您可以分块读取数据并以与解码整个文件相同的方式对其进行解码。

试试这个:

       File file = new File(filePath);
       FileInputStream fileInputStreamReader = new FileInputStream(file);
       StringBuilder sb = new StringBuilder();
       Base64.Encoder encoder = java.util.Base64.getEncoder();
       int bufferSize = 3 * 1024; //3 mb is the size of a chunk
       byte[] bytes = new byte[bufferSize]; 
       int readSize = 0;

       while ((readSize = fileInputStreamReader.read(bytes)) == bufferSize) {
            sb.append(encoder.encodeToString(bytes));
       }

       if (readSize > 0) {
            bytes = Arrays.copyOf(bytes, readSize);
            sb.append(encoder.encodeToString(bytes) );
       }

       String encodedBase64  = sb.toString();
于 2019-03-25T06:13:01.470 回答
0

如果你有大文件,你总是会遇到 OOM 错误,具体取决于文件的大小。如果您的目标是使用 Apache Commons Base64 Streams 进行 base64 编码。

https://commons.apache.org/proper/commons-codec/apidocs/org/apache/commons/codec/binary/Base64InputStream.html

于 2019-03-25T05:44:37.577 回答