Pourquoi StreamReader.ReadLine () retourne une valeur pour un fichier d'une ligne sans retour à la ligne?

StackOverflow https://stackoverflow.com/questions/3445546

  •  27-09-2019
  •  | 
  •  

Question

Je veux ajouter deux fichiers texte ensemble.

I ai un fichier avec une ligne de retour chariot alimentation à l'extrémité. Observer fichier A qui est de 28 octets.

  

est une ligne dans le fichier \ n

alors j'ai un autre fichier qui est la même chose sans la nouvelle ligne. Observer le fichier B qui est de 26 octets.

  

est une ligne dans le fichier

Je veux ajouter le même fichier lui-même (fichier A à A, et le fichier B to B) et de comparer le nombre d'octets.

Cependant, lors de l'utilisation StreamReader.ReadLine() dans le dossier A, je reçois une valeur retournée, mais MSDN dit:

  

Une ligne est définie comme une séquence de caractères suivie par un saut de ligne ( « \ n »), un retour de chariot ( « \ r ») ou un retour de chariot suivi immédiatement par un saut de ligne ( « \ r \ n » ). La chaîne qui est renvoyée ne contient pas le retour du chariot de terminaison ou de saut de ligne. La valeur renvoyée est nulle si la fin du flux d'entrée est atteinte.

Cependant, il n'y a pas CRLF dans le fichier.

Comment puis-je ajouter en toute sécurité ces fichiers sans ajouter une saut de ligne supplémentaire à la fin? Par exemple, StreamWriter.WriteLine() mettra saut de ligne supplémentaire dans le dossier A quand je ne veux pas que ça. Quelle serait une approche idéale?

Était-ce utile?

La solution

StreamReader et StreamWriter (qui dérivent de TextReader et TextWriter) ne conviennent pas pour des situations nécessitant une forme exacte de données binaires. Ils sont des abstractions de haut niveau d'un fichier qui se compose d'octets, et non pas du texte ou des lignes. En fait, non seulement pourrait vous retrouver avec un nombre différent de nouvelles lignes, mais en fonction de l'environnement vous pourriez écrire une terminaison de ligne autre que le CR / LF prévu.

Vous devriez plutôt simplement copier d'un cours d'eau à un autre. Ceci est assez facile en fait.

var bytes = File.ReadAllBytes(pathIn);
var stream = File.Open(pathOut, FileMode.Append);
stream.Write(bytes, 0, bytes.Length);
stream.Close();

Si la taille du fichier est potentiellement important, vous devez ouvrir l'entrée et le fichier de sortie en même temps et utiliser un tampon de taille fixe pour copier un bloc à la fois.

using (var streamIn = File.Open(pathIn, FileMode.Read))
using (var streamOut = File.Open(pathOut, FileMode.Append)) {

    var bytes = new byte[BLOCK_SIZE];

    int count;
    while ((count=streamIn.Read(bytes, 0, bytes.Length)) > 0) {
        streamOut.Write(bytes, 0, count);
    }

}

Il convient également de noter que le code ci-dessus pourrait être remplacé par Stream.CopyTo qui est nouveau dans .NET 4.

Autres conseils

Vous n'obtiendrez null si vous appelez ReadLine à la fin du cours d'eau . Sinon, vous obtiendrez toutes les données jusqu'à soit un CRLF ou la fin du flux.

Si vous essayez de faire un double emploi octet par octet (et la comparaison), vous êtes mieux à lire soit des personnages (en utilisant StreamReader / StreamWriter que vous utilisez maintenant) ou octets (en utilisant simplement en utilisant la Stream classe) en utilisant les fonctions de Read et Write normales plutôt que ReadLine et WriteLine.

Vous pouvez aussi simplement lire le contenu du fichier en utilisant ReadToEnd puis écrire en appelant Write (non WriteLine), bien que ce n'est pas pratique si le fichier est grand.

string data;

using(StreamReader reader = new StreamReader(path))
{
    data = reader.ReadToEnd();
}

using(StreamWriter writer = new StreamWriter(path, true))
{
    writer.Write(data);
}

Vous pouvez utiliser StreamWriter.Write au lieu de WriteLine pour éviter le CRLF supplémentaire.

En ce qui concerne les ReadLine docs, je beleive le problème est une explication mal formulée. Vous ne voudriez certainement pas les derniers octets d'un fichier juste parce qu'il mis au rebut a pas de drapeau de fin de ligne formelle.

Eh bien cela dépend vraiment des raisons de votre mise en œuvre (Pourquoi êtes-vous en train de lire par ligne et l'écriture en arrière ligne par ligne?) Vous pouvez simplement utiliser StreamWriter.Write(string) et la sortie tout le texte que vous avez enregistré, le les méthodes de WriteLine() sont nommés en tant que tels parce qu'ils ajoutent une nouvelle ligne.

  

TextWriter.WriteLine méthode (String)   Ecrit une chaîne suivie d'une terminaison de ligne du flux de texte.

scroll top