2009-05-13 10 views
7

J'ai un fichier texte en cours d'écriture dans le cadre d'un très grand extrait de données. La première ligne du fichier texte est le nombre de "comptes" extraits. En raison de la nature de cet extrait, ce nombre n'est pas connu jusqu'à la fin du processus, mais le fichier peut être volumineux (quelques centaines de megs).Quelle est la meilleure façon de remplacer du texte dans un fichier en utilisant C#/.NET?

Quelle est la meilleure façon en C#/.NET d'ouvrir un fichier (dans ce cas un simple fichier texte), et de remplacer les données qui sont dans la première «ligne» de texte?

REMARQUE IMPORTANTE: - Je n'ai pas besoin de remplacer une "quantité fixe d'octets" - ce serait facile. Le problème ici est que les données qui doivent être insérées en haut du fichier sont variables.

NOTE IMPORTANTE 2: - Quelques personnes ont demandé ou mentionné simplement garder les données en mémoire, puis les remplacer ... mais c'est complètement hors de question. La raison pour laquelle ce processus est en cours de mise à jour est due au fait que parfois, il se bloque lors du chargement de quelques concerts en mémoire.

+0

"##### \ r \ n (ce qui signifie pas de remplissage)" Êtes-vous sûr de ne pas avoir de Zéro? –

Répondre

4

Si vous le pouvez, vous devez insérer un espace réservé que vous écrasez à la fin avec le nombre réel et les espaces.

Si ce n'est pas une option, écrivez d'abord vos données dans un fichier cache. Lorsque vous connaissez le numéro réel, créez le fichier de sortie et ajoutez les données à partir du cache.

+0

Oui, la seule façon d'éviter d'écrire les données deux fois. Si le texte est basé, il ne devrait pas y avoir de problème, il suffit de réserver une quantité décente d'espaces en premier. –

+0

Voici ce que je voudrais * faire * (réserver de l'espace) - le seul problème est que le format de fichier dans lequel j'écris nécessite exactement ##### \ r \ n (ce qui signifie pas de remplissage). - Bonne réponse cependant. –

+1

@Timothy: autorise-t-il les zéros en tête? –

1

Si le fichier extrait n'est que de quelques centaines de mégaoctets, vous pouvez facilement conserver tout le texte en mémoire jusqu'à ce que l'extraction soit terminée. Ensuite, vous pouvez écrire votre fichier de sortie en tant que dernière opération, en commençant par le nombre d'enregistrements.

+3

"seulement quelques centaines de mégaoctets" ??? Es-tu sérieux ? – Cerebrus

+1

J'ai seulement 2 concerts sur ma machine - la plupart des autres dans notre bureau ont entre 4 et 8. Qu'est-ce que 200MB. Peut-être que 10% de la mémoire totale ... –

+0

Et que se passe-t-il dans un an quand le fichier est "seulement quelques gigaoctets", vous allez tout garder en mémoire alors aussi? –

2

Je ne ai pas besoin de remplacer un « fixe quantité d'octets »

Etes-vous sûr? Si vous écrivez un grand nombre à la première ligne du fichier (UInt32.MaxValue ou UInt64.MaxValue), alors lorsque vous trouvez le nombre réel correct, vous pouvez remplacer ce nombre d'octets avec le nombre correct, mais à gauche avec zéros , donc c'est toujours un nombre entier valide. par exemple.

Replace 999999 - your "large number placeholder" 
With  000100 - the actual number of accounts 
+0

Solution de contournement astucieuse! - Cependant, la spécification de fichier avec laquelle je travaille n'acceptera pas cela ... très bonne pensée cependant :) –

+0

Est-ce que ça vous dérange de me demander pourquoi? –

+0

C'est une spécification de fichier, elle n'a pas répondu à ma question: P –

3

Le meilleur est très subjectif. Pour n'importe quel fichier smallish, vous pouvez facilement ouvrir le fichier entier en mémoire et remplacer ce que vous voulez en utilisant une chaîne de caractères, puis réécrire le fichier.

Même pour les fichiers volumineux, il ne serait pas si difficile à charger en mémoire. Dans les jours de multi-concerts de la mémoire, je considérerais des centaines de mégaoctets pour toujours être facilement fait en mémoire.

Avez-vous testé cette approche naïve? Avez-vous vu un vrai problème avec cela? S'il s'agit d'un fichier très volumineux (taille de gigaoctets), je considérerais d'abord écrire toutes les données dans un fichier temporaire, puis j'écrirais le bon fichier en commençant par la ligne d'en-tête, puis en ajoutant le reste de la Les données. Étant donné que ce n'est que du texte, je devrais probablement juste sortir vers DOS:

TYPE temp.txt >> outfile.txt 
2

Cela me semble si je comprends bien la question?

Quelle est la meilleure façon en C#/.NET d'ouvrir un fichier (dans ce cas un simple fichier texte), et de remplacer les données qui sont dans la première «ligne» de texte? Comment placer en haut du fichier un jeton {UserCount} lors de sa première création.

Ensuite, utilisez TextReader pour lire le fichier ligne par ligne. S'il s'agit de la première ligne, recherchez {UserCount} et remplacez-la par votre valeur. Écrivez chaque ligne que vous lisez en utilisant TextWriter

Exemple:

int lineNumber = 1; 
    int userCount = 1234; 
    string line = null; 

    using(TextReader tr = File.OpenText("OriginalFile")) 
    using(TextWriter tw = File.CreateText("ResultFile")) 
    { 

     while((line = tr.ReadLine()) != null) 
     { 
      if(lineNumber == 1) 
      { 
       line = line.Replace("{UserCount}", userCount.ToString()); 
      } 

      tw.WriteLine(line); 
      lineNumber++; 
     } 

    } 
+0

C'est essentiellement ce que je devais faire, mais mon but était de ne pas avoir à créer 2 fichiers. –

+0

J'ai encore une solution que j'ai vu mais je n'ai pas encore vérifié ou essayé. Fondamentalement, ce que vous faites est d'utiliser quelque chose comme stream Streamriter pour écrire votre premier fichier et le garder ouvert.Ecrivez aussi comme j'ai suggéré l'espace réservé et gardez le début et la fin du jeton. Alors maintenant que vous êtes à la fin du fichier et vous avez le UserCount et juste besoin de revenir en arrière et remplacer le jeton avec votre valeur. Pour ce faire, vous utilisez un BitStream auquel je crois que vous pouvez accéder en accédant à StreamWriter.BaseStream et pouvez écrire des octets à un emplacement spécifique dans votre flux. Va essayer et tester et poster. –

1

Ok, plus tôt, je suggère une approche qui serait mieux si le traitement des dossiers existants.

Toutefois, dans votre situation, vous souhaitez créer le fichier et pendant le processus de création, revenez en haut et écrivez le nombre d'utilisateurs. Cela fera juste cela.

Voici une façon de le faire qui vous évite d'avoir à écrire le fichier temporaire.

private void WriteUsers() 
    { 
     string userCountString = null; 
     ASCIIEncoding enc = new ASCIIEncoding(); 
     byte[] userCountBytes = null; 
     int userCounter = 0; 

     using(StreamWriter sw = File.CreateText("myfile.txt")) 
     { 
      // Write a blank line and return 
      // Note this line will later contain our user count. 
      sw.WriteLine(); 

      // Write out the records and keep track of the count 
      for(int i = 1; i < 100; i++) 
      { 
       sw.WriteLine("User" + i); 
       userCounter++; 
      } 

      // Get the base stream and set the position to 0 
      sw.BaseStream.Position = 0; 

      userCountString = "User Count: " + userCounter; 

      userCountBytes = enc.GetBytes(userCountString); 

      sw.BaseStream.Write(userCountBytes, 0, userCountBytes.Length); 
     } 

    } 
+0

En fait, c'est la seule réponse à la demande d'édition d'un fichier existant ... Merci! – ephraim