#java #file #process #runtime
#java #файл #процесс #время выполнения
Вопрос:
Как я узнаю, закончила ли программа запись файла, если я запускаю это программное обеспечение с Java?Например, я выполняю geniatagger.exe с помощью входного файла RawText, который создаст выходной файл TAGGEDTEXT.txt . Когда geniatagger.exe закончено написание TAGGEDTEXT.txt файл, я могу сделать несколько других запросов с помощью этого файла. Проблема в том, как я могу узнать, что geniatagger закончил запись текстового файла?
try{
Runtime rt = Runtime.getRuntime();
Process p = rt.exec("geniatagger.exe -i " RawText " -o TAGGEDTEXT.txt");
}
Комментарии:
1. Не
.exec()
блокируется до тех пор, пока все, что вы выполняете, не завершится и не завершится?2. Нет метки, он вызывает geniatagger.exe — это нормально, но управление программой сразу переходит к следующему блоку кода (в то время как geniatagger.exe все еще пишет TAGGEDTEXT.txt )
3. Завершается ли программа после завершения записи файла? Можете ли вы проанализировать файл, чтобы определить, когда он будет завершен? Как вы узнаете, когда программа закончит запись файла?
4. Обычно, когда я запускаю geniatagger.exe тогда снаружи от java TAGGEDTEXT.txt сначала создается, а затем в него вставляются проанализированные тексты (размер файла увеличивается… увеличивается… и останавливается) @maerics
Ответ №1:
Вы не можете или, по крайней мере, ненадежно.
В этом конкретном случае лучше всего наблюдать за завершением процесса.
В качестве бонуса вы получаете код возврата процесса, который может сообщить вам, произошла ли ошибка.
Если вы на самом деле говорите об этом теггере GENIA, ниже приведен практический пример, который демонстрирует различные темы (см. Объяснение пронумерованных комментариев под кодом). Код был протестирован с версией v1.0 для Linux и демонстрирует, как безопасно запускать процесс, который ожидает, что как входной, так и выходной поток будут работать правильно.
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.concurrent.Callable;
import org.apache.commons.io.IOUtils;
public class GeniaTagger {
/**
* @param args
*/
public static void main(String[] args) {
tagFile(new File("inputText.txt"), new File("outputText.txt"));
}
public static void tagFile(File input, File output) {
FileInputStream ifs = null;
FileOutputStream ofs = null;
try {
ifs = new FileInputStream(input);
ofs = new FileOutputStream(output);
final FileInputStream ifsRef = ifs;
final FileOutputStream ofsRef = ofs;
// {1}
ProcessBuilder pb = new ProcessBuilder("geniatagger.exe");
final Process pr = pb.start();
// {2}
runInThread(new Callable<Void>() {
public Void call() throws Exception {
IOUtils.copy(ifsRef, pr.getOutputStream());
IOUtils.closeQuietly(pr.getOutputStream()); // {3}
return null;
}
});
runInThread(new Callable<Void>() {
public Void call() throws Exception {
IOUtils.copy(pr.getInputStream(), ofsRef); // {4}
return null;
}
});
runInThread(new Callable<Void>() {
public Void call() throws Exception {
IOUtils.copy(pr.getErrorStream(), System.err);
return null;
}
});
// {5}
pr.waitFor();
// output file is written at this point.
} catch (Exception e) {
e.printStackTrace();
} finally {
// {6}
IOUtils.closeQuietly(ifs);
IOUtils.closeQuietly(ofs);
}
}
public static void runInThread(final Callable<?> c) {
new Thread() {
public void run() {
try {
c.call();
} catch (Exception e) {
e.printStackTrace();
} finally {
}
}
}.start();
}
}
-
Используйте a
ProcessBuilder
для запуска вашего процесса, у него лучший интерфейс, чем у обычного старогоRuntime.getRuntime().exec(...)
. -
Настройте потоковую передачу в разных потоках, иначе
waitFor()
вызов ({5}) может никогда не завершиться. -
Обратите внимание, что я передал a
FileInputStream
процессу. Согласно вышеупомянутой странице GENIA, эта команда ожидает фактического ввода вместо-i
параметра. ТотOutputStream
, который подключается к процессу, должен быть закрыт, иначе программа продолжит работать! -
Скопируйте результат процесса в
FileOutputStream
файл результата, который вы ожидаете. -
Пусть основной поток подождет завершения процесса.
-
Очистите все потоки.
Комментарии:
1. Превосходно! Я думаю, что предыдущее решение работает для многих других исполняемых файлов… но это специально для genia pos tagger. Многому учусь у вас, ребята. Спасибо.
Ответ №2:
Если программа завершает работу после создания выходного файла, вы можете вызвать Process.waitFor()
, чтобы она была запущена до завершения, после чего вы можете обработать файл. Обратите внимание, что вам, вероятно, придется удалить как стандартный вывод, так и потоки ошибок (по крайней мере, в Windows) для завершения процесса.
[Править / править код]
Вот пример, непроверенный и, вероятно, чреватый проблемами:
// ...
Process p = rt.exec("geniatagger.exe -i " RawText " -o TAGGEDTEXT.txt");
drain(p.getInputStream());
drain(p.getErrorStream());
int exitCode = p.waitFor();
// Now you should be able to process the output file.
}
private static void drain(InputStream in) throws IOException {
while (in.read() != -1);
}
Комментарии:
1. Программа завершается, и я попытался использовать Process.waitFor() . Но система остановлена, и выходной файл не создается, и когда я останавливаю программу Java, тогда geniatagger.exe создает выходной файл.
2. Вам нужно удалить stdout и stderr из процесса.
3. @maerics На самом деле, слив потока должен происходить в другом потоке. Ваше решение может работать большую часть времени, но блокируется, когда процесс решает заполнить stderr и закрывает поток stderr перед stdout. Использование некоторого класса Apache Commons, вероятно, позволяет избежать этой проблемы.
4. @JBert: да, совершенно верно, просто хотел проиллюстрировать самую простую вещь, которая может сработать.
5. @maerics, программный элемент управления не перемещается в — // Теперь вы должны иметь возможность обрабатывать выходной файл.