FileStream est en position off après l'appel de ReadLine() à partir de C#
Je suis en train de lire une (petite-ish) le fichier en morceaux de quelques lignes à un moment, et j'ai besoin de retourner au début de particulier morceaux.
Le problème est que, après le premier appel à
streamReader.ReadLine();
la streamReader.BaseStream.Position
propriété est définie à la fin du fichier! Maintenant, je suppose que certains de la mise en cache se fait dans les coulisses, mais je m'attendais à cette propriété pour refléter le nombre d'octets qui je utilisé à partir de ce fichier. Et oui, le fichier a plus d'une ligne 🙂
Par exemple, l'appel ReadLine()
de nouveau (naturellement) le retour de la ligne suivante dans le fichier, ce qui ne démarre pas à la position précédemment rapporté par streamReader.BaseStream.Position
.
Comment puis-je trouver les réelle position où la 1ère ligne se termine, donc, je peux y revenir plus tard?
Je ne peux que penser à faire manuellement la tenue de la comptabilité, en ajoutant de la longueur des chaînes de caractères retournée par ReadLine(), mais même ici, il ya un couple de mises en garde:
- ReadLine() supprime le caractère de nouvelle ligne(s) qui peut avoir une longueur variable ('\n'? Est-il "\r\n"? Etc.)
- Je ne sais pas si ce serait le travail OK avec la longueur variable des caractères
...donc, pour l'instant il semble que ma seule option est de repenser la façon dont je parse le fichier, donc je n'ai pas à revenir en arrière.
Si cela peut aider, j'ai ouvert mon fichier comme ceci:
using (var reader = new StreamReader(
new FileStream(
m_path,
FileMode.Open,
FileAccess.Read,
FileShare.ReadWrite)))
{...}
Des suggestions?
OriginalL'auteur Cristi Diaconescu | 2010-05-28
Vous devez vous connecter pour publier un commentaire.
Si vous avez besoin de lire des lignes, et vous avez besoin de revenir à la précédente morceaux, pourquoi ne pas stocker les lignes que vous lisez dans une Liste? Cela devrait être assez facile.
Vous ne devriez pas dépendre sur le calcul de la longueur en octets basé sur la longueur de la chaîne - pour les raisons que vous mentionnez vous-même: des caractères Multioctets, les caractères de saut de ligne, etc.
OriginalL'auteur driis
J'ai fait une implémentation similaire où j'avais besoin d'accéder à la n-ième ligne, dans un très gros fichier texte rapide.
La raison
streamReader.BaseStream.Position
avait souligné, à la fin du fichier, c'est qu'il a une mémoire tampon intégré, comme vous l'avez prévu.Comptabilité par comptage du nombre d'octets lus à partir de chaque
ReadLine()
appel à la plupart des fichiers de texte brut. Cependant, j'ai rencontré de cas où il y a un caractère de contrôle, la non imprimable, mélangé dans le fichier texte. Le nombre d'octets calculée est mal et la cause de mon programme de ne pas être en mesure de rechercher l'emplacement correct par la suite.Ma dernière solution était d'aller avec la mise en œuvre de la ligne de lecteur sur mon propre. Il a bien fonctionné jusqu'à présent. Cela devrait donner quelques idées à quoi il ressemble:
Et pour revenir à connecté offset:
Également noter qu'il y est déjà mise en mémoire tampon mécanisme construit en
FileStream
.OriginalL'auteur Gant
StreamReader
n'est pas conçu pour ce type d'utilisation, donc si c'est ce que vous avez besoin, je soupçonne que vous devrez écrire votre propre wrapper pourFileStream
.OriginalL'auteur JSBձոգչ
Un problème avec l'acceptées réponse est que si ReadLine() rencontre une exception, dire en raison de la structure de journalisation du verrouillage d'un fichier temporairement à droite lorsque vous ReadLine(), alors vous n'aurez pas que la ligne "sauvé" dans une liste car il n'est jamais retourné une ligne. Si vous attrapez cette exception, vous ne peut pas retenter l'ReadLine() une deuxième fois parce que StreamReaders interne de l'état et de la mémoire tampon sont vissé vers le haut à partir de la dernière ReadLine() et vous obtenez seulement une partie d'un retourné, et vous ne pouvez pas ignorer que la ligne brisée et demander de revenir au début de ce que l'OP.
Si vous voulez obtenir le vrai seekable endroit, alors vous devez utiliser la réflexion pour arriver à StreamReaders variables privées qui vous permettent de calculer sa position à l'intérieur de son propre tampon. Granger solution vu ici: StreamReader et de la recherche, devrait fonctionner. Ou faire ce que d'autres réponses à d'autres questions connexes ont fait: créer votre propre StreamReader qui expose la vraie seekable emplacement (cette réponse dans ce lien: Le suivi de la position de la ligne d'un streamreader). Ce sont les deux seules options que j'ai rencontré tout en traitant avec StreamReader et de la recherche, qui, pour une raison quelconque a décidé de supprimer complètement la possibilité de chercher dans presque toutes les situations.
edit: j'ai utilisé Granger solution et ça fonctionne. Juste être sûr que vous allez dans cet ordre: GetActualPosition(), puis mis en BaseStream.La Position de cette position, alors assurez-vous que vous appelez DiscardBufferedData(), et enfin, vous pouvez appeler ReadLine() et vous obtiendrez la ligne complète à partir de la position donnée dans la méthode.
OriginalL'auteur Quantic