écrire Comment utiliser Java pour lire à partir d'un fichier en cours d'écriture?




lire un fichier en java ligne par ligne (8)

J'ai une application qui écrit des informations dans un fichier. Cette information est utilisée après l'exécution pour déterminer la réussite / l'échec / l'exactitude de l'application. J'aimerais pouvoir lire le fichier tel qu'il est en train d'être écrit afin de pouvoir effectuer ces vérifications de réussite / échec / correction en temps réel.

Je suppose qu'il est possible de faire cela, mais quels sont les problèmes impliqués lors de l'utilisation de Java? Si la lecture rattrape l'écriture, attendra-t-elle simplement plus d'écritures jusqu'à ce que le fichier soit fermé, ou la lecture lancera-t-elle une exception à ce stade? Si ce dernier, qu'est-ce que je fais alors?

Mon intuition me pousse actuellement vers BufferedStreams. Est-ce le chemin à parcourir?


Vous pouvez également jeter un oeil à la chaîne Java pour verrouiller une partie d'un fichier.

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

Cette fonction du FileChannel peut être un début

lock(long position, long size, boolean shared) 

Une invocation de cette méthode bloquera jusqu'à ce que la région puisse être verrouillée


La réponse semble être "non" ... et "oui". Il semble y avoir aucun moyen réel de savoir si un fichier est ouvert pour l'écriture par une autre application. Ainsi, la lecture d'un tel fichier avancera juste jusqu'à ce que le contenu soit épuisé. J'ai suivi le conseil de Mike et j'ai écrit un code de test:

Writer.java écrit une chaîne dans le fichier, puis attend que l'utilisateur appuie sur Entrée avant d'écrire une autre ligne dans le fichier. L'idée étant que cela puisse être démarré, alors un lecteur peut commencer à voir comment il gère le fichier "partiel". Le lecteur que j'ai écrit est dans 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);
    }
}

Aucune garantie que ce code est la meilleure pratique.

Cela laisse l'option suggérée par Mike de vérifier périodiquement s'il y a de nouvelles données à lire dans le fichier. Cela nécessite ensuite une intervention de l'utilisateur pour fermer le lecteur de fichiers lorsqu'il est déterminé que la lecture est terminée. Ou, le lecteur doit être mis au courant du contenu du fichier et être capable de déterminer et de mettre fin à la condition d'écriture. Si le contenu était XML, la fin du document pourrait être utilisée pour signaler cela.


Impossible de faire fonctionner l'exemple avec FileChannel.read(ByteBuffer) car il ne s'agit pas d'une lecture bloquante. A cependant obtenu le code ci-dessous pour travailler:

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

Bien sûr, la même chose fonctionnerait comme une minuterie au lieu d'un fil, mais je laisse cela au programmeur. Je cherche toujours un meilleur moyen, mais cela fonctionne pour moi pour l'instant.

Oh, et je vais mettre en garde avec ceci: J'utilise 1.4.2. Oui, je sais que je suis encore dans l'âge de la pierre.


Je n'ai jamais essayé, mais vous devriez écrire un cas de test pour voir si la lecture d'un flux après que vous avez atteint la fin fonctionnera, indépendamment du fait qu'il y ait plus de données écrites dans le fichier.

Y a-t-il une raison pour laquelle vous ne pouvez pas utiliser un flux d'entrée / sortie canalisé? Est-ce que les données sont écrites et lues à partir de la même application (si oui, vous avez les données, pourquoi avez-vous besoin de lire dans le fichier)?

Sinon, peut-être lire jusqu'à la fin du fichier, puis surveiller les changements et chercher à l'endroit où vous vous êtes arrêté et continuer ... mais attention aux conditions de course.


Je suis totalement d'accord avec la réponse de Joshua , Tailer est apte au travail dans cette situation. Voici un exemple :

Il écrit une ligne toutes les 150 ms dans un fichier, tout en lisant ce même fichier toutes les 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);
        }
    }
}

Il existe une queue graphique Java Open Source qui le fait.

https://.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();
}

Regardez dans l'utilisation du Tailer d'Apache Commons IO. Il gère la plupart des cas de bord.


Si vous voulez lire un fichier pendant qu'il est en cours d'écriture et ne lire que le nouveau contenu, le suivant vous aidera à obtenir le même résultat.

Pour lancer ce programme, lancez-le à partir de l'invite de commande / fenêtre du terminal et transmettez le nom du fichier à lire. Il lira le fichier sauf si vous tuez le programme.

java FileReader c: \ monfichier.txt

Lorsque vous tapez une ligne de texte, enregistrez-la à partir du bloc-notes et vous verrez le texte imprimé dans la 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();
    }
}




file-io