Quelle est la manière appropriée de traiter les fichiers texte volumineux dans Objective-C? Disons que j'ai besoin de lire chaque ligne séparément et que je veux traiter chaque ligne comme une NSString. Quelle est la manière la plus efficace de procéder?
Une solution consiste à utiliser la méthode NSString:
+ (id)stringWithContentsOfFile:(NSString *)path
encoding:(NSStringEncoding)enc
error:(NSError **)error
puis divisez les lignes avec un séparateur de nouvelle ligne, puis parcourez les éléments du tableau. Cependant, cela semble assez inefficace. N'existe-t-il pas un moyen facile de traiter le fichier comme un flux, en énumérant chaque ligne, au lieu de simplement tout lire en même temps? Un peu comme java.io.BufferedReader de Java.
Réponses:
C'est une excellente question. Je pense que @Diederik a une bonne réponse, même s'il est regrettable que Cocoa n'ait pas de mécanisme pour exactement ce que vous voulez faire.
NSInputStream
vous permet de lire des morceaux de N octets (très similaire àjava.io.BufferedReader
), mais vous devez le convertir en unNSString
seul, puis rechercher les nouvelles lignes (ou tout autre délimiteur) et enregistrer les caractères restants pour la prochaine lecture, ou lire plus de caractères si une nouvelle ligne n'a pas encore été lue. (NSFileHandle
vous permet de lire unNSData
que vous pouvez ensuite convertir en unNSString
, mais c'est essentiellement le même processus.)Apple a un guide de programmation de flux qui peut aider à remplir les détails, et cette question SO peut également vous aider si vous avez affaire à des
uint8_t*
tampons.Si vous lisez fréquemment des chaînes comme celle-ci (en particulier dans différentes parties de votre programme), ce serait une bonne idée d'encapsuler ce comportement dans une classe qui peut gérer les détails pour vous, ou même de sous-classer
NSInputStream
(il est conçu pour être sous-classées ) et en ajoutant des méthodes qui vous permettent de lire exactement ce que vous voulez.Pour mémoire, je pense que ce serait une fonctionnalité intéressante à ajouter, et je vais déposer une demande d'amélioration pour quelque chose qui rend cela possible. :-)
Modifier: il s'avère que cette demande existe déjà. Il existe un radar datant de 2006 pour cela (rdar: // 4742914 pour les personnes internes à Apple).
la source
Cela fonctionnera pour la lecture générale
String
deText
. Si vous souhaitez lire du texte plus long ( texte de grande taille) , utilisez la méthode mentionnée par d'autres personnes ici, par exemple en mémoire tampon (réservez la taille du texte dans l'espace mémoire) .Disons que vous lisez un fichier texte.
Vous voulez vous débarrasser de la nouvelle ligne.
Voilà.
la source
Cela devrait faire l'affaire:
Utilisez comme suit:
Ce code lit les caractères non-nouvelle ligne du fichier, jusqu'à 4095 à la fois. Si vous avez une ligne de plus de 4095 caractères, la lecture continue jusqu'à ce qu'elle atteigne une nouvelle ligne ou une fin de fichier.
Remarque : je n'ai pas testé ce code. Veuillez le tester avant de l'utiliser.
la source
"%4095[^\n]%n%*c"
consommera et jettera silencieusement un caractère à chaque lecture de tampon. Il semble que ce format suppose que les lignes seront plus courtes que la longueur du tampon.Mac OS X est Unix, Objective-C est un sur-ensemble C, vous pouvez donc simplement utiliser old-school
fopen
etfgets
from<stdio.h>
. Il est garanti de fonctionner.[NSString stringWithUTF8String:buf]
convertira la chaîne C enNSString
. Il existe également des méthodes pour créer des chaînes dans d'autres encodages et créer sans copier.la source
fgets
inclura le'\n'
caractère, donc vous voudrez peut-être le supprimer avant de convertir la chaîne.Vous pouvez utiliser
NSInputStream
qui a une implémentation de base pour les flux de fichiers. Vous pouvez lire des octets dans un tampon (read:maxLength:
méthode). Vous devez scanner vous-même la mémoire tampon pour les nouvelles lignes.la source
La manière appropriée de lire les fichiers texte dans Cocoa / Objective-C est documentée dans le guide de programmation String d'Apple. La section pour lire et écrire des fichiers devrait être exactement ce que vous recherchez. PS: Qu'est-ce qu'une "ligne"? Deux sections d'une chaîne séparées par "\ n"? Ou "\ r"? Ou "\ r \ n"? Ou peut-être êtes-vous en fait après les paragraphes? Le guide mentionné précédemment comprend également une section sur la division d'une chaîne en lignes ou en paragraphes. (Cette section s'appelle "Paragraphes et sauts de ligne" et est liée dans le menu de gauche de la page que j'ai indiquée ci-dessus. Malheureusement, ce site ne me permet pas de publier plus d'une URL car je suis pas encore un utilisateur digne de confiance.)
Pour paraphraser Knuth: l'optimisation prématurée est la racine de tout mal. Ne supposez pas simplement que "lire le fichier entier en mémoire" est lent. L'avez-vous évalué? Savez-vous qu'il lit réellement le fichier entier en mémoire? Peut-être qu'il renvoie simplement un objet proxy et continue de lire dans les coulisses lorsque vous consommez la chaîne? ( Clause de non-responsabilité: je n'ai aucune idée si NSString fait réellement cela. Il pourrait le faire. ) Le point est: commencez par suivre la manière documentée de faire les choses. Ensuite, si les benchmarks montrent que cela n'a pas les performances que vous désirez, optimisez.
la source
-stringWithContentsOf*
méthodes suivies par-componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]
, il voit le\r
et\n
séparément et ajoute une ligne vide après chaque ligne.Un grand nombre de ces réponses sont de longs morceaux de code ou lisent le fichier entier. J'aime utiliser les méthodes c pour cette tâche même.
Notez que fgetln ne conservera pas votre caractère de nouvelle ligne. En outre, nous +1 la longueur de la chaîne parce que nous voulons faire de la place pour la terminaison NULL.
la source
La lecture d'un fichier ligne par ligne (également pour les fichiers extrêmement volumineux) peut être effectuée par les fonctions suivantes:
Ou:
La classe DDFileReader qui permet cela est la suivante:
Fichier d'interface (.h):
Implémentation (.m)
Le cours a été fait par Dave DeLong
la source
Tout comme @porneL l'a dit, l'API C est très pratique.
la source
Comme d'autres l'ont répondu, NSInputStream et NSFileHandle sont de bonnes options, mais cela peut également être fait de manière assez compacte avec NSData et le mappage de la mémoire:
BRLineReader.h
BRLineReader.m
la source
Cette réponse n'est PAS ObjC mais C.
Puisque ObjC est basé sur «C», pourquoi ne pas utiliser des fgets?
Et oui, je suis sûr qu'ObjC a sa propre méthode - je ne suis tout simplement pas encore assez compétent pour savoir ce que c'est :)
la source
meta
question; Les très anciennes questions d'utilisateurs réguliers devraient-elles pouvoir être signalées pour examen?à partir de la réponse de @Adam Rosenfield, la chaîne de formatage de
fscanf
serait modifiée comme ci-dessous:il fonctionnera dans les fins de ligne osx, linux, windows.
la source
Utiliser une catégorie ou une extension pour nous rendre la vie un peu plus facile.
la source
J'ai trouvé la réponse de @lukaswelte et le code de Dave DeLong très utiles. Je cherchais une solution à ce problème, mais j'avais besoin d'analyser de gros fichiers
\r\n
non seulement\n
.Le code tel qu'il est écrit contient un bogue s'il est analysé par plus d'un caractère. J'ai changé le code comme ci-dessous.
fichier .h:
Fichier .m:
la source
J'ajoute cela parce que toutes les autres réponses que j'ai essayées ont échoué d'une manière ou d'une autre. La méthode suivante peut gérer des fichiers volumineux, de longues lignes arbitraires ainsi que des lignes vides. Il a été testé avec du contenu réel et supprimera le caractère de nouvelle ligne de la sortie.
Le crédit va à @Adam Rosenfield et @sooop
la source
Je vois que beaucoup de ces réponses reposent sur la lecture du fichier texte entier en mémoire au lieu de le prendre un morceau à la fois. Voici ma solution dans Swift moderne et agréable, en utilisant FileHandle pour réduire l'impact de la mémoire:
Notez que cela préserve le retour chariot à la fin de la ligne, donc en fonction de vos besoins, vous souhaiterez peut-être ajuster le code pour le supprimer.
Utilisation: ouvrez simplement un descripteur de fichier vers votre fichier texte cible et appelez
readLine
avec une longueur maximale appropriée - 1024 est la norme pour le texte brut, mais je l'ai laissé ouvert au cas où vous sauriez qu'il sera plus court. Notez que la commande ne débordera pas la fin du fichier, vous devrez donc peut-être vérifier manuellement que vous ne l'avez pas atteint si vous avez l'intention d'analyser le tout. Voici un exemple de code qui montre comment ouvrir un fichier àmyFileURL
et le lire ligne par ligne jusqu'à la fin.la source
Voici une belle solution simple que j'utilise pour les petits fichiers:
la source
Utilisez ce script, cela fonctionne très bien:
la source