[java] 현재 기록중인 파일에서 Java를 사용하여 읽으려면 어떻게해야합니까?

파일에 정보를 쓰는 응용 프로그램이 있습니다. 이 정보는 애플리케이션의 합격 / 불합격 / 정확성을 결정하기 위해 실행 후 사용됩니다. 실시간으로 이러한 합격 / 불합격 / 정확성 검사를 수행 할 수 있도록 작성중인 파일을 읽을 수 있기를 바랍니다.

나는 이것을 할 수 있다고 가정하지만 Java를 사용할 때 어떤 문제가 있습니까? 읽기가 쓰기를 따라 잡으면 파일이 닫힐 때까지 더 많은 쓰기를 기다릴까요, 아니면이 시점에서 읽기가 예외를 던질까요? 후자의 경우 어떻게해야합니까?

내 직감은 현재 나를 BufferedStreams로 밀고 있습니다. 이게 갈 길 이니?



답변

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를 사용하고 있습니다. 예, 아직 석기 시대에 있다는 것을 압니다.


답변

작성하는 동안 파일을 읽고 새 내용 만 읽으려면 다음을 수행하면 동일한 결과를 얻을 수 있습니다.

이 프로그램을 실행하려면 명령 프롬프트 / 터미널 창에서 실행하고 읽을 파일 이름을 전달합니다. 프로그램을 종료하지 않으면 파일을 읽습니다.

자바 FileReader c : \ myfile.txt

텍스트 줄을 입력 할 때 메모장에서 저장하면 콘솔에 인쇄 된 텍스트가 표시됩니다.

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


답변

파일의 일부를 잠그기 위해 Java 채널을 살펴볼 수도 있습니다.

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

이 기능은 FileChannel시작이 될 수 있습니다.

lock(long position, long size, boolean shared) 

이 메서드의 호출은 영역을 잠글 수있을 때까지 차단됩니다.


답변

나는 Joshua의 반응에 전적으로 동의합니다 . Tailer 는이 상황에서 일에 적합합니다. 다음은 예입니다.

파일에 150ms마다 한 줄을 쓰고 2500ms마다 동일한 파일을 읽습니다.

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


답변

대답은 “아니오”… 그리고 “예”인 것 같습니다. 다른 응용 프로그램에서 쓰기 위해 파일이 열려 있는지 알 수있는 실제 방법이없는 것 같습니다. 따라서 이러한 파일에서 읽는 것은 내용이 모두 소진 될 때까지 진행됩니다. 나는 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 인 경우 문서의 끝을 사용하여이를 알릴 수 있습니다.


답변

Java는 아니지만 파일에 무언가를 작성했지만 아직 실제로 작성되지 않은 문제가 발생할 수 있습니다. 캐시 어딘가에있을 수 있으며 동일한 파일에서 읽는 것이 실제로 제공되지 않을 수 있습니다. 새로운 정보.

짧은 버전-flush () 또는 관련 시스템 호출을 사용하여 데이터가 실제로 파일에 기록되도록합니다.

참고 저는 OS 레벨 디스크 캐시에 대해 말하는 것이 아닙니다. 데이터가 여기에 들어 오면이 시점 이후에 read ()에 나타나야합니다. 언어 자체가 쓰기를 캐시하고 버퍼가 가득 차거나 파일이 플러시 / 닫힐 때까지 기다릴 수 있습니다.


답변

이를 수행하는 오픈 소스 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();
}