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.
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.
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=newFileInputStream("someFile.txt");BufferedReader br =newBufferedReader(newInputStreamReader(fs));for(int i =0; i <31;++i)
br.readLine();String lineIWant = br.readLine();
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).
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.
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 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();
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.
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);}
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.
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.
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.
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'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.
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.
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;}}
Réponses:
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.
la source
Pour les petits fichiers:
Pour les gros fichiers:
la source
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
la source
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:
http://commons.apache.org/io/api-release/org/apache/commons/io/FileUtils.html#readLines(java.io.File , java.lang.String)
la source
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:
L'exemple ci-dessus lit un fichier texte composé de 50 lignes au format suivant:
Disclamer: j'ai écrit cette bibliothèque
la source
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.
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 !
la source
Autrement.
la source
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.
la source
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.
la source
Dans Java 8,
Pour les petits fichiers:
Pour les gros fichiers:
Dans Java 7
Source: lecture de la nième ligne du fichier
la source
la source
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.
la source
Utilisez ce code:
la source
Vous pouvez utiliser LineNumberReader au lieu de BufferedReader. Passez par l'API. Vous pouvez trouver les méthodes setLineNumber et getLineNumber.
la source
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.
la source
vous pouvez utiliser la fonction skip () pour sauter les lignes du début.
la source
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.
la source