Монтирование и распаковка файла в Java

В настоящее время я работаю над веб-приложением, которое включает в себя монтирование диска и извлечение файла tar.gz, все на Java. Поскольку приложение работает в среде Linux, я решил попробовать использовать команды Unix, такие как «mount» и «tar».

Runtime runtime = Runtime.getRuntime();
Process proc;

String mountCommand = "mount -t cifs -o username=...";
String extractCommand = "tar xzf ..."

proc = runtime.exec(mountCommand);
proc.waitFor();

proc = runtime.exec(extractCommand);
proc.waitFor();

Выполнение команды mount и команды извлечения в терминале работает нормально, но происходит сбой при ПЕРВОМ запуске в java. Второй proc.waitFor() возвращает код выхода 2. Однако запуск этого кода после первой неудачной попытки работает нормально. У меня такое ощущение, что проблема в том, что waitFor() не ждет, пока команда монтирования не будет полностью завершена. Я пропустил что-то важное в своем коде?

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


person Matthew    schedule 08.07.2009    source источник


Ответы (5)


Продвигается. Если кому интересно, вот как я извлекаю файл tar.gz в Java. Собран из нескольких онлайн-уроков.

public static void extract(String tgzFile, String outputDirectory)
    throws Exception {

// Create the Tar input stream.
FileInputStream fin = new FileInputStream(tgzFile);
GZIPInputStream gin = new GZIPInputStream(fin);
TarInputStream tin = new TarInputStream(gin);

// Create the destination directory.
File outputDir = new File(outputDirectory);
outputDir.mkdir();

// Extract files.
TarEntry tarEntry = tin.getNextEntry();
while (tarEntry != null) {
    File destPath = new File(outputDirectory + File.separator + tarEntry.getName());

    if (tarEntry.isDirectory()) {
    destPath.mkdirs();
    } else {
    // If the parent directory of a file doesn't exist, create it.
    if (!destPath.getParentFile().exists())
        destPath.getParentFile().mkdirs();

    FileOutputStream fout = new FileOutputStream(destPath);
    tin.copyEntryContents(fout);
    fout.close();
    // Presserve the last modified date of the tar'd files.
    destPath.setLastModified(tarEntry.getModTime().getTime());
    }
    tarEntry = tin.getNextEntry();
}
tin.close();
}
person Matthew    schedule 09.07.2009

Быстрый ответ

Поскольку существует зависимость от внешних команд, упростим ее следующим образом:

#!/bin/bash
mount -t cifs -o username=...
tar xzf ...

Назовите его mount-extract.sh, а затем вызовите с помощью одного вызова Runtime.exec().

Полуинтегрированный ответ

Используйте API-интерфейсы Java.

Вам понадобится Runtime.exec для выполнения команды монтирования.

Перспективы

Поскольку Java является кроссплатформенным инструментом разработки программного обеспечения, рассмотрите возможность абстрагирования команды монтирования в вашем приложении, чтобы она производилась динамически на основе базовой операционной системы.

См.: Как смонтировать диск Windows в Java?

См.: http://java.sun.com/j2se/1.4.2/docs/api/java/lang/System.html#getProperties()

Конечно, Agile-разработка будет настаивать на том, чтобы это не делалось до тех пор, пока в этом нет необходимости. Так что держите это в уме до тех пор (поскольку вы можете никогда не запускать приложение ни на чем, кроме систем на основе Unix).

person Dave Jarvis    schedule 08.07.2009
comment
Очень полезно, большое спасибо. Я только что попробовал первый быстрый метод, но он не удался из-за той же проблемы. Сценарий bash не дождался завершения монтирования перед выполнением команды tar, и программа взорвалась. Я собираюсь сделать вторую попытку извлечения с помощью Java. На самом деле я пытался использовать библиотеку tar ранее, но не мог понять, как сохранить даты последнего изменения в извлеченных файлах, поэтому я сдался. Должен быть простой способ сделать это. Существует также библиотека SMB (jcifs.samba.org), которая кажется довольно многообещающей. - person Matthew; 09.07.2009
comment
Теперь вы знаете то, чего раньше не знали: команда mount завершает работу до того, как завершится. Другое решение — использовать спящий режим и цикл до тех пор, пока файл не будет прочитан (или не пройдет фиксированное количество итераций). - person Dave Jarvis; 09.07.2009

Взгляните на org.apache.tools.tar в кодовой базе Ant. В этом пакете есть класс TarInputStream, который можно использовать для чтения архивов tar.

person Brandon E Taylor    schedule 08.07.2009
comment
Да, это похоже на путь, я просто не мог понять, как сохранить даты последнего изменения в извлеченных файлах при использовании этого. - person Matthew; 09.07.2009

Это может быть связано с тем, как вы вызываете метод.

См. этот ответ

В основном попробуйте использовать

.exec( String [] command );

вместо

.exec( String command );

Я не уверен, что это вообще связано, потому что вы упомянули, что это работает во второй раз. Попробуйте и дайте нам знать.

person OscarRyz    schedule 08.07.2009
comment
Спасибо за вклад, но, похоже, это не работает. Из того, что я читал, это просто вызывает один exec за другим, не дожидаясь завершения каждого процесса. - person Matthew; 09.07.2009
comment
:( Слишком грустно. Ну, на самом деле нет, что он на самом деле делает, так это точно разделяет аргументы. Таким образом, опция опции параметра команды преобразуется в 4 части ( команда, параметр, опция, опция ) и все. Иногда передаются аргументы как-то не так заказ, и он отправляет параметр опции параметра команды, используя две строки вместо 4. - person OscarRyz; 09.07.2009

Все это можно сделать в Java, но вы должны знать о предостережениях при работе с собственными процессами.

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

Один из способов обойти это — запустить какой-нибудь тест, чтобы убедиться, что собственные процессы, которые вы начали, завершились к вашему удовлетворению — в этом случае, возможно, проверьте, существует ли какой-либо файл java.io.File.

person Glenn    schedule 08.07.2009
comment
А, это имеет смысл. Использование этого трюка с файлом сработало бы, но это кажется таким хакерским... Думаю, я еще немного изучу библиотеки Java, прежде чем прибегнуть к этому. - person Matthew; 09.07.2009