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++; } } } }