StringBuilders以mass nul字符结尾

时间:2011-03-22 16:14:27

标签: java text file null printwriter

我很难用我正在构建的应用程序调试问题。问题本身我似乎无法用具有相同问题的代表性测试程序重现,这使得难以演示。不幸的是,由于安全性,我无法分享我的实际来源,但是,以下测试代表了我正在做的事情,文件和数据是unix样式EOL,使用PrintWriter写入zip文件以及使用StringBuilders这一事实:

public class Tester {

    public static void main(String[] args) {
        // variables
        File target = new File("TESTSAVE.zip");
        PrintWriter printout1;
        ZipOutputStream zipStream;
        ZipEntry ent1;
        StringBuilder testtext1 = new StringBuilder();
        StringBuilder replacetext = new StringBuilder();
        // ensure file replace
        if (target.exists()) {
            target.delete();
        }
        try {
            // open the streams
            zipStream = new ZipOutputStream(new FileOutputStream(target, true));
            printout1 = new PrintWriter(zipStream);
            ent1 = new ZipEntry("testfile.txt");
            zipStream.putNextEntry(ent1);

            // construct the data
            for (int i = 0; i < 30; i++) {
            testtext1.append("Testing 1 2 3 Many! \n");
            }
            replacetext.append("Testing 4 5 6 LOTS! \n");
            replacetext.append("Testing 4 5 6 LOTS! \n");

            // the replace operation
            testtext1.replace(21, 42, replacetext.toString());

            // write it
            printout1 = new PrintWriter(zipStream);
            printout1.println(testtext1);
            // save it
            printout1.flush();
            zipStream.closeEntry();
            printout1.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

问题的核心是我在我身边看到的文件正在生成一个16.3k字符的文件。我的朋友,无论他是否在他的电脑上使用该应用程序,或者他是否看到与我完全相同的文件,我看到一个19.999k字符的文件,额外的字符是CRLF,后跟大量的空字符。无论我使用什么应用程序,编码或视图,我都看不到这些空字符,我只看到最后一行的单个LF,但我确实看到了20k的文件。在所有情况下,两台机器上的完全相同的文件之间存在差异,即使它们都是Windows机器,并且两者都使用相同的编辑软件来查看。

我还没有能够用任何数量的虚拟程序重现这种行为。然而,我已经能够追踪最后一行的迷路CRLF,以便在PrintWriter上使用println。当我用println(s)替换print(s + '\n')时问题似乎消失了(文件大小为16.3k)。但是,当我将程序返回到println(s)时,问题似乎没有返回。我目前正在法国的一位朋友验证这些文件,看看这个问题是否确实消失了(因为我看不到这些问题,但他可以),但这种行为已经彻底混淆了。

我还注意到StringBuilder的替换函数声明“如果需要,将延长此序列以容纳指定的字符串”。鉴于stringbuilders setLength函数pad具有nul字符,并且ensureCapacity函数将容量设置为输入或(currentCapacity*2)+2中的较大者,我怀疑某处有关系。但是,我只有一次用这个想法进行测试时能够得到一个代表我所见过的结果,并且从那时起就无法再现它。

有没有人知道可能导致此错误的原因或者至少有一个关于测试方向的建议?

编辑,因为评论部分对我来说是破碎的: 只是为了澄清,无论操作系统如何,输出都必须采用unix格式,因此直接使用'\ n'而不是格式化程序。插入的原始StringBuilder实际上并不是为我生成的,而是由程序读入的文件的内容。我很高兴阅读过程有效,因为其中的信息在整个应用程序中被大量使用。我做了一点探测,发现在保存之前,缓冲区是正确的容量,并且调用toString()时的输出是正确的长度(即它不包含空字符,长度为16,363,而不是19,999 )。这会将错误的原因放在生成字符串和保存zip文件之间。

1 个答案:

答案 0 :(得分:2)

终于找到了原因。管理几次重现问题并追溯原因而不是代码的输出端而是输入端。我的文件阅读功能基本上是这样的:

char[] buf;
int charcount = 0;
StringBuilder line = new StringBuilder(2048);
InputStreamReader reader = new InputStreamReader(stream);// provides a line-wise read
BufferedReader file = new BufferedReader(reader);
do { // capture loop
    try {
    buf = new char[2048];
    charcount = file.read(buf, 0, 2048);
    } catch (IOException e) {
    return null; // unknown IO error
    }
    line.append(buf);
} while (charcount != -1);
// close and output

问题是附加了一个未满的缓冲区,因此后面的值仍处于初始值null。原因我无法重现它是因为一些数据很好地填充在缓冲区中,有些则没有。

为什么我似乎无法在我的文本编辑器上查看问题,我仍然不知道,但我现在应该能够解决这个问题。有关最佳方法的任何建议都是受欢迎的,因为这是我的一个长期实用程序库的一部分,我希望将其保持为通用和优化。

相关问题