2009-05-19 10 views

Répondre

8

Nouvelle réponse

(Voir l'explication pour junking réponse originale ci-dessous.)

static void CopyFiles(string dest, params string[] sources) 
{ 
    using (TextWriter writer = File.CreateText(dest)) 
    { 
     // Somewhat arbitrary limit, but it won't go on the large object heap 
     char[] buffer = new char[16 * 1024]; 
     foreach (string source in sources) 
     { 
      using (TextReader reader = File.OpenText(source)) 
      { 
       int charsRead; 
       while ((charsRead = reader.Read(buffer, 0, buffer.Length)) > 0) 
       { 
        writer.Write(buffer, 0, charsRead); 
       } 
      } 
     } 
    } 
} 

Cette nouvelle réponse est tout à fait comme l'approche de Martin, à l'exception:

  • Il se lit dans un tampon plus petit; 16K va être acceptable dans presque toutes les situations, et ne finira pas sur le tas d'objets volumineux (qui ne soit pas compactée)
  • Il lit texte données au lieu de données binaires, pour deux raisons:
    • le code peut facilement être modifié pour convertir d'un encodage à un autre
    • Si chaque fichier d'entrée contient une marque d'ordre d'octet, qui sera ignoré par le lecteur, au lieu de se retrouver avec des marques octet ordre dispersé à travers le fichier de sortie aux limites du fichier d'entrée

réponse originale

Martin Stettner a souligné un problème dans la réponse ci-dessous - si le premier fichier se termine sans un saut de ligne, il sera toujours créer une nouvelle ligne dans le fichier de sortie. En outre, il traduira les nouvelles lignes dans le "\ r \ n" même si elles étaient auparavant juste "\ r" ou "\ n". Enfin, il risque inutilement d'utiliser de grandes quantités de données pour les longues lignes.

Quelque chose comme:

static void CopyFiles(string dest, params string[] sources) 
{ 
    using (TextWriter writer = File.CreateText(dest)) 
    { 
     foreach (string source in sources) 
     { 
      using (TextReader reader = File.OpenText(source)) 
      { 
       string line; 
       while ((line = reader.ReadLine()) != null) 
       { 
        writer.WriteLine(line); 
       } 
      } 
     } 
    } 
} 

Notez que ce lit ligne par ligne pour éviter de lire trop en mémoire à la fois. Vous pouvez le rendre plus simple si vous êtes heureux de lire complètement chaque fichier dans la mémoire (encore un à la fois):

static void CopyFiles(string dest, params string[] sources) 
{ 
    using (TextWriter writer = File.CreateText(dest)) 
    { 
     foreach (string source in sources) 
     { 
      string text = File.ReadAllText(source); 
      writer.Write(text); 
     } 
    } 
} 
+0

Skeet me bat à nouveau! – jrcs3

+0

Il a juste jeté un coup d'oeil à son clavier et il a commencé à taper la réponse avec la vitesse de la lumière.:) –

+0

Skeet doit être un android. Il ne peut pas être humain. +1 – ichiban

2

Modifier:

Comme Jon Skeet a souligné, les fichiers texte devrait normalement être traité différemment des fichiers binaires .

Je laisse juste cette réponse car il pourrait être plus performant si vous avez vraiment de gros fichiers et ne sont pas concernded en codant des problèmes (tels que les différents fichiers d'entrée ayant différents codages ou plusieurs Byte Order Marks dans le fichier de sortie):

public void CopyFiles(string destPath, string[] sourcePaths) { 
    byte[] buffer = new byte[10 * 1024 * 1024]; // Just allocate a buffer as big as you can afford 
    using (var destStream= = new FileStream(destPath, FileMode.Create) { 
    foreach (var sourcePath in sourcePaths) { 
     int read; 
     using (var sourceStream = FileStream.Create(sourcePath, FileMode.Open) { 
     while ((read = sourceStream.Read(buffer, 0, 10*1024*1024)) != 0) 
      destStream.Write(buffer, 0, read); 
     } 
    } 
    } 
} 
+0

Cela fait toute la différence - réfléchissez à ce qui se passe si tous les fichiers texte commencent par une marque d'ordre d'octet. Vous voudriez que votre sortie n'en ait qu'une seule. –

+0

Merci de l'avoir signalé. Fait intéressant, MSDN ne mentionne pas que File.OpenText() (ou même StreamReader) consomme les marques d'ordre des octets. Les nomenclatures ne sont même pas mentionnées dans toute la documentation de StreamReader-constructors. De plus MSDN indique que File.OpenText fonctionne avec les fichiers UTF-8 alors qu'il utilise vraiment le même mécanisme de détection que StreamReader (fonctionnant ainsi parfaitement avec tout autre encodage supporté). – MartinStettner

+0

Je serais en désaccord avec "tout autre encodage supporté" - c'est "tout encodage auto-détecté" qui est une chose très différente IMO :) –

Questions connexes