C#大文件读取和查询--内存映射
笔者最近需要快速查询日志文件,文件大小在4G以上。
需求如下:
1.读取4G左右大小的文件中的指定行,程序运行占用内存不超过500M。
2.希望查询1G以内容,能控制在20s左右.
刚开始觉得这个应该不难.研究一天之后,发现这个需要使用内存映射技术。
查阅了相关资料之后
发现还是有一定的复杂性.特别是需要对字符处理。
笔者自己写了一个Demo,希望实现
很遗憾,测试结果,查询1G左右的内容,花费时间在100s左右.
程序如下:

using System; using System.IO; using System.IO.MemoryMappedFiles; using System.Text; namespace ConsoleDemo { class Program { private const string TXT_FILE_PATH = @"E:\开源学习\超大文本文件读取\File\a.txt"; private const string SPLIT_VARCHAR = "囧"; private const char SPLIT_CHAR = '囧'; private static long FILE_SIZE = 0; static void Main(string[] args) { //long ttargetRowNum = 39999999; long ttargetRowNum = 10000000; DateTime beginTime = DateTime.Now; string line = CreateMemoryMapFile(ttargetRowNum); double totalSeconds = DateTime.Now.Subtract(beginTime).TotalSeconds; Console.WriteLine(line); Console.WriteLine(string.Format("查找第{0}行,共耗时:{1}s", ttargetRowNum, totalSeconds)); Console.ReadLine(); } /// <summary> /// 创建内存映射文件 /// </summary> private static string CreateMemoryMapFile(long ttargetRowNum) { string line = string.Empty; using (FileStream fs = new FileStream(TXT_FILE_PATH, FileMode.Open, FileAccess.ReadWrite)) { long targetRowNum = ttargetRowNum + 1;//目标行 long curRowNum = 1;//当前行 FILE_SIZE = fs.Length; using (MemoryMappedFile mmf = MemoryMappedFile.CreateFromFile(fs, "test", fs.Length, MemoryMappedFileAccess.ReadWrite, null, HandleInheritability.None, false)) { long offset = 0; //int limit = 250; int limit = 200; try { StringBuilder sbDefineRowLine = new StringBuilder(); do { long remaining = fs.Length - offset; using (MemoryMappedViewStream mmStream = mmf.CreateViewStream(offset, remaining > limit ? limit : remaining)) //using (MemoryMappedViewStream mmStream = mmf.CreateViewStream(offset, remaining)) { offset += limit; using (StreamReader sr = new StreamReader(mmStream)) { //string ss = sr.ReadToEnd().ToString().Replace("\n", "囧").Replace(Environment.NewLine, "囧"); string ss = sr.ReadToEnd().ToString().Replace("\n", SPLIT_VARCHAR).Replace(Environment.NewLine, SPLIT_VARCHAR); if (curRowNum <= targetRowNum) { if (curRowNum < targetRowNum) { string s = sbDefineRowLine.ToString(); int pos = s.LastIndexOf(SPLIT_CHAR); if (pos > 0) sbDefineRowLine.Remove(0, pos); } else { line = sbDefineRowLine.ToString(); return line; } if (ss.Contains(SPLIT_VARCHAR)) { curRowNum += GetNewLineNumsOfStr(ss); sbDefineRowLine.Append(ss); } else { sbDefineRowLine.Append(ss); } } //sbDefineRowLine.Append(ss); //line = sbDefineRowLine.ToString(); //if (ss.Contains(Environment.NewLine)) //{ // ++curRowNum; // //curRowNum++; // //curRowNum += GetNewLineNumsOfStr(ss); // //sbDefineRowLine.Append(ss); //} //if (curRowNum == targetRowNum) //{ // string s = ""; //} sr.Dispose(); } mmStream.Dispose(); } } while (offset < fs.Length); } catch (Exception e) { Console.WriteLine(e.Message); } return line; } } } private static long GetNewLineNumsOfStr(string s) { string[] _lst = s.Split(SPLIT_CHAR); return _lst.Length - 1; } } }
测试截图:
欢迎大家提供更好的解决思路.
参考资料:
https://msdn.microsoft.com/zh-cn/library/dd997372(v=vs.110).aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-1
http://blog.csdn.net/onejune2013/article/details/7577152
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· 展开说说关于C#中ORM框架的用法!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?