C# 2GBを超えたテキストファイルを読む
よくわかんないのだけど、通常のSystem.IO.File.ReadLines(path)では、なぜか2GBを超えたでかいテキストファイルが読めなかった。エラーも特に出さないのが酷い。ファイルサイズをみたら気づいた。たぶんバグ。そのうち修正されるのだろう。内部がINT32で管理されているとかそういうオチなんだろう。
しかし、普通のファイルストリームを使えば、2GB越えは普通に読めるみたいなので、ちょこっと改造して読めるようにした。
戦略は、「読む位置をずらしながら読む」です。
ずーとストリームとストリームリーダーが分かれている理由がよくわかんなかったのだけど、
さまざま種類のストリームを扱えるというのは当然として、こういう使い方をするためでもあるのですかねぇ。
あと、前提として改行が\r\nに固定なので、使うときは気を付けてください。
おまけとして、ファイル分割用のつけました。
public class BigText
{
public static int MaxLine = 1000000;
public static IEnumerable<string> ReadLines(string file, Encoding enc)
{
if (MaxLine == 0) MaxLine = 100000;
long postion = 0;
int count = 0;
bool flag = true;
while (flag)
{
using (System.IO.FileStream fs = new System.IO.FileStream(file, System.IO.FileMode.Open))
{
fs.Seek(postion, System.IO.SeekOrigin.Begin);
using (var stream = new System.IO.StreamReader(fs, enc))
{
while (flag && count < MaxLine)
{
string line = stream.ReadLine();
if (line == null) flag = false;
else
{
count++;
postion += enc.GetByteCount(line + "\r\n");
yield return line;
}
}
}
count = 0;
}
}
}
public static void SplitTextFile(string file,Encoding enc,string folder,int maxLine)
{
long postion = 0;
int count = 0;
int part = 0;
bool flag = true;
while (flag)
{
using (System.IO.FileStream fs = new System.IO.FileStream(file, System.IO.FileMode.Open))
{
fs.Seek(postion, System.IO.SeekOrigin.Begin);
string wFile = folder + "/" + Path.GetFileNameWithoutExtension(file) + "_" + part.ToString() + Path.GetExtension(file);
using (var stream = new System.IO.StreamReader(fs, enc))
using(var write = new StreamWriter(wFile,false,enc))
{
while (flag && count < maxLine)
{
string line = stream.ReadLine();
if (line == null) flag = false;
else
{
count++;
postion += enc.GetByteCount(line + "\r\n");
write.WriteLine(line);
}
}
}
count = 0;
part++;
}
}
}
}