Comment lire une ligne spécifique en utilisant le numéro de ligne spécifique d'un fichier en Java?


90

En Java, existe-t-il une méthode pour lire une ligne particulière à partir d'un fichier? Par exemple, lisez la ligne 32 ou tout autre numéro de ligne.


5
Je sais que je suis très en retard, mais au cas où quelqu'un trouverait cette question: notez qu'un fichier n'est qu'une séquence d'octets. Et une nouvelle ligne n'est qu'un caractère (deux sous Windows), et un caractère est juste un octet (ou plus, selon l'encodage). Et, sans avoir d'index des positions d'un octet dans un fichier, le seul moyen de savoir où se trouvent ces octets est de le lire et de le rechercher. (cela ne signifie cependant pas que vous devez charger le fichier entier en mémoire).
szgal

Réponses:


71

Sauf si vous avez une connaissance préalable des lignes du fichier, il n'y a aucun moyen d'accéder directement à la 32e ligne sans lire les 31 lignes précédentes.

C'est vrai pour toutes les langues et tous les systèmes de fichiers modernes.

Donc, effectivement, vous lirez simplement les lignes jusqu'à ce que vous ayez trouvé la 32e.


4
La «connaissance précédente» peut être aussi simple que le modèle de taille de ligne exacte dans le fichier afin que vous puissiez rechercher une certaine position.
Murali VP

2
@Murali: bien sûr. Il peut également s'agir d'un index du numéro de ligne au décalage d'octet ou de toute combinaison de ceux-ci.
Joachim Sauer

103

Pour les petits fichiers:

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

Pour les gros fichiers:

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

Cela renvoie java.nio.charset.MalformedInputException: Input length = 1 lorsqu'il est utilisé avec une valeur de saut de 1
canadiancreed

Ce n'est pas un problème avec le code que j'ai publié, c'est un problème avec l'encodage de votre fichier. Voir ce post .
aioobe

3
"Notez que cette méthode est destinée aux cas simples où il est pratique de lire toutes les lignes en une seule opération. Elle n'est pas destinée à la lecture de fichiers volumineux." - Javadoc of Files.readAllLines ()
PragmaticProgrammer

Le code suivant nécessite le niveau d'API 26 dans Android. Si notre min est inférieur à ce niveau, cela ne fonctionne pas
Ali Azaz Alam

38

Pas que je sache, mais ce que vous pouvez faire est de parcourir les 31 premières lignes sans rien faire en utilisant la fonction readline () de 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
Veuillez noter qu'ici vous lisez la ligne 30, qui est la 31e ligne parce que nous commençons les numéros de ligne à partir de 0. Je suggérerais donc de la changer pour qu'elle corresponde précisément à la question.
kiedysktos

15

Joachim a raison, bien sûr, et une implémentation alternative à celle de Chris (pour les petits fichiers uniquement parce qu'il charge le fichier entier) pourrait être d'utiliser commons-io d'Apache (bien que vous ne souhaitiez peut-être pas introduire une nouvelle dépendance juste pour ceci, si vous le trouvez utile pour d'autres choses aussi, cela pourrait avoir du sens).

Par exemple:

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
Bien que cela chargerait tout le fichier en mémoire avant d'aller à la 32e ligne, ce qui pourrait ne pas être pratique avec un gros fichier et serait plus lent que de lire util pour trouver la 32e ligne ...
beny23

Bon point, oui. J'ai utilisé cela dans des cas de test, où les fichiers de test étaient petits, mais sur de gros fichiers, d'accord, ce n'est pas une bonne approche.
Charlie Collins

Message de réponse mis à jour pour refléter que FileUtils est une mauvaise idée dans ce cas d'utilisation si vous avez un fichier volumineux et n'avez besoin de rien au-delà de la ligne X.
Charlie Collins

11

Vous pouvez essayer le lecteur de fichiers indexés (licence Apache 2.0). La classe IndexedFileReader a une méthode appelée readLines (int from, int to) qui renvoie un SortedMap dont la clé est le numéro de ligne et la valeur est la ligne qui a été lue.

Exemple:

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]"));      

L'exemple ci-dessus lit un fichier texte composé de 50 lignes au format suivant:

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

Disclamer: j'ai écrit cette bibliothèque


6

Bien que comme indiqué dans d'autres réponses, il n'est pas possible d'accéder à la ligne exacte sans connaître le décalage (pointeur) auparavant. Donc, j'ai réalisé cela en créant un fichier d'index temporaire qui stockerait les valeurs de décalage de chaque ligne. Si le fichier est suffisamment petit, vous pouvez simplement stocker les index (offset) en mémoire sans avoir besoin d'un fichier séparé pour cela.

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

Consultez également la documentation java pour plus d'informations: https://docs.oracle.com/javase/8/docs/api/java/io/RandomAccessFile.html#mode

Complexité : C'est O (n) car il lit une fois le fichier entier. Veuillez prendre en compte les besoins en mémoire. S'il est trop volumineux pour être en mémoire, créez un fichier temporaire qui stocke les décalages au lieu de ArrayList comme indiqué ci-dessus.

Remarque : Si tout ce que vous voulez en ligne '32', il vous suffit d'appeler readLine () également disponible via d'autres classes '32' fois. L'approche ci-dessus est utile si vous souhaitez obtenir une ligne spécifique (en fonction du numéro de ligne bien sûr) plusieurs fois.

Merci !


Il y a quelque chose à modifier pour que le code ci-dessus fonctionne. Et si quelqu'un a besoin d'un jeu de caractères concerné, vous devriez vraiment lire ceci: stackoverflow.com/a/37275357/3198960
rufushuang

5

Autrement.

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
Élégant, j'aime ça.
Florescu Cătălin

4

Non, à moins que dans ce format de fichier les longueurs de ligne ne soient prédéterminées (par exemple, toutes les lignes avec une longueur fixe), vous devrez itérer ligne par ligne pour les compter.


2

Si vous parlez d'un fichier texte, alors il n'y a vraiment aucun moyen de le faire sans lire toutes les lignes qui le précèdent - Après tout, les lignes sont déterminées par la présence d'une nouvelle ligne, il faut donc la lire.

Utilisez un flux prenant en charge readline, lisez simplement les premières lignes X-1 et sauvegardez les résultats, puis traitez la suivante.


2

Dans Java 8,

Pour les petits fichiers:

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

Pour les gros fichiers:

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

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

Source: lecture de la nième ligne du fichier


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

Cela fonctionne pour moi: j'ai combiné la réponse de lire un simple fichier texte

Mais au lieu de renvoyer une chaîne, je renvoie une liste LinkedList de chaînes. Ensuite, je peux sélectionner la ligne que je veux.

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

Vous pouvez alors faire: linkedlist.get (31)
Tachenko

1

Utilisez ce code:

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

Vous pouvez utiliser LineNumberReader au lieu de BufferedReader. Passez par l'API. Vous pouvez trouver les méthodes setLineNumber et getLineNumber.


n'aide pas - vous devez toujours lire toutes les lignes avant ... sauf que vous trichez et que vous définissez la première ligne sur 32 <g>
kleopatra

0

Vous pouvez également jeter un œil à LineNumberReader, sous-classe de BufferedReader. En plus de la méthode readline, il dispose également de méthodes setter / getter pour accéder au numéro de ligne. Très utile pour garder une trace du nombre de lignes lues, lors de la lecture des données du fichier.


0

vous pouvez utiliser la fonction skip () pour sauter les lignes du début.

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

Ils ont tous tort, je viens d'écrire ceci en 10 secondes environ. Avec cela, j'ai réussi à appeler l'objet.getQuestion ("numéro de lin") dans la méthode principale pour renvoyer la ligne que je veux.

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; }}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.