Como faço para usar o Java para ler de um arquivo que está ativamente sendo gravados?

votos
83

Eu tenho um aplicativo que grava as informações para o arquivo. Esta informação é usada pós-execução para determinar passa / falha / correção da aplicação. Eu gostaria de ser capaz de ler o arquivo como ele está sendo escrito para que eu possa fazer essas verificações passa / falha / correção em tempo real.

Eu suponho que é possível fazer isso, mas quais são as gotcha envolvidos quando usando Java? Se a leitura alcança o escrito, vai apenas esperar por mais escreve-se até que o arquivo é fechado, ou será que a leitura lançar uma exceção neste ponto? Neste último caso, o que eu faço, então?

Minha intuição está me empurrando para BufferedStreams. É este o caminho a percorrer?

Publicado 07/08/2008 em 00:57
fonte usuário
Em outras línguas...                            


10 respostas

votos
34

Não foi possível obter o exemplo de trabalhar usando FileChannel.read(ByteBuffer)porque não é uma leitura de bloqueio. Fez no entanto se o código abaixo ao trabalho:

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

Claro que a mesma coisa iria funcionar como um temporizador em vez de um fio, mas eu deixar isso para o programador. Eu ainda estou procurando uma maneira melhor, mas isso funciona para mim por agora.

Oh, e eu vou Advertência este com: Eu estou usando 1.4.2. Sim eu sei que estou na idade da pedra ainda.

Respondeu 30/09/2008 em 20:32
fonte usuário

votos
16

Olhar em usar o Tailer do Apache Commons IO. Ele lida com a maioria dos casos de ponta.

Respondeu 29/05/2012 em 17:28
fonte usuário

votos
6

Se você quiser ler um arquivo enquanto ele está sendo escrito e só ler o novo conteúdo, então a seguir irá ajudá-lo a conseguir o mesmo.

Para executar este programa você vai lançá-lo a partir do prompt de comando janela / terminal e passar o nome do arquivo a ser lido. Ele irá ler o arquivo a menos que você matar o programa.

java FileReader c: \ myfile.txt

Conforme você digita uma linha de texto salvá-lo do bloco de notas e você vai ver o texto impresso no 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();
    }
}
Respondeu 29/09/2015 em 19:08
fonte usuário

votos
5

Eu concordo totalmente com a resposta de Joshua , Tailer está apto para o trabalho nesta situação. Aqui está um exemplo :

Ele escreve uma linha de cada 150 ms em um arquivo, ao ler este mesmo arquivo a cada 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);
        }
    }
}
Respondeu 25/09/2015 em 13:45
fonte usuário

votos
5

Você também pode dar uma olhada no canal de java para bloquear uma parte de um arquivo.

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

Esta função do FileChannelpode ser um começo

lock(long position, long size, boolean shared) 

Uma chamada de este método será bloqueado até que a região pode ser bloqueado

Respondeu 01/09/2008 em 17:31
fonte usuário

votos
3

A resposta parece ser "não" ... e "sim". Não parece haver nenhuma maneira real de saber se um arquivo é aberto para escrita por outra aplicação. Assim, a leitura de um arquivo tal só vai progredir até que o conteúdo está esgotado. Segui os conselhos de Mike e escreveu um código de teste:

Writer.java escreve uma string para o arquivo e, em seguida, aguarda que o usuário pressione Enter antes de escrever uma outra linha para o arquivo. A idéia é que ele poderia ser iniciado, em seguida, um leitor pode ser iniciado para ver como ele lida com o arquivo "parcial". O leitor que eu escrevi está em 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);
    }
}

Não há garantias de que este código é a melhor prática.

Isso deixa a opção sugerida por Mike de verificar periodicamente se há novos dados para ser lido a partir do arquivo. Isso, então, requer a intervenção do utilizador para fechar o leitor de arquivos quando for determinado que a leitura seja concluída. Ou, o leitor precisa estar ciente do conteúdo do arquivo e ser capaz de determinar e no final da condição de gravação. Se o conteúdo foram XML, o fim do documento poderia ser usado para sinalizar isso.

Respondeu 07/08/2008 em 08:25
fonte usuário

votos
1

Há uma cauda Open Source Java gráfica que faz isso.

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();
}
Respondeu 02/03/2015 em 20:04
fonte usuário

votos
1

Não Java per-se, mas você pode executar em questões em que você escreveu algo em um arquivo, mas não foi realmente escrito ainda - pode ser em um cache em algum lugar, e lendo a partir do mesmo arquivo não pode realmente dar-lhe as novas informações.

Versão curta - uso flush () ou qualquer que seja a chamada de sistema relevante é garantir que os seus dados são realmente escrito para o arquivo.

Nota eu não estou falando sobre o cache de disco de nível OS - se os seus dados entra aqui, ele deve aparecer em uma leitura () após este ponto. Pode ser que a própria linguagem caches escreve, esperando até que um buffer enche ou arquivo é liberado / fechado.

Respondeu 07/08/2008 em 01:31
fonte usuário

votos
0

Você não pode ler um arquivo que está aberto a partir de outro processo usando FileInputStream, FileReader ou RandomAccessFile.

Mas usando FileChannel diretamente irá funcionar:

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;
}
Respondeu 03/01/2016 em 12:09
fonte usuário

votos
0

Eu nunca tentei isso, mas você deve escrever um caso de teste para ver se a leitura de um fluxo depois de ter atingido o final vai funcionar, independentemente de se há mais dados gravados no arquivo.

Existe uma razão que você não pode usar um fluxo de entrada / saída canalizada? É os dados que está sendo escrito e lido da mesma aplicação (se assim for, você tem os dados, por que você precisa ler a partir do arquivo)?

Caso contrário, talvez ler até o fim do arquivo, em seguida, monitorar mudanças e procurar onde você parou e continuar ... embora atente para as condições de corrida.

Respondeu 07/08/2008 em 01:37
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more