c# - 读取大型文本文件(超过 400 万行)并在 .NET 中解析每一行

标签 c# wpf parsing text-files

我每个月的每一天都有一个日志文件。这些文件是纯文本,每行都有一些信息,如下面的代码片段:

1?2017-06-01T00:00:00^148^3
2?myVar1^3454.33
2?myVar2^35
2?myVar3^0
1?2017-06-01T00:00:03^148^3
...

为了处理和显示这些数据,我正在开发一个 WPF 应用程序来读取这些 txt 文件、解析行并将这些数据保存在 SQLite 数据库中。然后,我允许用户进行一些基本的数学运算,例如子集的 AVG。

由于这些文件太大(每个文件超过 300mb 和 400 万行),我正在努力解决 ProcessLine 方法中的内存使用问题(据我所知,读取部分还可以现在)。该方法永远不会完成,应用程序会自行进入中断模式。

我的代码:

private bool ParseContent(string filePath)
    {
        if (string.IsNullOrEmpty(FilePath) || !File.Exists(FilePath))
            return false;

        string logEntryDateTimeTemp = string.Empty;

        string [] AllLines = new string[5000000]; //only allocate memory here
        AllLines = File.ReadAllLines(filePath);
        Parallel.For(0, AllLines.Length, x =>
        {
            ProcessLine(AllLines[x], ref logEntryDateTimeTemp);
        });

        return true;
    }

    void ProcessLine(string line, ref string logEntryDateTimeTemp)
    {
        if (string.IsNullOrEmpty(line))
            return;

        var logFields = line.Split(_delimiterChars);

        switch (logFields[0])
        {
            case "1":
                logEntryDateTimeTemp = logFields[1];
                break;
            case "2":
                LogEntries.Add(new LogEntry
                {
                    Id = ItemsCount + 1,
                    CurrentDateTime = logEntryDateTimeTemp,
                    TagAddress = logFields[1],
                    TagValue = Convert.ToDecimal(logFields[2])
                });

                ItemsCount++;
                break;
            default:
                break;
        }
    }

有更好的方法吗?

OBS:我还测试了另外两种读取文件的方法,它们是:

        #region StreamReader
        //using (StreamReader sr = File.OpenText(filePath))
        //{
        //    string line = String.Empty;
        //    while ((line = sr.ReadLine()) != null)
        //    {
        //        if (string.IsNullOrEmpty(line))
        //            break;

        //        var logFields = line.Split(_delimiterChars);

        //        switch (logFields[0])
        //        {
        //            case "1":
        //                logEntryDateTimeTemp = logFields[1];
        //                break;
        //            case "2":
        //                LogEntries.Add(new LogEntry
        //                {
        //                    Id = ItemsCount + 1,
        //                    CurrentDateTime = logEntryDateTimeTemp,
        //                    TagAddress = logFields[1],
        //                    TagValue = Convert.ToDecimal(logFields[2])
        //                });

        //                ItemsCount++;
        //                break;
        //            default:
        //                break;
        //        }
        //    }
        //}
        #endregion

        #region ReadLines
        //var lines = File.ReadLines(filePath, Encoding.UTF8);

        //foreach (var line in lines)
        //{
        //    if (string.IsNullOrEmpty(line))
        //        break;      

        //    var logFields = line.Split(_delimiterChars);

        //    switch (logFields[0])
        //    {
        //        case "1":
        //            logEntryDateTimeTemp = logFields[1];
        //            break;
        //        case "2":
        //            LogEntries.Add(new LogEntry
        //            {
        //                Id = ItemsCount + 1,
        //                CurrentDateTime = logEntryDateTimeTemp,
        //                TagAddress = logFields[1],
        //                TagValue = Convert.ToDecimal(logFields[2])                          
        //            });

        //            ItemsCount++;
        //            break;
        //        default:
        //            break;
        //    }             
        //}
        #endregion

OBS2:我使用的是Visual Studio 2017,当应用程序运行在debug模式时,应用程序突然进入break模式,Output窗口的信息如下:

The CLR has been unable to transition from COM context 0xb545a8 to COM context 0xb544f0 for 60 seconds. The thread that owns the destination context/apartment is most likely either doing a non pumping wait or processing a very long running operation without pumping Windows messages. This situation generally has a negative performance impact and may even lead to the application becoming non responsive or memory usage accumulating continually over time. To avoid this problem, all single threaded apartment (STA) threads should use pumping wait primitives (such as CoWaitForMultipleHandles) and routinely pump messages during long running operations.

最佳答案

尝试使用 StreamReader 而不是一次将整个文件加载到内存中:

using (System.IO.StreamReader sr = new System.IO.StreamReader(filePath))
{
    string line;
    while ((line = sr.ReadLine()) != null)
    {
        //..
    }
}

关于c# - 读取大型文本文件(超过 400 万行)并在 .NET 中解析每一行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46407477/

相关文章:

c# - 业务对象,在线对象和计算器上 - 这是最好的

c# - 从函数返回多个列表

c# - 与 UI 中的部分异步

c# - 捕捉中止()

xml - Perl XML::简单的 XMLout 函数

python - 如何在 Pharo Smalltalk 中加载 Python 解析器?

c# - 如何在c#中设置定时器在特定时间执行

c# - 如何在 WPF 的 ListBox 中找到元素的总和

c# - Kong Solutions 拖放以对列表进行排序,从列表中删除项目

c++ - 用纯C++解析简单的html