我有一个很大的文件,需要在特定位置插入某些字符。在不重新编写整个文件的情况下,在C#中最简单的方法是什么。
我有一个很大的文件,需要在特定位置插入某些字符。在不重新编写整个文件的情况下,在C#中最简单的方法是什么。
文件系统不支持在文件中间“插入”数据。如果你确实需要一个可以按排序方式写入的文件,建议考虑使用嵌入式数据库。
你可能需要查看SQLite或BerkeleyDB。
然而,如果你正在处理文本文件或旧的二进制文件,则唯一的选择是从插入点到文件结尾重写文件。
我建议你查看FileStream类来进行C#中的随机I/O操作。
您可能需要从插入更改的位置重写文件到结尾。最好总是将信息写入文件末尾,并使用诸如sort和grep等工具按所需顺序获取数据。我假设您在这里谈论的是文本文件,而不是二进制文件。
// 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);
}
}
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个字节。
无论如何,没有直接支持“插入到文件”的功能。但是以下代码可以准确地完成此操作。
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);
根据文件系统如何存储文件,可能可以“快速”插入(即添加额外的)字节。如果远程可能,每次仅通过对文件系统进行低级修改或使用特定于文件系统的接口以一个完整块为单位执行此操作可能是可行的。
文件系统通常不设计此操作。如果您需要快速进行插入,则确实需要更通用的数据库。
根据您的应用程序,中间地带将是将插入分组在一起,因此您只需重写文件而不是二十个。