Ler arquivo de trás para frente

Buenas,
Tô utilizando BufferedReader para ler o conteúdo de um arquivo, porém pelo que sempre usei ele só lê sequencialmente, e nãoe xiste nenhum método com informações sobre o arquivo(qtde linhas, carateres, etc).
E eu tô precisando ler por exemplo os 50 últimos registros de um arquivo, alguém tem uma idéia de como fazer isso, tô quebrando a cabeça aqui e num vejo como.

Uma forma boboca é ler o arquivo do início para o fim mesmo, mas deixando as linhas em um LinkedList cujo comprimento você limita a 50 linhas.
Como é que você faz isso? Algo como:

String linha;
List linhas = new LinkedList();
BufferedReader br = ...;
int nMaxLinhas = 50;
while ((linha  = br.readLine()) != null) {
    linhas.add (linha);
    if (linhas.size() > nMaxLinhas) {
        linhas.remove (0); 
    }
}
br.close(); 
// No final você terá um LinkedList com no máximo as últimas 50 linhas.

Hun, xeu testar essa solução.
A zica é que é pra gerar aquele arquivo da Receita Federal - IN86-, e a ordem anual de um arquivo desse é de alguns milhões de linha. De qualquer forma, grato pela sugestão.

Ixe. Se a quantidade de bytes do que você quer ler for fixa, você pode usar o File.length para ver o tamanho do arquivo e indicar quantos bytes você quer ler usando http://java.sun.com/j2se/1.5.0/docs/api/java/io/FileInputStream.html#read(byte[],%20int,%20int) <-- Copie a URL

Se não houver problema em ler todo o arquivo, você pode usar Commons IO, que tem CountingInputStream e FileUtils.readLines().

Num é fixo não, é retorno de um SELECT que monta o arquivo.

Thingol, creio que me perdi ali no seu algoritmo, depois da posição máxima ele não vai retirar e inserir sempre na primeira posição?

Já que o arquivo tem alguns milhões de linhas, você pode usar o método usado pelo “tail”. O “tail” (utilitário do Unix) pega o arquivo e o lê usando o análogo ao RandomAccessFile (o programa é em C), pegando os últimos KBytes e procurando os caracteres usados para quebra de linha, para formar as linhas.

Você pode usar o próprio “tail”, se estiver no Unix. É mais rápido que escrever o seu.

[quote=Rafael Nunes]Num é fixo não, é retorno de um SELECT que monta o arquivo.

Thingol, creio que me perdi ali no seu algoritmo, depois da posição máxima ele não vai retirar e inserir sempre na primeira posição?[/quote]

add sempre insere na última, e remove(0) sempre deleta da primeira. Essa é a idéia.

Não rola de fazer um COUNT e um LIMIT nessa query?

Como isso vai ser um job que vai rodar de madrugada, vou deixar a sua primeira solução mesmo, só rezar pra num dar OutOfMemory no servidor de madrugada…hehe
Bregadão.

Quanto ao Count/Limit, se tiver algum problema com essa sugestão do thingol, vou acabar lendo essas linhas direto do select mesmo.

Um problema na minha solução é que size(), para LinkedList, envolve percorrer a lista inteira. Se eu usasse um ArrayList a parte de inserção e remoção de elementos é mais lenta, mas em compensação o cálculo de tamanho é mais rápido. Não sei se faz alguma diferença.

inverte a ordem com um ORDER BY … DESC

[quote=thingol]Um problema na minha solução é que size(), para LinkedList, envolve percorrer a lista inteira. Se eu usasse um ArrayList a parte de inserção e remoção de elementos é mais lenta, mas em compensação o cálculo de tamanho é mais rápido. Não sei se faz alguma diferença.
[/quote]

Mas como a lista sempre vai ser pequena(30/50) elementos, num vejo muita perda de performance nisso.

[quote=Rafael Nunes][quote=thingol]Um problema na minha solução é que size(), para LinkedList, envolve percorrer a lista inteira. Se eu usasse um ArrayList a parte de inserção e remoção de elementos é mais lenta, mas em compensação o cálculo de tamanho é mais rápido. Não sei se faz alguma diferença.
[/quote]

Mas como a lista sempre vai ser pequena(30/50) elementos, num vejo muita perda de performance nisso.[/quote]

Você mesmo disse que seu arquivo tem zilhões de linhas. Depois que ele ler a 50ª, vai percorrer a lista inteira (tá, são só 50 elementos, mas vai percorrer) zilhões - 50 vezes.

É melhor manter um contadorzinho manual.