Cum utilizez Java pentru a citi dintr-un fișier care este scris în mod activ?

Am o aplicație care scrie informații în dosar. Această informație este utilizată după executare pentru a determina trecerea / incapacitatea / corectitudinea aplicației. Aș dori să pot citi fișierul așa cum este scris, astfel încât să pot face aceste verificări de pass / fail / correctness în timp real.

Presupun că este posibil să faci acest lucru, dar care sunt chestiunile implicate în folosirea Java? În cazul în care lectura atinge până la scris, va aștepta doar pentru a scrie mai mult până când fișierul este închis, sau va citi arunca o excepție în acest moment? Dacă acesta din urmă, ce fac atunci?

Intuiția mea mă împinge în prezent spre BufferedStreams. Este aceasta cale de a merge?

0
fr hi bn
@EJP - care DB vă recomandăm? Cred că MySQL este un început bun?
adăugat autor Coffee, sursa
Utilizați o bază de date. Acestea "citesc un fișier în timp ce scenariile sale scrise" se termină cu lacrimi.
adăugat autor EJP, sursa
hei, ca eu sunt confruntat cu un scenariu similar am fost formularea dacă ați găsit o soluție mai bună decât cea acceptată?
adăugat autor Asaf David, sursa
Știu că aceasta este o întrebare veche, dar de dragul viitorilor cititori, puteți să vă extindeți și mai mult cazul de utilizare? Fără a avea mai multe informații, se întreabă dacă poate rezolvați problema greșită.
adăugat autor user359996, sursa

10 răspunsuri

N-am încercat niciodată, dar ar trebui să scrieți un test pentru a vedea dacă citirea dintr-un flux după ce ați lovit sfârșitul va funcționa, indiferent dacă există mai multe date scrise în fișier.

Există un motiv pentru care nu puteți utiliza un flux de intrare / ieșire prin conducte? Datele sunt scrise și citite din aceeași aplicație (dacă da, aveți datele, de ce trebuie să citiți din fișier)?

În caz contrar, poate să citiți până la sfârșitul fișierului, apoi să monitorizați modificările și să căutați unde ați rămas și să continuați ... deși aveți grijă de condițiile de rasă.

0
adăugat

Nu este Java per-se, dar puteți întâmpina probleme în care ați scris ceva într-un fișier, dar nu a fost încă scris - ar putea fi într-un cache undeva și citirea din același fișier nu vă poate da de fapt noile informații.

Versiunea scurtă - folosiți flush() sau orice apel sistem relevant pentru a vă asigura că datele dvs. sunt de fapt scrise în fișier.

Notă Nu vorbesc despre memoria cache a discului la nivel de sistem - dacă datele dvs. intră aici, ar trebui să apară într-o citire() după acest punct. Este posibil ca limbajul propriu-zis să scrie, așteptând până când un tampon se umple sau fișierul este spălat / închis.

0
adăugat

Răspunsul pare a fi "nu" ... și "da". Nu pare să existe o modalitate reală de a ști dacă un fișier este deschis pentru scrierea de către o altă aplicație. Așadar, citirea dintr-un astfel de fișier va progresa până la epuizarea conținutului. Am luat sfatul lui Mike și am scris un cod de testare:

Writer.java scrie un șir de fișiere și apoi așteaptă ca utilizatorul să atingă intrarea înainte de a scrie o altă linie pentru a fișier. Ideea fiind că ar putea fi pornită, cititorul poate începe să vadă cum se comportă cu dosarul "parțial". Cititorul pe care l-am scris este în 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);
    }
}

Nu există garanții că acest cod este cea mai bună practică.

Acest lucru lasă opțiunea sugerată de Mike de a verifica periodic dacă există date noi de citit din fișier. Aceasta necesită apoi intervenția utilizatorului pentru a închide cititorul de fișiere atunci când se constată că citirea este terminată. Sau, cititorul trebuie să fie conștient de conținutul fișierului și să fie capabil să determine și să încheie condiția de scriere. Dacă conținutul era XML, sfârșitul documentului ar putea fi folosit pentru a semnala acest lucru.

0
adăugat

De asemenea, puteți să aruncați o privire la canalul Java pentru a bloca o parte dintr-un fișier.

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

Această funcție a FileChannel ar putea fi un început

lock(long position, long size, boolean shared) 

O invocare a acestei metode se va bloca până când regiunea nu poate fi blocată

0
adăugat

Încercați să utilizați Tailer de la Apache Commons IO. Se ocupă de majoritatea cazurilor de margine.

0
adăugat

Sunt total de acord cu răspunsul lui Joshua , Tailer este potrivit pentru această lucrare. Iată un exemplu:

Se scrie o linie la fiecare 150 ms într-un fișier, în timp ce citiți același fișier la fiecare 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);
        }
    }
}
0
adăugat
Linkul tău către Tailer este întrerupt.
adăugat autor Stealth Rabbi, sursa
@StealthRabbi Cel mai bun lucru pe care trebuie să-l faceți este să căutați linkul corect și să editați răspunsul cu el.
adăugat autor igracia, sursa

Nu puteți citi un fișier care este deschis de la un alt proces folosind FileInputStream, FileReader sau RandomAccessFile.

Dar folosind FileChannel direct va funcționa:

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;
}
0
adăugat

Nu s-a putut obține exemplul să funcționeze utilizând FileChannel.read (ByteBuffer) deoarece nu este o citire blocantă. Cu toate acestea, codul de mai jos a funcționat:

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

Desigur, același lucru ar funcționa ca un cronometru în loc de un fir, dar lăsăm asta până la programator. Încă mai caut o cale mai bună, dar asta lucrează pentru mine deocamdată.

Oh, și voi spune cu asta: Eu folosesc 1.4.2. Da, știu că sunt în vârstă de piatră încă.

0
adăugat
Mulțumesc că ați adăugat acest lucru ... ceva pe care nu l-am făcut niciodată. Cred că răspunsul lui Blade de a bloca dosarul este de asemenea unul bun. Cu toate acestea, este nevoie de Java 6 (cred că).
adăugat autor Anthony Cramp, sursa
@AnthonyCramp de ce nu dai recompensa? :)
adăugat autor Yassin Hajaj, sursa
@JosephGordon - Va trebui să vă deplasați la vârstele Drone într-una din aceste zile ;-)
adăugat autor TungstenX, sursa

Există un Open Source Java Graphic Tail care face acest lucru.

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();
}
0
adăugat

Dacă doriți să citiți un fișier în timp ce acesta este scris și citiți doar conținutul nou, atunci următoarele vă vor ajuta să obțineți același lucru.

Pentru a rula acest program, îl veți lansa din fereastra de comandă / terminal și veți transmite numele fișierului. Va citi fișierul dacă nu ucizi programul.

java FileReader c: \ myfile.txt

Pe măsură ce tastați o linie de text, salvați-o din notepad și veți vedea textul imprimat în consola.

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
0
adăugat
Acest cod consumă o mulțime de CPU, deoarece bucla nu are un thread.sleep apel în el. Fără a adăuga o cantitate mică de întârziere, acest cod tinde să mențină CPU foarte ocupat.
adăugat autor ChaitanyaBhatt, sursa
Nu există posibilitatea ca, între momentul citirii fișierului și timpul de preluare a lungimii fișierului, procesul extern ar putea adăuga mai multe date în fișier. Dacă da, acest lucru ar duce la lipsa datelor din procesul de lectură scrise în fișier.
adăugat autor JohnC, sursa