我的问题是我被分配来修改和改进执行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
转换为BufferedInputStream
和StdOut
转换为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
答案 0 :(得分:1)
听起来问题是程序的内部问题;它可能会在后续调用中保留对System.in
原始值的引用。
另一种可能性是程序正在破坏输入文件(用空文件替换它)作为副作用。
重复调用System.setIn()
没有问题,并且如您所做的那样创建新的FileInputStream
确实会从头开始再次读取该文件。因此,问题在于您尚未发布的代码。
在程序内部,输入被初始化为静态变量,如下所示:
private static BufferedInputStream in = new BufferedInputStream(System.in);
当加载类时,初始化只发生一次。这是一个糟糕的设计,应该修复。由于System.in
只读取一次,因此您对System.setIn()
所做的后续更改将被忽略。
如果你无法正确修复它,可以用反射重置该变量,但这个问题可能只是糟糕设计的冰山一角。或者,您可以尝试在自己的类加载器中隔离此程序,并在每次主进程运行程序时创建一个新的类加载器。