Lecture d'un fichier texte à l'aide de streamreader.
using (StreamReader sr = new StreamReader(FileName, Encoding.Default))
{
string line = sr.ReadLine();
}
Je veux forcer ce délimiteur de ligne devrait être \n
et non pas \r
. Alors, comment puis-je faire ça?
string text = sr.ReadToEnd();
string[] lines = text.Split('\r');
foreach(string s in lines)
{
// Consume
}
J'implémenterais quelque chose comme la réponse de George, mais comme méthode d'extension évitant de charger tout le fichier à la fois (non testé, mais quelque chose comme ceci):
static class ExtensionsForTextReader
{
public static IEnumerable<string> ReadLines (this TextReader reader, char delimiter)
{
List<char> chars = new List<char> ();
while (reader.Peek() >= 0)
{
char c = (char)reader.Read ();
if (c == delimiter) {
yield return new String(chars.ToArray());
chars.Clear ();
continue;
}
chars.Add(c);
}
}
}
Ce qui pourrait alors être utilisé comme:
using (StreamReader sr = new StreamReader(FileName, Encoding.Default))
{
foreach (var line in sr.ReadLines ('\n'))
Console.WriteLine (line);
}
J'ai adoré la réponse donnée par @Pete. Je voudrais juste soumettre une légère modification. Cela vous permettra de passer un séparateur de chaîne au lieu d'un seul caractère:
using System;
using System.IO;
using System.Collections.Generic;
internal static class StreamReaderExtensions
{
public static IEnumerable<string> ReadUntil(this StreamReader reader, string delimiter)
{
List<char> buffer = new List<char>();
CircularBuffer<char> delim_buffer = new CircularBuffer<char>(delimiter.Length);
while (reader.Peek() >= 0)
{
char c = (char)reader.Read();
delim_buffer.Enqueue(c);
if (delim_buffer.ToString() == delimiter || reader.EndOfStream)
{
if (buffer.Count > 0)
{
if (!reader.EndOfStream)
{
yield return new String(buffer.ToArray()).Replace(delimiter.Substring(0, delimiter.Length - 1), string.Empty);
}
else
{
buffer.Add(c);
yield return new String(buffer.ToArray());
}
buffer.Clear();
}
continue;
}
buffer.Add(c);
}
}
private class CircularBuffer<T> : Queue<T>
{
private int _capacity;
public CircularBuffer(int capacity)
: base(capacity)
{
_capacity = capacity;
}
new public void Enqueue(T item)
{
if (base.Count == _capacity)
{
base.Dequeue();
}
base.Enqueue(item);
}
public override string ToString()
{
List<String> items = new List<string>();
foreach (var x in this)
{
items.Add(x.ToString());
};
return String.Join("", items);
}
}
}
Selon la documentation:
http://msdn.Microsoft.com/en-us/library/system.io.streamreader.readline.aspx
Une ligne est définie comme une séquence de caractères suivie d'un saut de ligne ("\ n"), un retour de chariot ("\ r") ou un retour de chariot immédiatement suivi d'un saut de ligne ("\ r\n").
Par défaut, la méthode StreamReader ReadLine reconnaîtra une ligne à la fois/\ n ou\r
C'est une amélioration de la réponse de sovemp. Désolé, j'aurais aimé commenter, bien que ma réputation ne me permette pas de le faire. Cette amélioration concerne 2 problèmes:
lorsque les derniers caractères du flux sont égaux au délimiteur, la fonction renverrait à tort une chaîne, y compris des délimiteurs.
using System;
using System.IO;
using System.Collections.Generic;
internal static class StreamReaderExtensions
{
public static IEnumerable<string> ReadUntil(this StreamReader reader, string delimiter)
{
List<char> buffer = new List<char>();
CircularBuffer<char> delim_buffer = new CircularBuffer<char>(delimiter.Length);
while (reader.Peek() >= 0)
{
char c = (char)reader.Read();
delim_buffer.Enqueue(c);
if (delim_buffer.ToString() == delimiter || reader.EndOfStream)
{
if (buffer.Count > 0)
{
if (!reader.EndOfStream)
{
buffer.Add(c);
yield return new String(buffer.ToArray()).Substring(0, buffer.Count - delimeter.Length);
}
else
{
buffer.Add(c);
if (delim_buffer.ToString() != delimiter)
yield return new String(buffer.ToArray());
else
yield return new String(buffer.ToArray()).Substring(0, buffer.Count - delimeter.Length);
}
buffer.Clear();
}
continue;
}
buffer.Add(c);
}
}
private class CircularBuffer<T> : Queue<T>
{
private int _capacity;
public CircularBuffer(int capacity)
: base(capacity)
{
_capacity = capacity;
}
new public void Enqueue(T item)
{
if (base.Count == _capacity)
{
base.Dequeue();
}
base.Enqueue(item);
}
public override string ToString()
{
List<String> items = new List<string>();
foreach (var x in this)
{
items.Add(x.ToString());
};
return String.Join("", items);
}
}
}
Vous devez soit analyser le flux, octet par octet, vous-même et gérer le fractionnement, soit utiliser le comportement par défaut de ReadLine, qui scinde sur/r,/n ou/r/n.
Si vous voulez analyser le flux octet par octet, j'utiliserais quelque chose comme la méthode d'extension suivante:
public static string ReadToChar(this StreamReader sr, char splitCharacter)
{
char nextChar;
StringBuilder line = new StringBuilder();
while (sr.Peek() > 0)
{
nextChar = (char)sr.Read();
if (nextChar == splitCharacter) return line.ToString();
line.Append(nextChar);
}
return line.Length == 0 ? null : line.ToString();
}
J'avais besoin d'une solution qui se lit jusqu'à "\ r\n", et ne s'arrête pas à "\ n". La solution de jp1980 a fonctionné, mais était extrêmement lente sur un fichier volumineux. J'ai donc converti la solution de Mike Sackton en lecture jusqu'à ce qu'une chaîne spécifiée soit trouvée.
public static string ReadToString(StreamReader sr, string splitString)
{
char nextChar;
StringBuilder line = new StringBuilder();
int matchIndex = 0;
while (sr.Peek() > 0)
{
nextChar = (char)sr.Read();
line.Append(nextChar);
if (nextChar == splitString[matchIndex])
{
if(matchIndex == splitString.Length - 1)
{
return line.ToString().Substring(0, line.Length - splitString.Length);
}
matchIndex++;
}
else
{
matchIndex = 0;
}
}
return line.Length == 0 ? null : line.ToString();
}
Et ça s'appelle comme ça ...
using (StreamReader reader = new StreamReader(file))
{
string line;
while((line = ReadToString(reader, "\r\n")) != null)
{
Console.WriteLine(line);
}
}
Même si vous avez dit "Using StreamReader", puisque vous avez également déclaré "Mon cas, le fichier peut contenir des tonnes d'enregistrements ...", je recommanderais d'essayer SSIS. C'est parfait pour ce que vous essayez de faire. Vous pouvez traiter un fichier très volumineux et spécifier facilement les délimiteurs de ligne/colonne.
Vous pouvez simplement utiliser ReadToEnd () sur le lecteur, puis utiliser String.Split pour le délimiter comme bon vous semble.
Cet extrait de code lira une ligne d'un fichier jusqu'à ce qu'il rencontre "\ n".
using (StreamReader sr = new StreamReader(path))
{
string line = string.Empty;
while (sr.Peek() >= 0)
{
char c = (char)sr.Read();
if (c == '\n')
{
//end of line encountered
Console.WriteLine(line);
//create new line
line = string.Empty;
}
else
{
line += (char)sr.Read();
}
}
}
Parce que ce code lit caractère par caractère, il fonctionne avec un fichier de n'importe quelle longueur sans être contraint par la mémoire disponible.