Frage

Ich habe eine Anwendung, die schreibt Informationen in die Datei.Diese Informationen werden verwendet, post-Ausführung zu bestimmen, pass/Fehler/Richtigkeit der Anwendung.Ich möchte in der Lage sein, die Datei zu Lesen, als es geschrieben wird, so dass ich diese pass - /Fehler/Richtigkeit überprüft in Echtzeit.

Ich nehme an, es ist möglich, dies zu tun, aber was sind die gotcha ist beteiligt bei der Verwendung von Java?Wenn die Lesung holt das schreiben, wird es nur warten, für mehr schreibt, bis die Datei geschlossen ist, oder wird das Lesen eine Ausnahme an dieser Stelle?Wenn letzteres, was kann ich dann tun?

Meine intuition ist derzeit schob mich in Richtung BufferedStreams.Ist dies der Weg zu gehen?

War es hilfreich?

Lösung

Konnte nicht erhalten Sie das Beispiel, um die Arbeit mit FileChannel.read(ByteBuffer) denn es ist nicht ein blockieren zu Lesen.Hat allerdings erhalten Sie den code unten, um zu funktionieren:

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

Natürlich die gleiche Sache, die funktionieren würde, wie ein timer, anstatt einen thread, aber das überlasse ich den Programmierer.Ich bin noch auf der Suche nach einem besseren Weg, aber das funktioniert bei mir für jetzt.

Oh, und ich werde VORBEHALT dies mit:Ich bin mit 1.4.2.Ja, ich weiß, ich bin in der Steinzeit immer noch.

Andere Tipps

Wenn Sie möchten, um eine Datei Lesen, während es geschrieben wird und nur die neuen Inhalte dann folgende wird Ihnen helfen, das gleiche zu erreichen.

Um dieses Programm ausführen, öffnen Sie es von der Eingabeaufforderung/terminal-Fenster, und übergeben Sie den Namen der Datei zu Lesen.Es wird die Datei gelesen werden, es sei denn, Sie töten das Programm.

java FileReader c:\myfile.txt

Wie geben Sie eine Zeile text speichern, Editor aus und sehen Sie die gedruckte text in der Konsole.

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

Sie könnten auch einen Blick auf java-Kanal zum sperren einen Teil einer Datei.

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

Diese Funktion des FileChannel vielleicht ein Anfang

lock(long position, long size, boolean shared) 

Ein Aufruf dieser Methode wird blockiert, bis die region ist gesperrt

Ich bin völlig einverstanden mit Joshuas Antwort, Tailer ist fit für den job, in dieser situation.Hier ist ein Beispiel :

Es schreibt eine Zeile pro 150 ms in einer Datei, während Sie Lesen diese Datei, jedes 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);
        }
    }
}

Die Antwort scheint "Nein" ...und "ja".Es scheint keine wirkliche Möglichkeit zu wissen, wenn eine Datei zum schreiben geöffnet wird von einer anderen Anwendung.So, das Lesen aus dieser Datei werden nur die Fortschritte, bis Inhalt erschöpft ist.Ich nahm Mikes Rat und schrieb einige test-code:

Writer.java schreibt einen string-Datei und wartet dann, bis der Benutzer die enter-Taste drücken, bevor Sie schreiben eine weitere Zeile in die Datei.Die Idee, dass es gestartet werden könnte, dann einer reader gestartet werden kann, um zu sehen, wie es kommt mit die "Teil" - Datei.Der Leser, den ich schrieb, ist 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);
    }
}

Keine Garantien, dass dieser code ist die beste Praxis.

Dies lässt die option vorgeschlagen, die von Mike periodisch zu überprüfen, wenn es neue Daten aus der Datei Lesen.Dies erfordert dann eingreifen des Benutzers, um die Datei zu schließen, reader, wenn festgestellt wird, dass das Lesen abgeschlossen ist.Oder der Leser muss bewusst gemacht werden, den Inhalt der Datei und in der Lage sein zu bestimmen und zu Ende schreiben Zustand.Wenn der Inhalt wurden von XML, das Ende des Dokuments verwendet werden könnte, um zu signalisieren dies.

Java nicht per se, aber Sie können Fragen, wo Sie geschrieben haben, etwas in einer Datei, aber es ist noch nicht tatsächlich noch geschrieben - vielleicht ist es in einem cache, irgendwo, und das Lesen aus der gleichen Datei kann nicht wirklich geben Sie die neuen Informationen ein.

Kurze version - verwenden Sie flush() oder was auch immer die relevante system-Aufruf, um sicherzustellen, dass Ihre Daten tatsächlich in die Datei geschrieben.

Hinweis: ich spreche nicht über die OS-level-disk-cache - wenn Sie Ihre Daten kommt in hier, es sollte in einem read() nach diesem Zeitpunkt.Es kann sein, dass die Sprache selbst caches schreibt, zu warten, bis ein Puffer gefüllt oder Datei geleert wird/geschlossen.

Es gibt eine Open-Source-Java-Grafik-Schwanz, der dies tut.

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

Ich habe es nie versucht, aber Sie sollten schreiben Sie einen Testfall, um zu sehen, wenn das Lesen aus einem stream, nachdem Sie getroffen haben, wird das Ende der Arbeit, egal wenn es mehr Daten in die Datei geschrieben.

Gibt es einen Grund, warum Sie nicht verwenden können, eine Pipe-input - /output-stream?Die Daten werden geschrieben und gelesen von der gleichen Anwendung (wenn das so ist, haben Sie die Daten, warum Sie benötigen die Datei zu Lesen)?

Ansonsten vielleicht Lesen Sie bis zum Ende der Datei, dann auf Veränderungen überwachen und versuchen, wo Sie Links off, und weiterhin...aber aufpassen, für race-Bedingungen.

Sie können nicht Lesen einer Datei, die geöffnet ist von einem anderen Prozess mit FileInputStream, FileReader oder RandomAccessFile.

Aber mit FileChannel direkt funktioniert:

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;
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top