如何使用跨越多行的c#解析文本文件中的消息?

时间:2013-06-20 20:46:38

标签: c#

鉴于此日志文件,如何使用\n读取包含多个新行(StreamReader)的行? ReadLine方法按字面返回每一行,但消息可能跨越一行。

Larger Image for the down votes

这是我到目前为止所拥有的

using (var sr = new StreamReader(filePath))
using (var store = new DocumentStore {ConnectionStringName = "RavenDB"}.Initialize())
{
    IndexCreation.CreateIndexes(typeof(Logs_Search).Assembly, store);

    using (var bulkInsert = store.BulkInsert())
    {
        const char columnDelimeter = '|';
        const string quote = @"~";
        string line;

        while ((line = sr.ReadLine()) != null)
        {
            batch++;
            List<string> columns = null;
            try
            {
                columns = line.Split(columnDelimeter)
                                .Select(item => item.Replace(quote, string.Empty))
                                .ToList();

                if (columns.Count != 5)
                {
                    batch--;
                    Log.Error(string.Join(",", columns.ToArray()));
                    continue;
                }

                bulkInsert.Store(LogParser.Log.FromStringList(columns));

                /* Give some feedback */
                if (batch % 100000 == 0)
                {
                    Log.Debug("batch: {0}", batch);
                }

                /* Use sparingly */
                if (ThrottleEnabled && batch % ThrottleBatchSize == 0)
                {
                    Thread.Sleep(ThrottleThreadWait);
                }
            }
            catch (FormatException)
            {
                if (columns != null) Log.Error(string.Join(",", columns.ToArray()));
            }
            catch (Exception exception)
            {
                Log.Error(exception);
            }
        }
    }                   
}

和模型

public class Log
{
    public string Component { get; set; }
    public string DateTime { get; set; }
    public string Logger { get; set; }
    public string Level { get; set; }
    public string ThreadId { get; set; }
    public string Message { get; set; }
    public string Terms { get; set; }

    public static Log FromStringList(List<string> row)
    {
        Log log = new Log();

        /*log.Component = row[0] == string.Empty ? null : row[0];*/
        log.DateTime = row[0] == string.Empty ? null : row[0].ToLower();
        log.Logger = row[1] == string.Empty ? null : row[1].ToLower();
        log.Level = row[2] == string.Empty ? null : row[2].ToLower();
        log.ThreadId = row[3] == string.Empty ? null : row[3].ToLower();
        log.Message = row[4] == string.Empty ? null : row[4].ToLower();

        return log;
    }
}

3 个答案:

答案 0 :(得分:3)

我会使用Regex.Split并在每个错误开头的任何与日期模式匹配的内容(例如2013-06-19)上打破文件。

答案 1 :(得分:2)

如果您可以将整个文件读入内存(例如File.ReadAllText),那么您可以将其视为单个字符串并使用正则表达式在日期上进行拆分,或者其他一些。

占用更少内存的更通用的解决方案是逐行读取文件。将行附加到缓冲区,直到获得以所需值开头的下一行(在您的情况下,为日期/时间戳)。然后处理那个缓冲区。例如:

StringBuilder buffer = new StringBuilder();
foreach (var line in File.ReadLines(logfileName))
{
    if (line.StartsWith("2013-06-19"))
    {
        if (sb.Length > 0)
        {
            ProcessMessage(sb.ToString());
            sb.Clear();
        }
        sb.AppendLine(line);
    }
}
// be sure to process the last message
if (sb.Length > 0)
{
    ProcessMessage(sb.ToString());
}

答案 2 :(得分:0)

很难看到你的档案。但我会说逐行阅读并附加到某个变量。 检查消息的结束。当你看到它时,做你想对该变量中的消息做什么(插入到DB等...)然后继续阅读下一条消息。

Pseudo code

read the line
variable a = a +  new line
if end of message
    insert into DB
    reset the variable
continue reading the message.....