用 C# 更新一个非常大的文件的最佳方法是什么
What's best way to update a very large file with c#
我问的不是只读取一个大文件或 reading/writing 一个 xml 文件,我知道有 Xml 相关的 类 来处理它。让我更具体地描述我正在尝试做的事情:
我有一个非常大的文件,大约有 10TB,我无法立即加载到内存中。意思是,我不能这样做:
var lines = File.ReadAllLines("LargeFile.txt");
var t = 1 << 40;
for(var i= t; i< 2 * t; i++)
{
lines[i] = someWork(); //
}
File.WriteAllLines("LargeFile.txt", lines);
我想读取和更新 1 到 2TB 范围内的行。
执行此操作的最佳方法是什么? .Net 类 或第 3 方库的示例会有所帮助。
我也对其他语言如何处理这个问题感兴趣。
我通过使用 position 尝试了 David 的建议。
但是,我觉得它不起作用。
1. FileStream的大小好像是固定的,我可以按字节修改,但是会逐字节覆盖。我的新数据大小比原始数据行大 large/less。我将无法正确更新。
2. 我没有找到将第 num 行转换为第 num 个位置的 O(1) 方法。我仍然需要 O(n) 才能找到位置。
下面是我的尝试
public static void ReadWrite()
{
var fn = "LargeFile.txt";
File.WriteAllLines(fn, Enumerable.Range(1, 20).Select(x => x.ToString()));
var targetLine = 11; // zero based
long pos = -1;
using (var fs = new FileStream(fn, FileMode.Open, FileAccess.Read, FileShare.Read))
{
while (fs.Position != fs.Length)
{
if (targetLine == 0)
{
pos = fs.Position +1; // move pos to begin of next line;
}
// still take average O(N) time to scan whole file to find the position.
// I'm not sure if there is better way. to redirect to the pos of x line by O(1) time.
if (fs.ReadByte() == '\n')
{
targetLine--;
}
}
}
using (var fs = new FileStream(fn, FileMode.Open, FileAccess.ReadWrite))
{
var data = Encoding.UTF8.GetBytes("999");
fs.Position = pos;
// if the modify data has differnt size compare to the current one
// it will overwrite next lines of data
fs.Write(data, 0, data.Length);
}
}
您不必通读前 1TB 即可修改文件的中间部分。 FileStream 支持随机访问。 EG
string fn = @"c:\temp\huge.dat";
using (var fs = new FileStream(fn, FileMode.Open, FileAccess.Read, FileShare.Read))
{
fs.Position = (1024L * 1024L * 1024L);
//. . .
}
重新定位文件流后,您可以在当前位置读写,或打开 StreamReader 从文件中读取文本。当然,您必须确保移动到文件编码中字符开始的字节偏移量。
我问的不是只读取一个大文件或 reading/writing 一个 xml 文件,我知道有 Xml 相关的 类 来处理它。让我更具体地描述我正在尝试做的事情:
我有一个非常大的文件,大约有 10TB,我无法立即加载到内存中。意思是,我不能这样做:
var lines = File.ReadAllLines("LargeFile.txt");
var t = 1 << 40;
for(var i= t; i< 2 * t; i++)
{
lines[i] = someWork(); //
}
File.WriteAllLines("LargeFile.txt", lines);
我想读取和更新 1 到 2TB 范围内的行。
执行此操作的最佳方法是什么? .Net 类 或第 3 方库的示例会有所帮助。 我也对其他语言如何处理这个问题感兴趣。
我通过使用 position 尝试了 David 的建议。 但是,我觉得它不起作用。 1. FileStream的大小好像是固定的,我可以按字节修改,但是会逐字节覆盖。我的新数据大小比原始数据行大 large/less。我将无法正确更新。 2. 我没有找到将第 num 行转换为第 num 个位置的 O(1) 方法。我仍然需要 O(n) 才能找到位置。
下面是我的尝试
public static void ReadWrite()
{
var fn = "LargeFile.txt";
File.WriteAllLines(fn, Enumerable.Range(1, 20).Select(x => x.ToString()));
var targetLine = 11; // zero based
long pos = -1;
using (var fs = new FileStream(fn, FileMode.Open, FileAccess.Read, FileShare.Read))
{
while (fs.Position != fs.Length)
{
if (targetLine == 0)
{
pos = fs.Position +1; // move pos to begin of next line;
}
// still take average O(N) time to scan whole file to find the position.
// I'm not sure if there is better way. to redirect to the pos of x line by O(1) time.
if (fs.ReadByte() == '\n')
{
targetLine--;
}
}
}
using (var fs = new FileStream(fn, FileMode.Open, FileAccess.ReadWrite))
{
var data = Encoding.UTF8.GetBytes("999");
fs.Position = pos;
// if the modify data has differnt size compare to the current one
// it will overwrite next lines of data
fs.Write(data, 0, data.Length);
}
}
您不必通读前 1TB 即可修改文件的中间部分。 FileStream 支持随机访问。 EG
string fn = @"c:\temp\huge.dat";
using (var fs = new FileStream(fn, FileMode.Open, FileAccess.Read, FileShare.Read))
{
fs.Position = (1024L * 1024L * 1024L);
//. . .
}
重新定位文件流后,您可以在当前位置读写,或打开 StreamReader 从文件中读取文本。当然,您必须确保移动到文件编码中字符开始的字节偏移量。