在Java中重置FileInputStream,这样我就可以在测试程序中运行另一个程序的多个实例

时间:2016-10-12 15:51:22

标签: java inputstream fileinputstream system.out system.in

我的问题是我被分配来修改和改进执行LZW压缩的程序。据我所知,我的程序运行正常,但依赖于输入文件和输出文件的System.in和System.out重定向。对于我的测试程序,我运行一个充满文件的文件夹,对于每个文件,在程序上运行4个不同的测试。要模拟命令行输入/输出重定向,在每个文件的循环的第一次迭代中,我执行以下操作:

FileOutputStream fos = new FileOutputStream(compressOut); // compressOut is compressed file
PrintStream ps = new PrintStream(fos);
System.setOut(ps);
FileInputStream fis = new FileInputStream(file); // file is file to be compressed
System.setIn(fis);
fis.mark(0);// mark not supported so this is actually left over from my test code -- wanted to show I tried to do this

第一次运行我正在测试的程序时,它运行良好并返回压缩比并准备将其写入程序输出文件。

然而,在第二次程序调用(并且,如果我要消除所有额外调用,for循环的第二次迭代)时,它崩溃并返回输入流为空。我还没有机会看看输出流是否会做同样的事情,但我试图重置流的方法如下:

在每次调用程序之前,我有以下代码块,我认为这样可以解决问题,但无济于事:

//System.setIn(null); // Tried - didn't work
//System.setOut(null); // Tried - didn't work
fos.close();
ps.close();
fis.close();
fos = new FileOutputStream(compressOut);
ps = new PrintStream(fos);
System.setOut(ps);
fis = new FileInputStream(file);
System.setIn(fis);
//fis.reset(); // Tried - didn't work

我已经尝试了各种不同方式的组合来重置输入流,但每个解决方案仍然会返回相同的结果,这是一条错误消息,指示它从空输入流中读取 - 错误这意味着流位于文件的末尾(或文件中没有任何内容)。

我能得到的唯一其他错误是,当我尝试标记(0)时,我调用reset时不支持mark();和reset();方法

我已经完成阅读,无法找到有关如何使其发挥作用的可靠答案。该程序将StdIn转换为BufferedInputStreamStdOut转换为BufferedOutputStream,因此我需要一种兼容的方法,并提供与StdIn / StdOut重定向类似的性能。< / p>

TL; DR :我需要重置FileInputStream并且不能使用mark()reset(),也不能重新初始化FileInputStream < / p>

更新尝试按照类似帖子的建议将FIS包装到BufferedInputStream,其中支持mark()。但是,mark()reset()方法仅适用于BufferedInputStream(我认为是4096字节)的大小,这几乎排除了标记/重置功能的潜在用途。我的所有文件。它们都大于4kB :(

更新2:我已经决定将完整的代码片段从我开始for循环的地方发布到出现空流错误的地方,万一有人可以看到我能做的事情&#39;吨。这是有问题的代码:

public static void main(String[] args) throws IOException, InterruptedException {
    File programOutputPath = new File("-- the compression file path --");
    File folderPath = new File("-- the relative folder path --");
    File compressOut = new File(folderPath + "compressed.lzw");
    File[] allFiles = folderPath.listFiles(); // get an array of all files
    FileWriter fw = new FileWriter(programOutputPath);
    for(File file : allFiles) {
        FileOutputStream fos = new FileOutputStream(compressOut);
        PrintStream ps = new PrintStream(fos);
        System.setOut(ps);
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
        System.setIn(bis);
        String[] cArgs = new String[2];
        cArgs[0] = "-"; cArgs[1] = "-n";
        String[] dArgs = new String[1];
        dArgs[0] = "+";
        String[] LZWArgs = new String[1];
        LZWArgs[0] = "-";
        System.err.println("File: " + file.toString());
        if(!file.canWrite()) {
            System.err.println("SKIPPED FILE");
        }
        if(file.getName().equalsIgnoreCase(".gitignore") || file.getName().equalsIgnoreCase("compressed.lzw")) continue;
        MyLZW.main(cArgs); // runs fine
        if(decompress) {
            //MyLZW.main(dArgs); // not executing this
        }
        long sizeUnc = file.length();
        long sizeC = compressOut.length();
        double ratio = (double)sizeUnc/(double)sizeC; // compression ratio is correct
        System.err.println("java MyLZW - -r <" + file.getName() + "> " + " compressed.lzw compression ratio:" + ratio ); // works fine
        fw.write("java MyLZW - -n <" + file.getName() + "> " + " compressed.lzw compression ratio:" + ratio + "\n");
        cArgs[1] = "-r";
        bis.close(); // close BufferedInputStream
        bis = new BufferedInputStream(new FileInputStream(file)); // reinitialize BIS
        System.setIn(bis); // setIn to newly initialized BufferedInputStream
        MyLZW.main(cArgs); // crashes here b/c empty input stream

1 个答案:

答案 0 :(得分:1)

听起来问题是程序的内部问题;它可能会在后续调用中保留对System.in原始值的引用。

另一种可能性是程序正在破坏输入文件(用空文件替换它)作为副作用。

重复调用System.setIn()没有问题,并且如您所做的那样创建新的FileInputStream确实会从头开始再次读取该文件。因此,问题在于您尚未发布的代码。

在程序内部,输入被初始化为静态变量,如下所示:

private static BufferedInputStream in = new BufferedInputStream(System.in); 

当加载类时,初始化只发生一次。这是一个糟糕的设计,应该修复。由于System.in只读取一次,因此您对System.setIn()所做的后续更改将被忽略。

如果你无法正确修复它,可以用反射重置该变量,但这个问题可能只是糟糕设计的冰山一角。或者,您可以尝试在自己的类加载器中隔离此程序,并在每次主进程运行程序时创建一个新的类加载器。