Как вставить символы в файл с помощью C # - PullRequest
13 голосов
/ 19 сентября 2008

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

Ответы [ 10 ]

10 голосов
/ 19 сентября 2008

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

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

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

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

3 голосов
/ 19 сентября 2008

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

2 голосов
/ 19 сентября 2008

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

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

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

1 голос
/ 20 апреля 2016

Вы можете взглянуть на этот проект: 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);
    }
}
1 голос
/ 22 января 2009

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

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

0 голосов
/ 16 мая 2017

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

0 голосов
/ 09 декабря 2011

Вам всегда придется переписывать оставшиеся байты из точки вставки. Если эта точка равна 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);

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

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

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

0 голосов
/ 19 сентября 2008

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

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

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

0 голосов
/ 19 сентября 2008

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

...