Come faccio a utilizzare Java per leggere da un file che è attivamente scritti?

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

  •  08-06-2019
  •  | 
  •  

Domanda

Ho un'applicazione che scrive le informazioni di file.Questa informazione viene utilizzata dopo l'esecuzione, per determinare il superamento/fallimento/correttezza dell'applicazione.Mi piacerebbe essere in grado di leggere il file come è scritto in modo che possa fare queste superamento/fallimento/correttezza controlli in tempo reale.

Suppongo che sia possibile fare questo, ma quali sono i gotcha è coinvolto quando si utilizza Java?Se la lettura catture fino alla scrittura, sarà solo attendere che scrive fino fino a quando il file viene chiuso, o le leggi di lanciare un'eccezione a questo punto?Se quest'ultimo, cosa devo fare allora?

La mia intuizione è attualmente mi spinge verso BufferedStreams.È questa la strada da percorrere?

È stato utile?

Soluzione

Potrebbe non ottenere l'esempio di lavorare utilizzando FileChannel.read(ByteBuffer) perché non si tratta di un blocco di lettura.Ha, tuttavia, ottenere il codice riportato di seguito al lavoro:

boolean running = true;
BufferedInputStream reader = new BufferedInputStream(new FileInputStream( "out.txt" ) );

public void run() {
    while( running ) {
        if( reader.available() > 0 ) {
            System.out.print( (char)reader.read() );
        }
        else {
            try {
                sleep( 500 );
            }
            catch( InterruptedException ex ) {
                running = false;
            }
        }
    }
}

Naturalmente la stessa cosa vorresti lavorare come un timer, invece di un thread, ma lascio che il programmatore.Sto ancora cercando un modo migliore, ma questo funziona per me, per ora.

Oh, e io avvertimento con:Sto usando 1.4.2.Sì, lo so che sono all'età della pietra ancora.

Altri suggerimenti

Se volete leggere un file mentre è in fase di scrittura e di leggere solo il contenuto, quindi di seguito vi aiuterà a raggiungere lo stesso.

Per eseguire questo programma puoi lanciare da prompt dei comandi/finestra di terminale e passare il nome del file da leggere.Si potrà leggere il file a meno che non si uccide il programma.

java FileReader c:\myfile.txt

Come è tipo una riga di testo e salvarlo dal blocco note e vedrete il testo stampato nella console.

public class FileReader {

    public static void main(String args[]) throws Exception {
        if(args.length>0){
            File file = new File(args[0]);
            System.out.println(file.getAbsolutePath());
            if(file.exists() && file.canRead()){
                long fileLength = file.length();
                readFile(file,0L);
                while(true){

                    if(fileLength<file.length()){
                        readFile(file,fileLength);
                        fileLength=file.length();
                    }
                }
            }
        }else{
            System.out.println("no file to read");
        }
    }

    public static void readFile(File file,Long fileLength) throws IOException {
        String line = null;

        BufferedReader in = new BufferedReader(new java.io.FileReader(file));
        in.skip(fileLength);
        while((line = in.readLine()) != null)
        {
            System.out.println(line);
        }
        in.close();
    }
}

Si potrebbe anche dare un'occhiata al java canale per la chiusura di una parte di un file.

http://java.sun.com/javase/6/docs/api/java/nio/channels/FileChannel.html

Questa funzione del FileChannel potrebbe essere un inizio

lock(long position, long size, boolean shared) 

Un'invocazione di questo metodo si blocca fino a quando la regione può essere bloccato

Sono totalmente d'accordo con Giosuè risposta, Tailer è adatto per il lavoro in questa situazione.Ecco un esempio :

Scrive una riga di ogni 150 ms in un file, durante la lettura di questo stesso file ogni 2500 ms

public class TailerTest
{
    public static void main(String[] args)
    {
        File f = new File("/tmp/test.txt");
        MyListener listener = new MyListener();
        Tailer.create(f, listener, 2500);

        try
        {
            FileOutputStream fos = new FileOutputStream(f);
            int i = 0;
            while (i < 200)
            {
                fos.write(("test" + ++i + "\n").getBytes());
                Thread.sleep(150);
            }
            fos.close();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    private static class MyListener extends TailerListenerAdapter
    {
        @Override
        public void handle(String line)
        {
            System.out.println(line);
        }
    }
}

La risposta sembra essere "no" ...e "sì".Sembra che ci sia alcun modo per sapere se un file è aperto in scrittura da un'altra applicazione.Così, la lettura da un file di solo i progressi fino a quando il contenuto è esaurito.Ho preso Mike consulenza e scritto un po ' di codice di test:

Writer.java scrive una stringa in un file e quindi attende che l'utente prema invio prima di scrivere un'altra riga del file.L'idea che potrebbe essere avviato, quindi un lettore può essere avviato per vedere come si affronta con la "parziale" del file.Il lettore che ho scritto è in Reader.java.

Writer.java

public class Writer extends Object
{
    Writer () {

    }

    public static String[] strings = 
        {
            "Hello World", 
            "Goodbye World"
        };

    public static void main(String[] args) 
        throws java.io.IOException {

        java.io.PrintWriter pw =
            new java.io.PrintWriter(new java.io.FileOutputStream("out.txt"), true);

        for(String s : strings) {
            pw.println(s);
            System.in.read();
        }

        pw.close();
    }
}

Reader.java

public class Reader extends Object
{
    Reader () {

    }

    public static void main(String[] args) 
        throws Exception {

        java.io.FileInputStream in = new java.io.FileInputStream("out.txt");

        java.nio.channels.FileChannel fc = in.getChannel();
        java.nio.ByteBuffer bb = java.nio.ByteBuffer.allocate(10);

        while(fc.read(bb) >= 0) {
            bb.flip();
            while(bb.hasRemaining()) {
                System.out.println((char)bb.get());
            }
            bb.clear();
        }

        System.exit(0);
    }
}

Non si garantisce che questo codice è la migliore pratica.

Questo lascia l'opzione suggerita da Mike di verificare periodicamente se c'è una nuova lettura dei dati dal file.Quindi, questo richiede l'intervento dell'utente per chiudere il lettore di file quando si è stabilito che la lettura è completata.O, che il lettore deve essere consapevole del contenuto del file ed essere in grado di determinare e di fine di scrittura condizione.Se il contenuto fosse stato XML, la fine del documento, può essere usato per segnalare questo.

Non Java di per sé, ma si può incorrere in problemi dove hai scritto qualcosa su un file, ma non è stato in realtà scritto ancora - potrebbe essere in una cache da qualche parte, e la lettura del file stesso non può effettivamente dare nuove informazioni.

Versione breve - utilizzare flush() o qualunque sia il sistema in questione è chiamata a garantire che i dati siano effettivamente scritto nel file.

Nota che io non sto parlando di OS livello di cache del disco - se i dati viene in questa sede, che dovrebbe apparire in una read() dopo questo punto.Può essere che la lingua stessa cache scrive, in attesa fino a un buffer si riempie o il file viene scaricato/chiuso.

Ci sono un Java Open Source di Grafica Coda che fa questo.

https://stackoverflow.com/a/559146/1255493

public void run() {
    try {
        while (_running) {
            Thread.sleep(_updateInterval);
            long len = _file.length();
            if (len < _filePointer) {
                // Log must have been jibbled or deleted.
                this.appendMessage("Log file was reset. Restarting logging from start of file.");
                _filePointer = len;
            }
            else if (len > _filePointer) {
                // File must have had something added to it!
                RandomAccessFile raf = new RandomAccessFile(_file, "r");
                raf.seek(_filePointer);
                String line = null;
                while ((line = raf.readLine()) != null) {
                    this.appendLine(line);
                }
                _filePointer = raf.getFilePointer();
                raf.close();
            }
        }
    }
    catch (Exception e) {
        this.appendMessage("Fatal error reading log file, log tailing has stopped.");
    }
    // dispose();
}

Non l'ho mai provato, ma si dovrebbe scrivere un test per vedere se la lettura da un flusso dopo che hai raggiunto la fine funzionerà, anche se non vi sono ulteriori dati scritti nel file.

C'è un motivo, non è possibile utilizzare un sottofondo di input/output stream?Sono i dati che vengono scritti e letti dalla stessa applicazione (se è così, si hanno i dati, perché avete bisogno di leggere il file)?

In caso contrario, forse leggere fino alla fine del file, quindi monitorare le modifiche e cercano di dove l'hai lasciato, e continua...se guardi fuori per le condizioni di gara.

Non è possibile leggere un file che viene aperto da un altro processo che utilizza FileInputStream, FileReader o RandomAccessFile.

Ma utilizzando FileChannel direttamente funzionerà:

private static byte[] readSharedFile(File file) throws IOException {
    byte buffer[] = new byte[(int) file.length()];
    final FileChannel fc = FileChannel.open(file.toPath(), EnumSet.of(StandardOpenOption.READ));
    final ByteBuffer dst = ByteBuffer.wrap(buffer);
    fc.read(dst);
    fc.close();
    return buffer;
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top