You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#读取大文本文件仅第二次触发OutOfMemoryException问题求助

解决大文件提取最后一个文本块的内存溢出问题

我来帮你搞定这个问题~你的核心需求是从不断更新的大文本文件里,提取最后一次出现的、以"My Statistics:"开头的24行文本块,但原代码因为一次性加载整个大文件,导致第二次读取时触发了OutOfMemoryException,这很常见,咱们一步步优化:

原代码的问题根源

File.ReadAllText(@"c:\file.txt")会把整个文件的内容一次性加载到内存里,如果文件非常大,第一次读取就会占用大量内存;30秒后文件更新变大,第二次读取时,之前的大字符串可能还没被垃圾回收,内存直接不够用,就抛出了内存溢出异常。

优化方案:只读取必要的内容

我们不需要加载整个文件,只需要从文件末尾往前找最后一个"My Statistics:",然后读取它后面的24行就行。下面给你两种实现方式:

方式1:倒序遍历行(简单易读)

用File.ReadLines逐行读取文件(不会一次性加载全部内容),然后倒序查找目标头,再提取对应行:

private static string GetLastStatisticsBlock(string filePath)
{
    // 倒序遍历所有行,找到第一个出现的"My Statistics:"(也就是文件里的最后一个)
    var reversedLines = File.ReadLines(filePath).Reverse().ToList();
    int targetHeaderIndex = reversedLines.FindIndex(line => line.StartsWith("My Statistics:"));
    
    if (targetHeaderIndex == -1)
        return string.Empty; // 没找到目标块,返回空
    
    // 从目标头开始取24行,再反转回正序
    var targetLines = reversedLines.Skip(targetHeaderIndex).Take(24).Reverse();
    return string.Join(Environment.NewLine, targetLines);
}

// 主循环调用
while (true)
{
    try
    {
        string lastBlock = GetLastStatisticsBlock(@"c:\file.txt");
        File.WriteAllText(@"last.txt", lastBlock);
    }
    catch (Exception ex)
    {
        // 加个错误处理,避免循环直接崩溃
        Console.WriteLine($"执行出错:{ex.Message}");
    }
    Thread.Sleep(30000);
}

方式2:从文件末尾反向读取(超高效,适合超大文件)

如果文件特别大(比如几个GB),上面的方式还是会遍历所有行,我们可以直接定位到文件末尾,往前逐字节读取,找到换行符后拼接行,直到找到目标头并收集够24行:

private static string GetLastStatisticsBlockEfficient(string filePath)
{
    const string TargetHeader = "My Statistics:";
    List<string> collectedLines = new List<string>();
    
    using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
    using (var reader = new StreamReader(fileStream))
    {
        fileStream.Seek(0, SeekOrigin.End);
        long currentPosition = fileStream.Position;
        
        while (currentPosition > 0)
        {
            fileStream.Seek(--currentPosition, SeekOrigin.Begin);
            char currentChar = (char)fileStream.ReadByte();
            
            // 遇到换行符就读取当前行
            if (currentChar == '\n' || currentChar == '\r')
            {
                string line = reader.ReadLine();
                if (!string.IsNullOrWhiteSpace(line))
                {
                    collectedLines.Insert(0, line);
                    
                    // 找到目标头且已经收集够24行,直接停止
                    if (line.StartsWith(TargetHeader) && collectedLines.Count >= 24)
                        break;
                }
            }
        }
    }
    
    // 提取从目标头开始的24行
    int headerIndex = collectedLines.FindIndex(line => line.StartsWith(TargetHeader));
    return headerIndex == -1 
        ? string.Empty 
        : string.Join(Environment.NewLine, collectedLines.Skip(headerIndex).Take(24));
}

额外建议

  • 加上错误处理:比如文件被占用、读取失败时,不要让循环直接崩溃,而是记录错误后继续执行
  • 如果文件更新频率固定,可以考虑监控文件变化(用FileSystemWatcher),而不是固定30秒轮询,更高效

内容的提问来源于stack exchange,提问作者Erofh Tor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:51:13