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

Java8编译遗留代码后BufferedWriter随机写入字符串为空/NULL问题

问题:Java 8下遗留代码写入文件时字符串随机丢失

维护一套基于Java 5/6编写的遗留代码,近期服务器升级到Java 8,重新编译后无编译错误,但运行时出现异常:写入文本+二进制混合格式文件时,字符串会随机变成空白(可视化时显示为空)。流程是读取图像后先写字符串数据,再写图像块。

该代码多年未改动且运行正常,写入前日志显示字符串内容完全正确,每次调用BufferedWriter.write()后都执行了flush(),FileOutputStream也无报错信息。

补充说明

  • outputData生成的字符串始终有效,不会为NULL
  • 最终文件按12455字符的块构建
  • 异常表现:部分块仅存在图像块,缺失对应字符串(例如:STR1+图像块、STR2+图像块、空白+图像块、STR4+图像块)
  • 无法在本地及测试机复现,生产环境随机出现,通常仅影响一行
  • 日志中STR内容始终正确,异常部分在Notepad++中显示为空白,无任何异常抛出

相关代码

ImageInputStream isb = ImageIO.createImageInputStream(file);
Iterator<ImageReader> iterator = ImageIO.getImageReaders(isb);
if (iterator == null || !iterator.hasNext())
{
    throw new IOException("Image file format not supported by ImageIO: ");
}
ImageReader reader = (ImageReader) iterator.next();
reader.setInput(isb);
int nbPages = reader.getNumImages(true);
outputFileStream = new FileOutputStream(getPathExit(), true);
fileWriter = new BufferedWriter(new OutputStreamWriter(outputFileStream));
byte[] block = new byte[GeneratingIssuedFileConstants.BLOCK_SIZE_IMAGE];
String str = null;                  
int total=0;
for(int p=0;p<nbPages;p++)
{
    int orderNumberImg = 1;
    int bytesRead = -1;
    int offset = 0;
    total=0;
    ByteArrayOutputStream byteConte= new ByteArrayOutputStream();
    BufferedImage bufferedImage = reader.read(p);
    ImageIO.write(bufferedImage, "tif", byteConte);
    total=byteConte.size();
    ByteArrayInputStream is = new ByteArrayInputStream(byteConte.toByteArray());
    String outputData = "CONSTANT_INFO_RELATED_TO_IMAGE";
    while ((bytesRead=is.read(block, offset, GeneratingIssuedFileConstants.BLOCK_SIZE_IMAGE))> -1)
    {
        for (int z=bytesRead; z<GeneratingIssuedFileConstants.BLOCK_SIZE_IMAGE; z++)
        {
            block[z] = 0x20;
        }
        str=outputData;
        str +=String.format("%08d" ,total);
        str +=String.format("%03d" ,orderNumberImg);
        log.info("---STR VALUE---: "+str);
        fileWriter.write(str);
        fileWriter.flush();
        outputFileStream.write(block,offset,GeneratingIssuedFileConstants.BLOCK_SIZE_IMAGE);
        outputFileStream.flush();
        orderNumberImg = orderNumberImg+1;
        str="";
    }
}
outputFileStream.close();
fileWriter.close();

问题根源与修复方案

根源分析

  1. 字符编码差异:Java 8对OutputStreamWriter的默认编码处理与Java 5/6存在差异,旧版本依赖系统默认编码,升级后编码不匹配导致字符串转字节时出现异常,最终写入空白。
  2. 流混用冲突:BufferedWriter(字符流)与FileOutputStream(字节流)共用底层输出流,尽管调用了flush(),但Java 8的缓冲机制兼容性问题可能导致字符串字节未真正写入就被二进制写入干扰。
  3. 生产环境隐式并发:生产环境可能存在文件被其他进程/线程访问的情况,代码未做同步控制,导致写入操作被中断或覆盖。

修复方案

  1. 指定明确字符编码:创建OutputStreamWriter时指定与旧环境一致的编码(如UTF-8或系统默认编码):

    // 示例:指定UTF-8编码
    fileWriter = new BufferedWriter(new OutputStreamWriter(outputFileStream, StandardCharsets.UTF_8));
    
  2. 统一使用字节流写入:避免字符流与字节流混用,将字符串转成字节数组后直接用FileOutputStream写入:

    // 替换原fileWriter相关逻辑
    byte[] strBytes = str.getBytes(StandardCharsets.UTF_8); // 匹配旧环境编码
    outputFileStream.write(strBytes);
    outputFileStream.flush();
    
  3. 调整流关闭顺序:先关闭字符流fileWriter,再关闭字节流outputFileStream,确保字符流的缓冲数据全部写入底层流:

    fileWriter.close();
    outputFileStream.close();
    
  4. 添加同步控制:如果生产环境存在并发访问文件的情况,添加全局同步锁:

    // 定义全局静态锁对象
    private static final Object FILE_LOCK = new Object();
    
    // 写入操作包裹同步块
    synchronized (FILE_LOCK) {
        byte[] strBytes = str.getBytes(StandardCharsets.UTF_8);
        outputFileStream.write(strBytes);
        outputFileStream.write(block, offset, GeneratingIssuedFileConstants.BLOCK_SIZE_IMAGE);
        outputFileStream.flush();
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.01 13:27:33