Sei que estou muito atrasado, mas caso alguém encontre essa dúvida: Observe que um arquivo é apenas uma sequência de bytes. E uma nova linha é apenas um caractere (dois no Windows), e um caractere é apenas um (ou mais, dependendo da codificação) byte. E, sem ter um índice das posições de um byte em um arquivo, a única forma de saber onde estão esses bytes é lê-lo e procurá-lo. (isso não significa que você tenha que carregar o arquivo inteiro na memória).
szgal
Respostas:
71
A menos que você tenha conhecimento prévio sobre as linhas do arquivo, não há como acessar diretamente a 32ª linha sem ler as 31 linhas anteriores.
Isso é verdade para todas as linguagens e todos os sistemas de arquivos modernos.
De forma eficaz, você simplesmente lerá as linhas até encontrar a 32ª.
Isso retorna java.nio.charset.MalformedInputException: comprimento de entrada = 1 quando usado com o valor de salto sendo 1
canadiancreed
Isso não é um problema com o código que postei, é um problema com a codificação do seu arquivo. Veja esta postagem .
aioobe 01 de
3
"Observe que este método se destina a casos simples em que é conveniente ler todas as linhas em uma única operação. Não se destina à leitura de arquivos grandes." - Javadoc de Files.readAllLines ()
PragmaticProgrammer
O código a seguir requer API nível 26 no Android. Se nosso mínimo for menor que este nível, então não funciona
Ali Azaz Alam
38
Não que eu saiba, mas o que você poderia fazer é percorrer as primeiras 31 linhas sem fazer nada usando a função readline () do BufferedReader
FileInputStream fs=newFileInputStream("someFile.txt");BufferedReader br =newBufferedReader(newInputStreamReader(fs));for(int i =0; i <31;++i)
br.readLine();String lineIWant = br.readLine();
Observe que aqui você lê a linha número 30, que é a 31ª linha porque começamos os números da linha a partir de 0. Portanto, sugiro alterá-la para corresponder precisamente à pergunta.
kiedysktos
15
Joachim está certo, é claro, e uma implementação alternativa para Chris (para arquivos pequenos apenas porque carrega o arquivo inteiro) pode ser usar o commons-io do Apache (embora você possa não querer introduzir uma nova dependência apenas para isso, se você achar que é útil para outras coisas também, pode fazer sentido).
Embora isso carregue o arquivo inteiro na memória antes de ir para a 32ª linha, o que pode não ser prático com um arquivo grande e seria mais lento do que ler util encontrando a 32ª linha ...
beny23
Ponto justo, sim. Eu usei isso em casos de teste, onde os arquivos de teste eram pequenos, em arquivos grandes, embora, de acordo, não seja uma boa abordagem.
Charlie Collins
Postagem de resposta atualizada para refletir que FileUtils é uma má ideia neste caso de uso se você tiver um arquivo grande e não precisar de nada além da linha X.
Charlie Collins
11
Você pode tentar o leitor de arquivos indexados (Licença Apache 2.0). A classe IndexedFileReader tem um método chamado readLines (int from, int to) que retorna um SortedMap cuja chave é o número da linha e o valor é a linha lida.
Embora como dito em outras respostas, não é possível chegar à linha exata sem saber o deslocamento (ponteiro) antes. Portanto, consegui isso criando um arquivo de índice temporário que armazenaria os valores de deslocamento de cada linha. Se o arquivo for pequeno o suficiente, você pode simplesmente armazenar os índices (deslocamento) na memória sem precisar de um arquivo separado para ele.
The offsets can be calculated by using the RandomAccessFileRandomAccessFile raf =newRandomAccessFile("myFile.txt","r");//above 'r' means open in read only modeArrayList<Integer> arrayList =newArrayList<Integer>();String cur_line ="";while((cur_line=raf.readLine())!=null){
arrayList.add(raf.getFilePointer());}//Print the 32 line//Seeks the file to the particular location from where our '32' line starts
raf.seek(raf.seek(arrayList.get(31));System.out.println(raf.readLine());
raf.close();
Complexidade : Este é O (n), pois lê o arquivo inteiro uma vez. Esteja ciente dos requisitos de memória. Se for muito grande para estar na memória, crie um arquivo temporário que armazene os deslocamentos em vez de ArrayList como mostrado acima.
Nota : Se tudo o que você quiser na linha '32', basta chamar o readLine () também disponível em outras classes '32' vezes. A abordagem acima é útil se você deseja obter uma linha específica (com base no número da linha, é claro) várias vezes.
Há algo que precisa ser editado para fazer o código acima funcionar. E se alguém precisar do conjunto de caracteres, você realmente deveria ler isto: stackoverflow.com/a/37275357/3198960
rufushuang
5
Outra maneira.
try(BufferedReader reader =Files.newBufferedReader(Paths.get("file.txt"),StandardCharsets.UTF_8)){List<String> line = reader.lines().skip(31).limit(1).collect(Collectors.toList());
line.stream().forEach(System.out::println);}
Não, a menos que nesse formato de arquivo os comprimentos de linha sejam pré-determinados (por exemplo, todas as linhas com um comprimento fixo), você terá que iterar linha por linha para contá-los.
Se você está falando sobre um arquivo de texto, então realmente não há como fazer isso sem ler todas as linhas que o precedem - Afinal, as linhas são determinadas pela presença de uma nova linha, então ela deve ser lida.
Use um fluxo que suporte readline e apenas leia as primeiras linhas X-1 e despeje os resultados, em seguida, processe o próximo.
Mas em vez de retornar uma String, estou retornando uma LinkedList of Strings. Então, posso selecionar a linha que desejo.
publicstaticLinkedList<String> readFromAssets(Context context,String filename)throwsIOException{BufferedReader reader =newBufferedReader(newInputStreamReader(context.getAssets().open(filename)));LinkedList<String>linkedList =newLinkedList<>();// do reading, usually loop until end of file readingStringBuilder sb =newStringBuilder();String mLine = reader.readLine();while(mLine !=null){
linkedList.add(mLine);
sb.append(mLine);// process line
mLine = reader.readLine();}
reader.close();return linkedList;}
não ajuda - você ainda tem que ler todas as linhas antes ... exceto que você trapaceia e define a primeira linha como 32 <g>
kleopatra
0
Você também pode dar uma olhada em LineNumberReader, subclasse de BufferedReader. Junto com o método readline, ele também possui métodos setter / getter para acessar o número da linha. Muito útil para controlar o número de linhas lidas, enquanto lê os dados do arquivo.
Eles estão todos errados. Acabei de escrever isso em cerca de 10 segundos. Com isso, consegui chamar apenas o object.getQuestion ("linho") no método principal para retornar a linha que eu quiser.
publicclassQuestions{File file =newFile("Question2Files/triviagame1.txt");publicQuestions(){}publicString getQuestion(int numLine)throwsIOException{BufferedReader br =newBufferedReader(newFileReader(file));String line ="";for(int i =0; i < numLine; i++){
line = br.readLine();}return line;}}
Respostas:
A menos que você tenha conhecimento prévio sobre as linhas do arquivo, não há como acessar diretamente a 32ª linha sem ler as 31 linhas anteriores.
Isso é verdade para todas as linguagens e todos os sistemas de arquivos modernos.
De forma eficaz, você simplesmente lerá as linhas até encontrar a 32ª.
fonte
Para arquivos pequenos:
Para arquivos grandes:
fonte
Não que eu saiba, mas o que você poderia fazer é percorrer as primeiras 31 linhas sem fazer nada usando a função readline () do BufferedReader
fonte
Joachim está certo, é claro, e uma implementação alternativa para Chris (para arquivos pequenos apenas porque carrega o arquivo inteiro) pode ser usar o commons-io do Apache (embora você possa não querer introduzir uma nova dependência apenas para isso, se você achar que é útil para outras coisas também, pode fazer sentido).
Por exemplo:
http://commons.apache.org/io/api-release/org/apache/commons/io/FileUtils.html#readLines(java.io.File , java.lang.String)
fonte
Você pode tentar o leitor de arquivos indexados (Licença Apache 2.0). A classe IndexedFileReader tem um método chamado readLines (int from, int to) que retorna um SortedMap cuja chave é o número da linha e o valor é a linha lida.
Exemplo:
O exemplo acima lê um arquivo de texto composto por 50 linhas no seguinte formato:
Disclamer: Eu escrevi esta biblioteca
fonte
Embora como dito em outras respostas, não é possível chegar à linha exata sem saber o deslocamento (ponteiro) antes. Portanto, consegui isso criando um arquivo de índice temporário que armazenaria os valores de deslocamento de cada linha. Se o arquivo for pequeno o suficiente, você pode simplesmente armazenar os índices (deslocamento) na memória sem precisar de um arquivo separado para ele.
Visite também os documentos java para obter mais informações: https://docs.oracle.com/javase/8/docs/api/java/io/RandomAccessFile.html#mode
Complexidade : Este é O (n), pois lê o arquivo inteiro uma vez. Esteja ciente dos requisitos de memória. Se for muito grande para estar na memória, crie um arquivo temporário que armazene os deslocamentos em vez de ArrayList como mostrado acima.
Nota : Se tudo o que você quiser na linha '32', basta chamar o readLine () também disponível em outras classes '32' vezes. A abordagem acima é útil se você deseja obter uma linha específica (com base no número da linha, é claro) várias vezes.
Obrigado !
fonte
Outra maneira.
fonte
Não, a menos que nesse formato de arquivo os comprimentos de linha sejam pré-determinados (por exemplo, todas as linhas com um comprimento fixo), você terá que iterar linha por linha para contá-los.
fonte
Se você está falando sobre um arquivo de texto, então realmente não há como fazer isso sem ler todas as linhas que o precedem - Afinal, as linhas são determinadas pela presença de uma nova linha, então ela deve ser lida.
Use um fluxo que suporte readline e apenas leia as primeiras linhas X-1 e despeje os resultados, em seguida, processe o próximo.
fonte
Em Java 8,
Para arquivos pequenos:
Para arquivos grandes:
Em Java 7
Fonte: Lendo enésima linha do arquivo
fonte
fonte
Funciona para mim: combinei a resposta de Lendo um arquivo de texto simples
Mas em vez de retornar uma String, estou retornando uma LinkedList of Strings. Então, posso selecionar a linha que desejo.
fonte
Use este código:
fonte
Você pode usar LineNumberReader em vez de BufferedReader. Vá até a API. Você pode encontrar os métodos setLineNumber e getLineNumber.
fonte
Você também pode dar uma olhada em LineNumberReader, subclasse de BufferedReader. Junto com o método readline, ele também possui métodos setter / getter para acessar o número da linha. Muito útil para controlar o número de linhas lidas, enquanto lê os dados do arquivo.
fonte
você pode usar a função skip () para pular as linhas desde o início.
fonte
Eles estão todos errados. Acabei de escrever isso em cerca de 10 segundos. Com isso, consegui chamar apenas o object.getQuestion ("linho") no método principal para retornar a linha que eu quiser.
fonte