You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中如何将超长字符串写入GZIP文件?解决内存溢出问题

解决超大字符串写入GZIP文件的内存溢出问题

你遇到的OutOfMemoryError是因为直接调用content.getBytes()会把整个超长字符串一次性转换成字节数组,当字符串足够大时,这个数组的尺寸会超过JVM允许的最大数组大小,直接触发内存溢出。

解决的核心思路是分块处理字符串,不要一次性把整个字符串加载到内存里转为字节数组,而是逐段读取、逐段写入GZIP流。

修改后的代码示例

方法1:基于字符流分块写入

对原way1改造,用StringReader逐块读取字符串,再把每一小块转为字节写入GZIP流:

import java.io.BufferedReader;
import java.io.StringReader;
import java.nio.CharBuffer;
import java.nio.charset.StandardCharsets;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.zip.GZIPOutputStream;

public static void way1Fixed() throws IOException {
    String filePath = "foo";
    String content = "very large string";
    int chunkSize = 8192; // 8KB的块大小,可根据内存情况调整
    char[] buffer = new char[chunkSize];

    try (OutputStream os = Files.newOutputStream(Paths.get(filePath));
         GZIPOutputStream gos = new GZIPOutputStream(os);
         BufferedReader reader = new BufferedReader(new StringReader(content))) {

        int charsRead;
        while ((charsRead = reader.read(buffer)) != -1) {
            // 将当前读取到的字符块转为字节数组写入
            byte[] chunkBytes = StandardCharsets.UTF_8.encode(CharBuffer.wrap(buffer, 0, charsRead)).array();
            gos.write(chunkBytes, 0, chunkBytes.length);
        }
        gos.finish(); // 确保GZIP完成所有压缩数据的写入
    }
}

方法2:基于NIO通道的分块编码

对原way2改造,用CharsetEncoder逐块将字符编码为字节,再写入通道:

import java.nio.charset.StandardCharsets;
import java.nio.charset.CharsetEncoder;
import java.nio.CharBuffer;
import java.nio.ByteBuffer;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.zip.GZIPOutputStream;
import java.nio.channels.Channels;
import java.nio.channels.WritableByteChannel;
import java.io.BufferedReader;
import java.io.StringReader;

public static void way2Fixed() throws IOException {
    String filePath = "foo";
    String content = "very large string";
    int chunkSize = 8192;
    char[] charBuffer = new char[chunkSize];
    CharsetEncoder encoder = StandardCharsets.UTF_8.newEncoder();

    try (OutputStream os = Files.newOutputStream(Paths.get(filePath));
         GZIPOutputStream gos = new GZIPOutputStream(os);
         WritableByteChannel channel = Channels.newChannel(gos);
         BufferedReader reader = new BufferedReader(new StringReader(content))) {

        int charsRead;
        while ((charsRead = reader.read(charBuffer)) != -1) {
            CharBuffer cb = CharBuffer.wrap(charBuffer, 0, charsRead);
            ByteBuffer bb = encoder.encode(cb);
            channel.write(bb);
            encoder.reset(); // 重置编码器,准备处理下一块字符
        }
        gos.finish();
    }
}

注意点

  • 块大小(比如8192)可以根据你的JVM内存配置调整,太大可能还是会有内存压力,太小则会增加IO操作次数,找个平衡值即可。
  • 一定要调用GZIPOutputStream.finish(),否则最后一部分压缩数据可能不会写入文件,导致GZIP文件损坏。
  • 保持try-with-resources的用法,确保所有流和通道自动关闭,避免资源泄漏。

内容的提问来源于stack exchange,提问作者Shigure

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 06:05:36