Подтвердить что ты не робот

В Java, что является лучшим/безопасным шаблоном для мониторинга присоединенного файла?

Кто-то другой процесс создает CSV файл, добавляя к нему строку за раз, когда происходят события. Я не контролирую формат файла или другой процесс, но я знаю, что он будет только добавляться.

В программе Java я хотел бы следить за этим файлом, а при добавлении строки читать новую строку и реагировать в соответствии с содержимым. Игнорируйте проблему синтаксического анализа CSV. Каков наилучший способ контролировать файл для изменений и читать строку за раз?

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

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

4b9b3361

Ответ 1

Так как Java 7 был метод newWatchService() на Класс FileSystem.

Однако есть некоторые оговорки:

  • Это только Java 7
  • Это необязательный метод
  • он отслеживает только каталоги, поэтому вам нужно самому обрабатывать файлы и беспокоиться о перемещении файла и т.д.

Перед Java 7 это невозможно со стандартными API.

Я попробовал следующее (опрос с интервалом в 1 секунду), и он работает (просто печатает в процессе обработки):

  private static void monitorFile(File file) throws IOException {
    final int POLL_INTERVAL = 1000;
    FileReader reader = new FileReader(file);
    BufferedReader buffered = new BufferedReader(reader);
    try {
      while(true) {
        String line = buffered.readLine();
        if(line == null) {
          // end of file, start polling
          Thread.sleep(POLL_INTERVAL);
        } else {
          System.out.println(line);
        }
      }
    } catch(InterruptedException ex) {
     ex.printStackTrace();
    }
  }

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

Ответ 2

Вы можете зарегистрироваться, чтобы получать уведомления в файловой системе, если какие-либо изменения происходят с файлом с использованием класса WatchService. Для этого требуется Java7, здесь ссылка для документации http://docs.oracle.com/javase/tutorial/essential/io/notification.html

здесь приведен код фрагмента:

public FileWatcher(Path dir) {
   this.watcher = FileSystems.getDefault().newWatchService();
   WatchKey key = dir.register(watcher, ENTRY_MODIFY);
}

void processEvents() {
    for (;;) {
        // wait for key to be signalled
        WatchKey key;
        try {
            key = watcher.take();
        } catch (InterruptedException x) {
            return;
        }

        for (WatchEvent<?> event : key.pollEvents()) {
            WatchEvent.Kind<?> kind = event.kind();

            if (kind == OVERFLOW) {
                continue;
            }
            // Context for directory entry event is the file name of entry
            WatchEvent<Path> ev = cast(event);
            Path name = ev.context();
            Path child = dir.resolve(name);
            // print out event
            System.out.format("%s: %s file \n", event.kind().name(), child);
        }
        // reset key and remove from set if directory no longer accessible
        boolean valid = key.reset();
    }
}

Ответ 3

Использовать Java 7 WatchService, часть NIO.2

API WatchService предназначен для приложений, которые должны быть уведомлены о событиях смены файлов.

Ответ 4

Это невозможно для стандартных классов библиотеки. Подробнее см. question.

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

Ответ 5

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

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

Я успешно тестировал эти два класса как на Windoze, так и на Linux. Я очень хотел бы знать, есть ли какое-то условие (например, операционная система), на котором они терпят неудачу.

КласС# 1:

import java.io.File;
import java.io.FileWriter;
import java.io.PrintWriter;

public class FileAppender {

    public static void main(String[] args) throws Exception {
        if ((args != null) && (args.length != 0)) throw
            new IllegalArgumentException("args is not null and is not empty");

        File file = new File("./file.txt");
        int numLines = 1000;
        writeLines(file, numLines);
    }

    private static void writeLines(File file, int numLines) throws Exception {
        PrintWriter pw = null;
        try {
            pw = new PrintWriter( new FileWriter(file), true );
            for (int i = 0; i < numLines; i++) {
                System.out.println("writing line number " + i);
                pw.println("line number " + i);
                Thread.sleep(100);
            }
        }
        finally {
            if (pw != null) pw.close();
        }
    }

}

КласС# 2:

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;

public class FileMonitor {

    public static void main(String[] args) throws Exception {
        if ((args != null) && (args.length != 0)) throw
            new IllegalArgumentException("args is not null and is not empty");

        File file = new File("./file.txt");
        readLines(file);
    }

    private static void readLines(File file) throws Exception {
        BufferedReader br = null;
        try {
            br = new BufferedReader( new FileReader(file) );
            while (true) {
                String line = br.readLine();
                if (line == null) { // end of file, start polling
                    System.out.println("no file data available; sleeping..");
                    Thread.sleep(2 * 1000);
                }
                else {
                    System.out.println(line);
                }
            }
        }
        finally {
            if (br != null) br.close();
        }
    }

}

Ответ 6

К сожалению, класс TailInputStream, который может использоваться для мониторинга конца файла, не является стандартным классом Java-платформы Java, но в Интернете мало реализаций. Вы можете найти реализацию класса TailInputStream вместе с примером использования http://www.greentelligent.com/java/tailinputstream.

Ответ 7

Вероятно, это не поможет, просто подумайте громко, но в UNIX можно было бы использовать хвост -f чтобы увидеть любые строки, добавленные в файл - вам нужно что-то подобное, но с точки зрения классов java. tail -f сам реализуется с опросом, я считаю. Он сталкивается с EOF, затем ждет небольшое количество времени (100 мс), затем пытается снова прочитать EOF. Таким образом, он всегда получает последние данные, потому что в то время как другие записи процесса - EOF перемещается вперед.

Ответ 8

Опрос, будь то последовательный цикл или случайный цикл; 200-2000 мс должен быть хорошим интервалом интервала опроса.

Проверьте две вещи...

Если вам нужно следить за ростом файла, проверьте количество EOF/байтов и не забудьте сравнить это, а также время fileAccess или fileWrite с опросом lass. Если ( > ), то файл был записан.

Затем объедините это с проверкой на эксклюзивный доступ к блокировке/чтению. Если файл может быть заблокирован для чтения и он вырос, то все, что было написано, завершено.

Проверка на наличие одного из свойств не обязательно обеспечит вам гарантированное состояние написанного ++ и фактически сделана и доступна для использования.