Question

J'ai un énorme fichier dans lequel je dois insérer certains caractères à un emplacement spécifique. Quel est le moyen le plus simple de faire cela en C # sans réécrire à nouveau le fichier entier.

Était-ce utile?

La solution

Les systèmes de fichiers ne prennent pas en charge l’insertion de " insertion de " données au milieu d'un fichier. Si vous avez réellement besoin d’un fichier sur lequel vous pouvez écrire de manière triée, je vous suggère d’envisager l’utilisation d’une base de données intégrée.

Vous voudrez peut-être consulter SQLite ou BerkeleyDB .

Là encore, vous travaillez peut-être avec un fichier texte ou un fichier binaire hérité. Dans ce cas, votre seule option est de réécrire le fichier, du moins du point d’insertion jusqu’à la fin.

Je regarderais le FileStream une classe pour effectuer des E / S aléatoires en C #.

Autres conseils

Vous devrez probablement réécrire le fichier à partir du point où vous avez inséré les modifications. Vous feriez mieux d’écrire toujours à la fin du fichier et d’utiliser des outils tels que sort et grep pour extraire les données dans l’ordre souhaité. Je suppose que vous parlez d’un fichier texte ici, pas d’un fichier binaire.

Il n’existe aucun moyen d’insérer des caractères dans un fichier sans les réécrire. Avec C #, cela peut être fait avec toutes les classes de flux. Si les fichiers sont volumineux, je vous recommanderais d'utiliser GNU Core Utils dans le code C #. Ils sont les plus rapides. Je manipulais de très gros fichiers texte avec les principaux utilitaires (de 4 Go, 8 Go ou plus, etc.). Des commandes telles que tête, queue, split, csplit, chat, shuf, shred, uniq aident beaucoup à la manipulation de texte.

Par exemple, si vous devez insérer des caractères dans un fichier de 2 Go, vous pouvez utiliser split -b BYTECOUNT, insérer l’extrait dans un fichier, y ajouter le nouveau texte et obtenir le reste du contenu, puis ajouter des éléments. il. Cela devrait soi-disant être plus rapide que tout autre moyen.

J'espère que ça marche. Essayez-le.

Vous pouvez utiliser un accès aléatoire pour écrire dans des emplacements spécifiques d'un fichier, mais vous ne pourrez pas le faire au format texte, vous devrez travailler directement avec des octets.

Si vous connaissez l'emplacement spécifique dans lequel vous souhaitez écrire les nouvelles données, utilisez la classe BinaryWriter:

using (BinaryWriter bw = new BinaryWriter (File.Open (strFile, FileMode.Open)))
{
    string strNewData = "this is some new data";
    byte[] byteNewData = new byte[strNewData.Length];

    // copy contents of string to byte array
    for (var i = 0; i < strNewData.Length; i++)
    {
        byteNewData[i] = Convert.ToByte (strNewData[i]);
    }

    // write new data to file
    bw.Seek (15, SeekOrigin.Begin);  // seek to position 15
    bw.Write (byteNewData, 0, byteNewData.Length);
}

Vous pouvez jeter un oeil à ce projet: Inspecteur de données Win

En gros, le code est le suivant:

// this.Stream is the stream in which you insert data

{

long position = this.Stream.Position;

long length = this.Stream.Length;

MemoryStream ms = new MemoryStream();

this.Stream.Position = 0;

DIUtils.CopyStream(this.Stream, ms, position, progressCallback);

ms.Write(data, 0, data.Length);

this.Stream.Position = position;

DIUtils.CopyStream(this.Stream, ms, this.Stream.Length - position, progressCallback);

this.Stream = ms;

}

#region Delegates

public delegate void ProgressCallback(long position, long total);

#endregion

DIUtils.cs

public static void CopyStream(Stream input, Stream output, long length, DataInspector.ProgressCallback callback)
{
    long totalsize = input.Length;
    long byteswritten = 0;
    const int size = 32768;
    byte[] buffer = new byte[size];
    int read;
    int readlen = length < size ? (int)length : size;
    while (length > 0 && (read = input.Read(buffer, 0, readlen)) > 0)
    {
        output.Write(buffer, 0, read);
        byteswritten += read;
        length -= read;
        readlen = length < size ? (int)length : size;
        if (callback != null)
            callback(byteswritten, totalsize);
    }
}

En fonction de l'étendue de votre projet, vous pouvez décider d'insérer chaque ligne de texte avec votre fichier dans une structure de données de table . Un peu comme une table de base de données , vous pouvez ainsi insérer à tout moment dans un emplacement spécifique sans avoir à lire, modifier et exporter le fichier texte entier à chaque fois. Ceci est dû au fait que vos données sont "énormes". comme vous le dites. Vous pouvez toujours recréer le fichier, mais au moins vous créez une solution évolutive de cette manière.

Cela peut être "possible" en fonction de la manière dont le système de fichiers stocke les fichiers pour insérer rapidement (c'est-à-dire ajouter des octets supplémentaires) au milieu. Si cela est possible à distance, il ne sera peut-être faisable que bloc par bloc, et seulement en effectuant une modification de bas niveau du système de fichiers lui-même ou en utilisant une interface spécifique au système de fichiers.

Les systèmes de fichiers ne sont généralement pas conçus pour cette opération. Si vous devez effectuer rapidement des insertions, vous avez vraiment besoin d’une base de données plus générale.

En fonction de votre application, un moyen terme consiste à regrouper vos insertions. Vous ne devez donc réécrire qu'une seule fois le fichier au lieu de vingt.

Vous devrez toujours réécrire les octets restants à partir du point d’insertion. Si ce point est à 0, vous réécrivez tout le fichier. Si le dernier octet se trouve 10 octets, vous devez réécrire les 10 derniers octets.

Dans tous les cas, aucune fonction ne prend en charge directement "Insérer dans un fichier". Mais le code suivant peut le faire avec précision.

var sw = new Stopwatch();
var ab = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ";

// create
var fs = new FileStream(@"d:\test.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite, 262144, FileOptions.None);
sw.Restart();
fs.Seek(0, SeekOrigin.Begin);
for (var i = 0; i < 40000000; i++) fs.Write(ASCIIEncoding.ASCII.GetBytes(ab), 0, ab.Length);
sw.Stop();
Console.WriteLine("{0} ms", sw.Elapsed.TotalMilliseconds);
fs.Dispose();

// insert
fs = new FileStream(@"d:\test.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite, 262144, FileOptions.None);
sw.Restart();
byte[] b = new byte[262144];
long target = 10, offset = fs.Length - b.Length;
while (offset != 0)
{
    if (offset < 0)
    {
        offset = b.Length - target;
        b = new byte[offset];
    }
    fs.Position = offset; fs.Read(b, 0, b.Length);
    fs.Position = offset + target; fs.Write(b, 0, b.Length);
    offset -= b.Length;
}
fs.Position = target; fs.Write(ASCIIEncoding.ASCII.GetBytes(ab), 0, ab.Length);
sw.Stop();
Console.WriteLine("{0} ms", sw.Elapsed.TotalMilliseconds);

Pour obtenir de meilleures performances d'IO de fichier, jouez avec "Deux chiffres magiques magiques". comme dans le code ci-dessus. La création du fichier utilise un tampon de 262144 octets (256 Ko) qui n’aide en rien. Le même tampon pour l'insertion effectue le "travail de performance". comme vous pouvez le voir avec les résultats de StopWatch si vous exécutez le code. Un projet de test sur mon PC a donné les résultats suivants:

13628,8 ms pour la création et 3597,0971 ms pour l'insertion.

Notez que l'octet cible à insérer est 10, ce qui signifie que presque tout le fichier a été réécrit.

Pourquoi ne placez-vous pas un pointeur sur la fin du fichier (littéralement, quatre octets au-dessus de la taille actuelle du fichier), puis écrivez à la fin du fichier la longueur des données insérées, et enfin les vouloir se insérer. Par exemple, si vous avez une chaîne au milieu du fichier et que vous souhaitez insérer quelques caractères au milieu de la chaîne, vous pouvez écrire un pointeur vers la fin du fichier sur quatre caractères environ de la chaîne, puis écrire que quatre caractères à la fin ainsi que les caractères que vous vouliez d’abord insérer. Tout est une question de commande de données. Bien sûr, vous ne pouvez le faire que si vous écrivez vous-même l’ensemble du fichier, c’est-à-dire que vous n’utilisez pas d’autres codecs.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top