Como inserir caracteres em um arquivo usando c #

Eu tenho um arquivo enorme, onde eu tenho que inserir certos caracteres em um local específico. Qual é a maneira mais fácil de fazer isso em C # sem rewrite todo o arquivo novamente.

Sistemas de arquivos não suportam “inserir” dados no meio de um arquivo. Se você realmente precisa de um arquivo que possa ser escrito de uma forma ordenada, sugiro que você procure usar um database embutido.

Você pode querer dar uma olhada no SQLite ou no BerkeleyDB .

Então, novamente, você pode estar trabalhando com um arquivo de texto ou um arquivo binário legado. Nesse caso, sua única opção é rewrite o arquivo, pelo menos do ponto de inserção até o final.

Eu olharia para a class FileStream para fazer E / S aleatória em C #.

Você provavelmente precisará rewrite o arquivo do ponto em que inserir as alterações no final. É melhor escrever sempre para o final do arquivo e usar ferramentas como sort e grep para obter os dados na ordem desejada. Estou supondo que você está falando sobre um arquivo de texto aqui, não um arquivo binário.

Não há como inserir caracteres em um arquivo sem reescrevê-los. Com C #, isso pode ser feito com qualquer class Stream. Se os arquivos são enormes, eu recomendo que você use o GNU Core Utils dentro do código C #. Eles são os mais rápidos. Eu costumava lidar com arquivos de texto muito grandes com os principais utilitários (de tamanhos de 4GB, 8GB ou mais, etc). Comandos como head, tail, split, csplit, cat, shuf, shred, uniq realmente ajudam muito na manipulação de texto.

Por exemplo, se você precisa colocar alguns caracteres em um arquivo de 2GB, você pode usar o split -b BYTECOUNT, colocar o ouptut em um arquivo, acrescentar o novo texto a ele e obter o restante do conteúdo e adicioná-lo a ele. Isso deveria ser supostamente mais rápido que qualquer outro caminho.

Espero que funcione. De uma chance.

Você pode usar o access random para gravar em locais específicos de um arquivo, mas você não poderá fazê-lo no formato de texto, você terá que trabalhar com bytes diretamente.

Você pode dar uma olhada neste projeto: Win Data Inspector

Basicamente, o código é o seguinte:

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

Dependendo do escopo do seu projeto, você pode decidir inserir cada linha de texto com seu arquivo em uma estrutura de dados de tabela. Como se fosse uma tabela de database , dessa forma você pode inserir em um local específico a qualquer momento e não ter que ler, modificar e gerar o arquivo de texto inteiro a cada vez. Isto é dado o fato de que seus dados são “enormes” como você diz. Você ainda recriaria o arquivo, mas pelo menos cria uma solução escalonável dessa maneira.

Pode ser “possível” dependendo de como o sistema de arquivos armazena arquivos para inserir rapidamente (ou seja, adicionar mais) bytes no meio. Se for remotamente possível, pode ser viável fazer um bloco inteiro de cada vez, e apenas fazendo uma modificação de baixo nível do próprio sistema de arquivos ou usando uma interface específica do sistema de arquivos.

Os filesystems geralmente não são projetados para esta operação. Se você precisa fazer inserções rapidamente, você realmente precisa de um database mais geral.

Dependendo da sua aplicação, um meio termo seria agrupar suas inserções, para que você faça apenas uma reescrita do arquivo em vez de vinte.

Se você souber o local específico no qual deseja gravar os novos dados, use a class 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); } 

Você sempre terá que rewrite os bytes restantes do ponto de inserção. Se este ponto estiver em 0, você irá rewrite o arquivo inteiro. Se for 10 bytes antes do último byte, você irá rewrite os últimos 10 bytes.

Em qualquer caso, não há function para suportar diretamente “inserir no arquivo”. Mas o código a seguir pode fazer isso com precisão.

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

Para obter melhor desempenho para o arquivo IO, jogue com "magic two powered numbers" como no código acima. A criação do arquivo usa um buffer de 262144 bytes (256KB) que não ajuda em nada. O mesmo buffer para a inserção faz o "trabalho de desempenho", como você pode ver pelos resultados do StopWatch, se você executar o código. Um teste de rascunho no meu PC deu os seguintes resultados:

13628,8 ms para criação e 3597.0971 ms para inserção.

Observe que o byte de destino para inserção é 10, significando que quase todo o arquivo foi reescrito.

Por que você não coloca um ponteiro no final do arquivo (literalmente, quatro bytes acima do tamanho atual do arquivo) e, no final do arquivo, grava o tamanho dos dados inseridos e, finalmente, os dados que deseja inserir? em si. Por exemplo, se você tiver uma cadeia no meio do arquivo e quiser inserir alguns caracteres no meio da string, poderá escrever um ponteiro para o final do arquivo sobre quatro caracteres da string e depois escrever que quatro personagens para o final, juntamente com os personagens que você queria inserir em primeiro lugar. É tudo sobre como encomendar dados. Claro, você pode fazer isso somente se você estiver escrevendo o arquivo inteiro sozinho, quero dizer que você não está usando outros codecs.