écrire - lire un fichier en java ligne par ligne




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

Ce n'est pas Java en soi, mais vous pouvez rencontrer des problèmes dans lesquels vous avez écrit quelque chose dans un fichier, mais ce dernier n'a pas encore été écrit. la nouvelle information.

Version courte - utilisez flush () ou l’appel système correspondant pour vous assurer que vos données sont réellement écrites dans le fichier.

Remarque Je ne parle pas du cache de disque au niveau du système d'exploitation. Si vos données entrent ici, elles devraient apparaître dans un read () après ce point. Il se peut que la langue elle-même mette en cache des écritures en attendant qu'un tampon se remplisse ou que le fichier soit vidé / fermé.

J'ai une application qui écrit des informations dans un fichier. Ces informations sont utilisées après l'exécution pour déterminer le succès / l'échec / la correction de l'application. J'aimerais pouvoir lire le fichier en cours d'écriture afin de pouvoir effectuer ces contrôles de réussite / échec / exactitude en temps réel.

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

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


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

Je suis totalement d'accord avec la réponse de Joshua , Tailer est apte à l'emploi 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);
        }
    }
}

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

Writer.java écrit une chaîne dans un fichier, puis attend que l'utilisateur appuie sur Entrée avant d'écrire une autre ligne dans le fichier. L'idée étant qu'il puisse être démarré, un lecteur peut être démarré pour 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 bien, le lecteur doit être informé du contenu du fichier et pouvoir déterminer une condition de fin d’écriture. Si le contenu était au format XML, la fin du document pourrait être utilisée pour le signaler.


Vous ne pouvez pas lire un fichier ouvert à partir d'un autre processus à l'aide de FileInputStream, FileReader ou RandomAccessFile.

Mais utiliser FileChannel directement fonctionnera:

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





file-io