In Java, qual è il miglior / modello più sicuro per il monitoraggio di un file che viene aggiunto al?

StackOverflow https://stackoverflow.com/questions/1073274

  •  21-08-2019
  •  | 
  •  

Domanda

processo che non ti sta creando un file CSV aggiungendo una riga alla volta per esso, come si verificano gli eventi. Non ho alcun controllo sul formato di file o l'altro processo, ma so che sarà solo aggiungere.

In un programma Java, vorrei monitorare questo file, e quando una linea viene aggiunto leggere la nuova linea e reagire in base al contenuto. Ignorare il problema parsing CSV per ora. Qual è il modo migliore per monitorare il file per le modifiche e leggere una riga alla volta?

Idealmente questo userà le classi della libreria standard. Il file potrebbe essere in un'unità di rete, quindi mi piacerebbe qualcosa di robusto al fallimento. Preferirei non usare polling, se possibile, -. Preferirei una sorta di soluzione bloccante invece

Modifica - dato che una soluzione di blocco non è possibile con le classi standard (grazie per la risposta), qual è la soluzione più robusta sondaggi? Io preferirei non riletto l'intero file ogni volta come si possa crescere abbastanza grande.

È stato utile?

Soluzione

Dato che Java 7 c'è stata la newWatchService () metodo sul classe FileSystem .

Tuttavia, ci sono alcune avvertenze:

  • E 'solo Java 7
  • Si tratta di un metodo facoltativo
  • è orologi solo directory, in modo da avere a che fare il lavoro di gestione di file, e la preoccupazione circa il file in movimento etc

Prima di Java 7 non è possibile con le API standard.

Ho provato quanto segue (polling su un intervallo di 1 sec) e funziona (solo stampa in lavorazione):

  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();
    }
  }

Come nessun altro ha suggerito una soluzione che utilizza una produzione attuale di Java ho pensato di aggiungerlo. Se ci sono difetti si prega di aggiungere nei commenti.

Altri suggerimenti

È possibile registrarsi per ricevere la notifica da parte del file system eventuale cambiamento avviene per il file utilizzando la classe WatchService. Ciò richiede Java7, qui il link per la documentazione http://docs.oracle .com / JavaSE / tutorial / essenziali / IO / notification.html

qui il frammento di codice per farlo:

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();
    }
}

L'uso di Java 7 di WatchService , parte di NIO.2

  

L'API WatchService è progettato per le applicazioni che necessitano di notifica di eventi di modifica del file.

Questo non è possibile con le classi della libreria standard. Vedere questo domanda per i dettagli.

Per il polling efficiente sarà meglio utilizzare Random Access . Esso aiuterà se si ricorda la posizione dell'ultimo fine del file e iniziare a leggere da lì.

Solo per espandere ultima voce di Nick Fortescue, qui di seguito sono due classi che è possibile eseguire contemporaneamente (ad esempio, in due diverse finestre di shell), che dimostra che un dato file può contemporaneamente essere scritto da un processo e leggere da un altro.

Qui, i due processi saranno in esecuzione queste classi Java, ma presumo che il processo di scrittura potrebbe essere da qualsiasi altra applicazione. (Supponendo che non tiene un blocco esclusivo sul file-ci sono tali blocchi del file system su alcuni sistemi operativi?)

Ho testato con successo queste due classi su entrambi Windoze e Linux. Mi piacerebbe molto sapere se c'è qualche condizione (ad esempio sistema operativo) su cui vengono a mancare.

Class # 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();
        }
    }

}

Class # 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();
        }
    }

}

Purtroppo, classe TailInputStream, che può essere utilizzato per monitorare la fine di un file, non è una delle classi Java Platform standard, ma ci sono poche implementazioni sul web. È possibile trovare un'implementazione di TailInputStream classe insieme ad un esempio di utilizzo su http://www.greentelligent.com/java / tailinputstream .

Poll, sia su un ciclo coerente o su un ciclo random; 200-2000ms dovrebbe essere un buon sondaggio casuale arco intervallo.

Controlla due cose ...

Se si deve guardare per la crescita di file, quindi controllare il numero di EOF / di byte, ed essere sicuri di confrontare i tempi che e FileAccess o FileWrite con il sondaggio lass. Se (>), allora il file è stato scritto.

Quindi, che si combinano con il controllo per blocco esclusivo / accesso in lettura. Se il file può essere letto bloccata ed è cresciuta, quindi tutto ciò che era iscritto ad esso ha finito.

Verifica di una delle proprietà da solo non necessariamente porterà uno stato garantito di scritto ++ e effettivamente fatto e disponibile per l'uso.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top