Il existe un File.ReadAllLines
mais pas un Stream.ReadAllLines
.
using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Test_Resources.Resources.Accounts.txt"))
using (StreamReader reader = new StreamReader(stream))
{
// Would prefer string[] result = reader.ReadAllLines();
string result = reader.ReadToEnd();
}
Existe-t-il un moyen de faire cela ou dois-je parcourir manuellement le fichier ligne par ligne?
Vous pouvez écrire une méthode qui lit ligne par ligne, comme ceci:
public IEnumerable<string> ReadLines(Func<Stream> streamProvider,
Encoding encoding)
{
using (var stream = streamProvider())
using (var reader = new StreamReader(stream, encoding))
{
string line;
while ((line = reader.ReadLine()) != null)
{
yield return line;
}
}
}
Puis appelez-le comme:
var lines = ReadLines(() => Assembly.GetExecutingAssembly()
.GetManifestResourceStream(resourceName),
Encoding.UTF8)
.ToList();
La partie Func<>
consiste à faire face lors de la lecture plusieurs fois et à éviter de laisser inutilement des flux ouverts. Vous pouvez facilement envelopper ce code dans une méthode, bien sûr.
Si vous n'avez pas besoin de tout cela en même temps, vous n'avez même pas besoin de la variable ToList
...
La propriété .EndOfStream
peut être utilisée dans la boucle au lieu de vérifier si la ligne suivante n'est pas nulle.
List<string> lines = new List<string>();
using (StreamReader reader = new StreamReader("example.txt"))
{
while(!reader.EndOfStream)
{
lines.Add(reader.ReadLine());
}
}
L'utilisation de Split
ici:
reader
.ReadToEnd()
.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
n'est pas équivalent à ReadLine
. Si vous regardez la source de ReadLine
, StreamReader.cs , vous verrez qu’elle gère correctement les terminaisons de ligne:\r,\n et\r\n. ReadLine
ne renvoie pas de chaîne vide supplémentaire lorsque le terminateur de ligne est\r\n, ce qui est typique sous DOS/Windows. Split
"voit" (analyse)\r suivi de\n sous forme de 2 délimiteurs distincts et renvoie une chaîne vide.
'StringSplitOptions.RemoveEmptyEntries' dans le code ci-dessus supprime ces chaînes vides, mais supprime également les lignes vides qui apparaissent également dans l'entrée.
Donc pour l'entrée line1\r \r line3\r ReadLine
renvoie 3 lignes. Le 2nd est vide .Split
crée 4 chaînes. (Il y a une chaîne supplémentaire après le dernier\r.) Il supprime ensuite les 2e et 4e.
Notez que Split
n'est pas bien adapté à l'analyse de lignes de texte délimitées "post-fix". C’est le délimiteur qui apparaît après le jeton. Alors que Split
est approprié pour infixe, où les délimiteurs apparaissent entre les jetons. C'est la différence entre a, b, c et line1\r, line2, line3\r. Pour ces entrées, Split
renvoie 3 chaînes ou 4 chaînes respectivement.
using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Test_Resources.Resources.Accounts.txt"))
using (StreamReader reader = new StreamReader(stream))
{
// Would prefer string[] result = reader.ReadAllLines();
string[] result = reader.ReadToEnd().Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
}
En utilisant la méthode d'extension suivante:
public static class Extensions
{
public static IEnumerable<string> ReadAllLines(this StreamReader reader)
{
string line;
while ((line = reader.ReadLine()) != null)
{
yield return line;
}
}
}
Il est possible d'obtenir le code souhaité:
using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Test_Resources.Resources.Accounts.txt"))
using (StreamReader reader = new StreamReader(stream))
{
string[] result = reader.ReadAllLines().ToArray();
}
Si vous voulez utiliser StreamReader, alors oui, vous devrez utiliser ReadLine et lire en boucle StreamReader, en le lisant ligne par ligne.
Quelque chose comme ca:
string line;
using (StreamReader reader = new StreamReader(stream))
{
while ((line = reader.ReadLine()) != null)
{
Console.WriteLine(line);
}
}
ou essayer
using (StreamReader reader = new StreamReader("file.txt"))
{
string[] content = reader.ReadToEnd().Replace("\n","").Split('\t');
}