Como ler uma linha específica usando o número da linha específica de um arquivo em Java?


90

Em Java, existe algum método para ler uma linha específica de um arquivo? Por exemplo, leia a linha 32 ou qualquer outro número de linha.


5
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ª.


4
O "conhecimento prévio" pode ser tão simples quanto o padrão de tamanho de linha exato no arquivo para que você possa buscar uma determinada posição.
Murali VP

2
@Murali: claro. Também pode ser um índice de número de linha para deslocamento de byte ou qualquer combinação destes.
Joachim Sauer

102

Para arquivos pequenos:

String line32 = Files.readAllLines(Paths.get("file.txt")).get(32)

Para arquivos grandes:

try (Stream<String> lines = Files.lines(Paths.get("file.txt"))) {
    line32 = lines.skip(31).findFirst().get();
}

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= new FileInputStream("someFile.txt");
BufferedReader br = new BufferedReader(new InputStreamReader(fs));
for(int i = 0; i < 31; ++i)
  br.readLine();
String lineIWant = br.readLine();

1
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).

Por exemplo:

String line32 = (String) FileUtils.readLines(file).get(31);

http://commons.apache.org/io/api-release/org/apache/commons/io/FileUtils.html#readLines(java.io.File , java.lang.String)


2
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.

Exemplo:

File file = new File("src/test/resources/file.txt");
reader = new IndexedFileReader(file);

lines = reader.readLines(6, 10);
assertNotNull("Null result.", lines);
assertEquals("Incorrect length.", 5, lines.size());
assertTrue("Incorrect value.", lines.get(6).startsWith("[6]"));
assertTrue("Incorrect value.", lines.get(7).startsWith("[7]"));
assertTrue("Incorrect value.", lines.get(8).startsWith("[8]"));
assertTrue("Incorrect value.", lines.get(9).startsWith("[9]"));
assertTrue("Incorrect value.", lines.get(10).startsWith("[10]"));      

O exemplo acima lê um arquivo de texto composto por 50 linhas no seguinte formato:

[1] The quick brown fox jumped over the lazy dog ODD
[2] The quick brown fox jumped over the lazy dog EVEN

Disclamer: Eu escrevi esta biblioteca


6

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 RandomAccessFile

    RandomAccessFile raf = new RandomAccessFile("myFile.txt","r"); 
    //above 'r' means open in read only mode
    ArrayList<Integer> arrayList = new ArrayList<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();

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 !


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

1
Elegante, eu gosto.
Florescu Cătălin

4

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.


2

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.


2

Em Java 8,

Para arquivos pequenos:

String line = Files.readAllLines(Paths.get("file.txt")).get(n);

Para arquivos grandes:

String line;
try (Stream<String> lines = Files.lines(Paths.get("file.txt"))) {
    line = lines.skip(n).findFirst().get();
}

Em Java 7

String line;
try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {
    for (int i = 0; i < n; i++)
        br.readLine();
    line = br.readLine();
}

Fonte: Lendo enésima linha do arquivo


1
public String readLine(int line){
        FileReader tempFileReader = null;
        BufferedReader tempBufferedReader = null;
        try { tempFileReader = new FileReader(textFile); 
        tempBufferedReader = new BufferedReader(tempFileReader);
        } catch (Exception e) { }
        String returnStr = "ERROR";
        for(int i = 0; i < line - 1; i++){
            try { tempBufferedReader.readLine(); } catch (Exception e) { }
        }
        try { returnStr = tempBufferedReader.readLine(); }  catch (Exception e) { }

        return returnStr;
    }

1

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.

public static LinkedList<String> readFromAssets(Context context, String filename) throws IOException {
    BufferedReader reader = new BufferedReader(new InputStreamReader(context.getAssets().open(filename)));
    LinkedList<String>linkedList = new LinkedList<>();
    // do reading, usually loop until end of file reading
    StringBuilder sb = new StringBuilder();
    String mLine = reader.readLine();
    while (mLine != null) {
        linkedList.add(mLine);
        sb.append(mLine); // process line
        mLine = reader.readLine();


    }
    reader.close();
    return linkedList;
}

Você pode então fazer: linkedlist.get (31)
Tachenko

1

Use este código:

import java.nio.file.Files;

import java.nio.file.Paths;

public class FileWork 
{

    public static void main(String[] args) throws IOException {

        String line = Files.readAllLines(Paths.get("D:/abc.txt")).get(1);

        System.out.println(line);  
    }

}

0

Você pode usar LineNumberReader em vez de BufferedReader. Vá até a API. Você pode encontrar os métodos setLineNumber e getLineNumber.


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.


0

você pode usar a função skip () para pular as linhas desde o início.

public static void readFile(String filePath, long lineNum) {
    List<String> list = new ArrayList<>();
    long totalLines, startLine = 0;

    try (Stream<String> lines = Files.lines(Paths.get(filePath))) {
        totalLines = Files.lines(Paths.get(filePath)).count();
        startLine = totalLines - lineNum;
        // Stream<String> line32 = lines.skip(((startLine)+1));

        list = lines.skip(startLine).collect(Collectors.toList());
        // lines.forEach(list::add);
    } catch (IOException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }

    list.forEach(System.out::println);

}

-7

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.

public class Questions {

File file = new File("Question2Files/triviagame1.txt");

public Questions() {

}

public String getQuestion(int numLine) throws IOException {
    BufferedReader br = new BufferedReader(new FileReader(file));
    String line = "";
    for(int i = 0; i < numLine; i++) {
        line = br.readLine();
    }
    return line; }}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.