2016-10-12 9 views
3

Моя проблема в том, что мне было назначено модифицировать и улучшать программу, которая выполняет сжатие LZW. Моя программа, насколько мне известно, работает нормально, но полагается на перенаправление System.in и System.out для входного файла и выходного файла. Для моей тестовой программы я запускаю папку с файлами и для каждого файла, запускаю 4 разных теста в программе. Для эмуляции ввода командной строки/перенаправление вывода, на первой итерации цикла для каждого файла я делаю следующее:Сброс FileInputStream в Java, поэтому я могу запускать несколько экземпляров другой программы в тестовой программе

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 

я пробовал все виды комбинаций различных способов сброса потока ввода, но каждое решение по-прежнему возвращает тот же результат, сообщение об ошибке, указывающее, что оно считывается из пустого потока ввода - ошибка, которая означает, что поток находится в конце файла (или в файле ничего нет).

Единственная другая ошибка, которую я могу получить, заключается в том, что mark() не поддерживается, когда я вызываю сброс, если я пытаюсь отметить (0); и reset(); методы.

Я сделал чтение и не могу найти твердых ответов относительно того, как заставить это работать. Программа превращает StdIn в BufferedInputStream и StdOut в BufferedOutputStream, поэтому мне нужен способ, который будет совместим и обеспечит производительность, аналогичную перенаправлению StdIn/StdOut.

TL; DR: Мне нужно сбросить мой FileInputStream и не может сделать это с помощью метки() сброс(), ни, если я переинициализировать FileInputStream

Update: попытался обертывание ФИС в BufferedInputStream как предложенный на аналогичной должности, где поддерживается знак(). Однако методы mark() и reset() хороши только для размера BufferedInputStream (который я считаю 4096 байтов), что в значительной степени исключает потенциальную полезность функции отметки/сброса во всех моих файлах. Они все больше 4kB :(

Update 2: я решил опубликовать полный фрагмент кода, с которого я начинаю по-цикл в котором происходит пустая ошибка потока, в случае, если кто может увидеть что-то я . не могу это код в вопросе:.

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

«Моя программа ... полагается на System.in и System.out ...» Измените ее, чтобы полагаться на InputStream и OutputStream. Это будет значительно более гибким, и вы сможете передавать новые потоки каждому вызову. – VGR

+0

@VGR Спасибо за предложение, и если все остальное не получится, я попробую это, но я бы предпочел, чтобы не пришлось изменять зависимости, в которых работает программа, поскольку мне давали зависимости как есть, и сказали, чтобы они не редактировали их. Единственный файл, который я должен коснуться, - это исходный файл, который управляет сжатием. Это стало скорее любопытством выяснить, как заставить мою программу работать таким образом, а не абсолютную необходимость заставить ее работать таким образом. В двух словах, я пытаюсь выяснить, в первую очередь, как динамически изменять StdOut и StdIn, как требуется для будущих работ. Большое спасибо за предложение :) – dddJewelsbbb

+0

Если вы хотите перезапустить FileInputStream, просто создайте новый (или переключитесь на RandomAccessFile). Потоки по дизайну предназначены для чтения только один раз - система маркировки/сброса - это всего лишь костыль для ситуации, когда альтернатив нет или вам просто нужно перемотать несколько байтов. – Robert

ответ

1

Это звучит как проблема внутренней по отношению к программе, может быть сохранение ссылки на исходное значение System.in на последующих вызовах

Другой возможно, что программа сбивает входной файл (заменяя его на пустой файл) в качестве побочного эффекта.

Нет проблем с вызовом System.setIn(), и создание нового FileInputStream, как вы это сделали, действительно будет читать файл с самого начала. Поэтому проблема заключается в коде, который вы еще не опубликовали.


Внутри программы, вход инициализируется как статической переменной, например:

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

что инициализация происходит только один раз, когда загружается класс. Это плохой дизайн, и он должен быть исправлен. Поскольку System.in читается только один раз, последующие изменения, сделанные вами с помощью System.setIn(), игнорируются.

Если вы не можете исправить это правильно, вы можете сбросить эту переменную с отражением, но эта проблема может быть просто верхушкой айсберга плохого дизайна. В качестве альтернативы вы можете попробовать изолировать эту программу в своем собственном загрузчике классов и создать новый загрузчик классов каждый раз, когда ваш основной процесс запускает программу.

+0

Спасибо, я прощуплю это и посмотрю, смогу ли я найти что-нибудь. Есть ли что-нибудь на уме, которое могло бы заставить это сохранить ссылку на исходный System.in? Это то, о чем я подумал, потому что он определенно попадает в конец файла и не обновляется. Я также могу опубликовать свой код, но я полностью понимаю, что это не чья-то работа или обязанность просачиваться через мой код за ошибки. – dddJewelsbbb

+0

стр. будет повышаться, когда я получу еще три репутации, поэтому я могу отбросить upvotes – dddJewelsbbb

+1

@dddJewelsbbb Похоже, что «MyLZW» был разработан для запуска один раз в процессе сам по себе, поэтому он может использовать плохие методы, такие как фиксирующие значения в статических переменных. Опять же, эта проблема находится внутри 'MyLZW', и поскольку вы не разместили этот код, я могу только догадываться. – erickson