Как вставить символы в файл с помощью С#

У меня есть огромный файл, где мне нужно вставить определенные символы в определенном месте. Самый простой способ сделать это на С#, не переписывая весь файл еще раз.

Ответы

Ответ 1

Файловые системы не поддерживают "вставку" данных в середину файла. Если у вас действительно есть необходимость в файле, который может быть написан в порядке сортировки, я предлагаю вам изучить встроенную базу данных.

Возможно, вам стоит взглянуть на SQLite или BerkeleyDB.

Затем вы можете работать с текстовым файлом или старым двоичным файлом. В этом случае ваш единственный вариант - переписать файл, по крайней мере, с точки вставки до конца.

Я бы посмотрел на класс FileStream, чтобы делать произвольный ввод-вывод в С#.

Ответ 2

Вам, вероятно, потребуется переписать файл с того места, где вы вставляете изменения в конец. Возможно, вам лучше всего писать до конца файла и использовать такие инструменты, как sort и grep, чтобы получить данные в нужном порядке. Я предполагаю, что вы говорите о текстовом файле здесь, а не о двоичном файле.

Ответ 3

Невозможно вставить символы в файл без их перезаписи. С С# это можно сделать с любыми классами Stream. Если файлы огромны, я бы рекомендовал использовать GNU Core Utils внутри кода С#. Они самые быстрые. Я использовал для обработки очень больших текстовых файлов с основными утилитами (размером 4 ГБ, 8 ГБ или более и т.д.). Команды, такие как head, tail, split, csplit, cat, shuf, shred, uniq, очень помогают в обработке текста.

Например, если вам нужно поместить некоторые символы в файл размером 2 ГБ, вы можете использовать split -b BYTECOUNT, поместить файл ouptut в файл, добавить к нему новый текст и получить остальную часть содержимого и добавить к нему Это. Вероятно, это должно быть быстрее, чем любой другой.

Надеюсь, что это сработает. Попробуйте.

Ответ 4

Вы можете использовать произвольный доступ для записи в определенные местоположения файла, но вы не сможете сделать это в текстовом формате, вам придется напрямую работать с байтами.

Ответ 5

Вы можете взглянуть на этот проект: Win Data Inspector

В принципе, код выглядит следующим образом:

// 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);
    }
}

Ответ 6

В зависимости от объема вашего проекта вы можете захотеть вставить каждую строку текста в файл в табличной структуре таблицы. Похоже на таблицу базы данных, таким образом, вы можете вставлять ее в определенное место в любой момент времени, и не должны каждый раз считывать, изменять и выводить весь текстовый файл. Это объясняется тем, что ваши данные "огромны", как вы выразились. Вы все равно воссоздаете файл, но по крайней мере вы создаете масштабируемое решение таким образом.

Ответ 7

Это может быть "возможно" в зависимости от того, как файловая система сохраняет файлы для быстрого добавления (то есть добавления дополнительных) байтов в середине. Если он удаленно, возможно, это будет возможно только для полного блока за один раз, и только путем изменения низкого уровня самой файловой системы или использования интерфейса конкретной файловой системы.

Файловые системы обычно не предназначены для этой операции. Если вам нужно быстро делать вставки, вам действительно нужна более общая база данных.

В зависимости от вашего приложения срединным основанием будет объединение ваших вставок вместе, так что вы только переписываете файл, а не двадцать.

Ответ 8

Если вы знаете конкретное местоположение, в которое хотите записать новые данные, используйте класс 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);
}

Ответ 9

Вам всегда придется переписывать оставшиеся байты из точки вставки. Если эта точка находится в 0, вы перепишете весь файл. Если он равен 10 байтам перед последним байтом, вы перепишете последние 10 байтов.

В любом случае нет функции прямой поддержки "вставить в файл". Но следующий код может сделать это точно.

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);

Чтобы получить лучшую производительность для IO файла, играйте с "волшебными двумя приведенными в действие номерами", как в приведенном выше коде. При создании файла используется буфер из 262144 байт (256 КБ), который вообще не помогает. Тот же буфер для вставки выполняет "задание производительности", как вы можете видеть по результатам StopWatch, если вы запускаете код. Проект теста на моем ПК дал следующие результаты:

13628,8 мс для создания и 3597.0971 мс для вставки.

Обратите внимание, что целевой байт для вставки равен 10, а это означает, что почти весь файл был перезаписан.

Ответ 10

Почему бы вам не поместить указатель в конец файла (буквально четыре байта выше текущего размера файла), а затем, в конце файла, напишите длину вставленных данных и, наконец, данные, которые вы хотите вставить себя. Например, если у вас есть строка в середине файла, и вы хотите вставить несколько символов в середине строки, вы можете записать указатель на конец файла над четырьмя символами в строке, а затем написать что четыре символа до конца вместе с персонажами, которые вы сначала хотели вставить. Все о заказе данных. Конечно, вы можете сделать это, только если вы пишете весь файл самостоятельно, я имею в виду, что вы не используете другие кодеки.