106

ファイルに情報を書き込むアプリケーションがあります。この情報は、アプリケーションの成功/失敗/正確性を判断するために実行後に使用されます。これらの成功/失敗/正確性のチェックをリアルタイムで実行できるように、ファイルが書き込まれているときにファイルを読み取れるようにしたいと考えています。

これは可能だと思いますが、Java を使用する際の落とし穴は何ですか? 読み取りが書き込みに追いついた場合、ファイルが閉じられるまでさらに書き込みを待つだけですか、それともこの時点で読み取りが例外をスローしますか? 後者の場合、私は何をしますか?

私の直感は現在、私を BufferedStreams に向かわせています。これは行く方法ですか?

4

9 に答える 9

45

FileChannel.read(ByteBuffer)ブロッキング読み取りではないため、この例を使用して動作させることができませんでした。ただし、以下のコードが機能するようになりました。

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

もちろん、同じことがスレッドの代わりにタイマーとして機能しますが、それはプログラマーに任せます。私はまだより良い方法を探していますが、これは今のところ私にとってはうまくいきます。

ああ、私はこれを警告します: 私は 1.4.2 を使用しています。はい、私はまだ石器時代にいることを知っています。

于 2008-09-30T19:32:24.637 に答える
7

ファイルの一部をロックするためのJavaチャネルもご覧ください。

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

のこの機能がFileChannel始まりかもしれません

lock(long position, long size, boolean shared) 

このメソッドの呼び出しは、領域がロックされるまでブロックされます

于 2008-09-01T16:31:53.870 に答える
7

Joshua の回答に完全に同意します。Tailerはこの状況での仕事に適しています。例を次に示します。

ファイルに150ミリ秒ごとに1行書き込み、2500ミリ秒ごとにこの同じファイルを読み取ります

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);
        }
    }
}
于 2015-09-25T13:45:22.043 に答える
3

答えは「いいえ」…そして「はい」のようです。ファイルが別のアプリケーションによって書き込み用に開かれているかどうかを知る実際の方法はないようです。したがって、そのようなファイルからの読み取りは、コンテンツが使い果たされるまで進行します。私は Mike のアドバイスを受けて、いくつかのテスト コードを書きました。

Writer.java は文字列をファイルに書き込み、ユーザーが Enter キーを押すのを待ってから、別の行をファイルに書き込みます。起動できるという考えは、リーダーが起動して、「部分的な」ファイルにどのように対処するかを確認できるようにすることです。私が書いたリーダーは 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);
    }
}

このコードがベスト プラクティスであることを保証するものではありません。

これにより、ファイルから読み取る新しいデータがあるかどうかを定期的に確認するという、Mike が提案したオプションが残ります。これにより、読み取りが完了したと判断されたときに、ファイル リーダーを閉じるためにユーザーの介入が必要になります。または、リーダーにファイルの内容を認識させ、書き込み条件の終了を判断できるようにする必要があります。コンテンツが XML の場合、ドキュメントの末尾を使用してこれを通知できます。

于 2008-08-07T07:25:02.580 に答える
2

FileInputStream、FileReader、または RandomAccessFile を使用して別のプロセスから開かれたファイルを読み取ることはできません。

ただし、FileChannel を直接使用すると機能します。

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;
}
于 2016-01-03T12:09:17.433 に答える
2

これを行う Open Source Java Graphic Tail があります。

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();
}
于 2015-03-02T20:04:34.257 に答える
1

Java自体ではありませんが、ファイルに何かを書き込んだが、実際にはまだ書き込まれていないという問題に遭遇する可能性があります-どこかのキャッシュにある可能性があり、同じファイルから読み取っても実際には得られない場合があります新しい情報。

短いバージョン - flush() または関連するシステム コールを使用して、データが実際にファイルに書き込まれるようにします。

OS レベルのディスク キャッシュについて話しているのではないことに注意してください。データがここに入った場合、この時点の後に read() に表示されるはずです。言語自体が書き込みをキャッシュし、バッファがいっぱいになるか、ファイルがフラッシュ/クローズされるまで待機している可能性があります。

于 2008-08-07T00:31:47.203 に答える
0

試したことはありませんが、ファイルにさらにデータが書き込まれるかどうかに関係なく、ストリームの終わりに到達した後にストリームからの読み取りが機能するかどうかを確認するテスト ケースを作成する必要があります。

パイプされた入出力ストリームを使用できない理由はありますか? データは同じアプリケーションから読み書きされていますか (そうであれば、データはあるのに、なぜファイルから読み取る必要があるのでしょうか)。

それ以外の場合は、ファイルの最後まで読み取ってから、変更を監視し、中断した場所を探して続行します... ただし、競合状態に注意してください。

于 2008-08-07T00:37:44.880 に答える