Как обрабатывать неполные файлы? Получение исключения - PullRequest
8 голосов
/ 04 февраля 2009

Мне нужно создать Java-программу, которая создаст поток для поиска файла в определенной папке (исходной папке) и сразу же выберет файл для работы процесса (преобразовать его в формат файла CSV), как только он найдет файл в источнике папка. Проблема, с которой я сейчас сталкиваюсь - это файл, который приходит в исходную папку большого размера (для копирования файла с сервера в исходную папку используется инструмент FTP), поток выбирает этот файл непосредственно перед тем, как полностью скопировать в исходную папку, и выдает исключение. Как остановить поток, пока файл полностью не скопируется в исходную папку? Он должен выбрать файл для обработки только после того, как файл полностью скопирован в исходную папку.

Ответы [ 7 ]

4 голосов
/ 04 февраля 2009

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

Это решение отлично работает для меня, так как у меня точно такой же сценарий, с которым вы сталкиваетесь.

4 голосов
/ 04 февраля 2009

Самый безопасный способ - загрузить файл в другое место и затем переместить его в целевую папку.

Другим вариантом, упомянутым Bombe, является изменение имени файла на другое расширение после загрузки и поиск только файлов с этим расширением.

3 голосов
/ 04 февраля 2009

Вы можете попробовать разные вещи:

  • Повторно проверяйте дату последнего изменения и размер файла, пока он не изменится в течение заданного периода времени, затем обработайте его. (Как указано в qbeuek, это не безопасно и не детерминированный.)
  • Обрабатывать только файлы с именами, которые соответствуют определенным критериям (например, * .dat). Измените процесс загрузки / выгрузки по FTP, чтобы загружать / скачивать файлы с другим именем (например, * .dat.temp) и переименовывать файлы после их завершения.
  • Загрузите файлы в другое место и переместите их в каталог обработки после их завершения.
  • Как сказал Уксус, если это не сработает в первый раз, попробуйте еще раз позже. :)
2 голосов
/ 04 февраля 2009

Если у вас есть некоторый контроль над процессом, который выполняет FTP, вы могли бы потенциально создать «файл флага» в исходной директории сразу после того, как ftp для большого файла закончен.

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

Флаг файла может быть любым (даже пустым файлом).

1 голос
/ 04 февраля 2009

Если у вас нет контроля над процессом FTP ...

Пусть будет так. Когда вы получите исключение, попробуйте обработать его снова в следующий раз. Повторяйте это, пока файл не будет обработан. Хорошо в случае исключения сохранить несколько атрибутов, чтобы проверить это позже, например; имя, последнее изменение, размер.

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

0 голосов
/ 08 октября 2012

Это в Grails, и я использую библиотеку FileUtils из общей известности Apache. Функция sizeof возвращает размер в байтах.

    def fileModified = sourceFile.lastModified()
    def fileSize = FileUtils.sizeOf(sourceFile)

    Thread.sleep(3000) //sleep to calculate size difference if the file is currently getting copied

    if((fileSize != FileUtils.sizeOf(sourceFile)) && (fileModified != sourceFile.lastModified())) //the file is still getting copied to return 
    {
        if(log.infoEnabled)
            log.info("File is getting copied!")
        return
    } 

    Thread.sleep(1000) //breather for picking up file just copied. 

Обратите внимание, что это также зависит от того, какую утилиту или ОС вы используете для передачи файлов. Самая безопасная ставка - скопировать файл, который был скопирован или был скопирован в другой файл или каталог. Процесс копирования является надежным, и он гарантирует вам, что файл присутствует после процесса копирования. Тот, который я использую, из API общих ресурсов.

FileUtils.copyFileToDirectory (файл f, каталог D)

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

0 голосов
/ 04 февраля 2009

Если ваша ОС Linux и ваше ядро> 2.6.13, вы можете использовать API уведомления о событиях файловой системы с именем inotify . Здесь есть реализация Java: https://bitbucket.org/nbargnesi/inotify-java.

Вот пример кода (по мотивам веб-сайта).

        try {
        Inotify i = new Inotify();
        InotifyEventListener e = new InotifyEventListener() {

            @Override
            public void filesystemEventOccurred(InotifyEvent e) {
                System.out.println("inotify event occurred!");
            }

            @Override
            public void queueFull(EventQueueFull e) {
                System.out.println("inotify event queue: " + e.getSource() +
                        " is full!");
            }

        };
        i.addInotifyEventListener(e);
        i.addWatch(System.getProperty("user.home"), Constants.IN_CLOSE_WRITE);
    } catch (UnsatisfiedLinkError e) {
        System.err.println("unsatisfied link error");
    } catch (UserLimitException e) {
        System.err.println("user limit exception");
    } catch (SystemLimitException e) {
        System.err.println("system limit exception");
    } catch (InsufficientKernelMemoryException e) {
        System.err.println("insufficient kernel memory exception");
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...