如何使用C#将字符插入文件

我有一个巨大的文件,我必须在特定位置插入某些字符。 在C#中最简单的方法是什么,而不是再次重写整个文件。

文件系统不支持在文件中间“插入”数据。 如果你真的需要一个可以按照有类似的方式写入的文件,我建议你考虑使用嵌入式数据库。

您可能想看一下SQLite或BerkeleyDB 。

然后,您可能正在使用文本文件或传统二进制文件。 在这种情况下,您唯一的选择是重写文件,至少从插入点到结束。

我会看看FileStream类在C#中做随机I / O.

您可能需要从将更改插入结尾的位置重写文件。 您可能最好总是写入文件的末尾,并使用sort和grep等工具以所需顺序获取数据。 我假设你在这里谈论的是一个文本文件,而不是二进制文件。

没有重写它们就无法在文件中插入字符。 使用C#,可以使用任何Stream类完成。 如果文件很大,我建议你在C#代码中使用GNU Core Utils。 他们是最快的。 我曾经使用核心工具(大小为4GB,8GB或更大等)来处理非常大的文本文件。 head,tail,split,csplit,cat,shuf,shred,uniq等命令在文本操作方面确实有很大帮助。

例如,如果您需要在2GB文件中放置一些字符,则可以使用split -b BYTECOUNT,将ouptut放入文件中,将新文本附加到其中,然后获取其余内容并添加到其中。 这应该比任何其他方式更快。

希望它有效。 试试看。

您可以使用随机访问来写入文件的特定位置,但是您无法以文本格式执行此操作,您必须直接使用字节。

您可以查看此项目: 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); } } 

根据项目的范围,您可能希望决定将每行文本与文件一起插入表数据结构中。 类似于数据库表 ,这种方式可以在任何给定时刻插入到特定位置,而不必每次都读入,修改和输出整个文本文件。 这是因为你提出的数据是“巨大的”。 您仍然可以重新创建该文件,但至少您可以通过这种方式创建可扩展的解决方案。

它可能是“可能的”,具体取决于文件系统如何存储文件以在中间快速插入(即添加额外的)字节。 如果它是远程可能的,那么一次只能完成一个完整的块,并且只能通过对文件系统本身进行低级修改或使用文件系统特定的接口。

文件系统通常不是为此操作而设计的。 如果你需要快速进行插入,你真的需要一个更通用的数据库。

根据您的应用程序,中间地带将您的插入物组合在一起,因此您只需重写一次而不是二十次。

如果您知道要将新数据写入的特定位置,请使用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); } 

您将始终必须重写插入点中的剩余字节。 如果此点为0,则您将重写整个文件。 如果它在最后一个字节之前是10个字节,那么你将重写最后10个字节。

在任何情况下都没有直接支持“插入文件”的function。 但是下面的代码可以准确地完成它。

 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字节(256KB)的缓冲区,完全没有帮助。 如果运行代码,则可以通过StopWatch结果看到用于插入的相同缓冲区“性能作业”。 我的电脑上的测试草案给出了以下结果:

创建时为13628.8 ms,插入时为3597.0971 ms。

请注意,插入的目标字节是10,这意味着几乎整个文件都被重写了。

为什么不将指针放在文件的末尾(字面意思,比文件当前大小高4个字节)然后,在文件末尾写入插入数据的长度,最后是要插入的数据本身。 例如,如果文件中间有一个字符串,并且要在字符串中间插入几个字符,则可以在字符串中的四个字符上写一个指向文件末尾的指针,然后写入最后四个字符以及您首先想要插入的字符。 这都是关于订购数据的。 当然,只有在您自己编写整个文件时才能执行此操作,我的意思是您没有使用其他编解码器。