【问题标题】:Fastest way to find strings in a file在文件中查找字符串的最快方法
【发布时间】:2011-08-24 23:46:53
【问题描述】:

我有一个不超过 10 KB 的日志文件(文件大小最大可达 2 MB),我想知道文件中是否至少有一组此类字符串出现。这些字符串将位于不同的行上,例如,

动作:.......

输入:...........

结果:............

我至少需要知道文件中是否存在上述一组。我已经为测试做了大约 100 次(每次日志都不一样,所以我重新加载并阅读了日志),所以我正在寻找最快和最有可能做到这一点的方法。

我在论坛中查找了最快的方法,但我认为我的文件对于那些解决方案来说不会太大。

感谢观看。

【问题讨论】:

  • 10 KB 真的很小。我处理过的文件太大而无法放入内存 =/

标签: c# string


【解决方案1】:

我会逐行阅读并检查条件。一旦你看到一个组,你可以退出。这样您就不需要将整个文件读入内存。像这样:

    public bool ContainsGroup(string file)
    {
        using (var reader = new StreamReader(file))
        {
            var hasAction = false;
            var hasInput = false;
            var hasResult = false;
            while (!reader.EndOfStream)
            {
                var line = reader.ReadLine();
                if (!hasAction)
                {
                    if (line.StartsWith("ACTION:"))
                        hasAction = true;
                }
                else if (!hasInput)
                {
                    if (line.StartsWith("INPUT:"))
                        hasInput = true;
                }
                else if (!hasResult)
                {
                    if (line.StartsWith("RESULT:"))
                        hasResult = true;
                }

                if (hasAction && hasInput && hasResult)
                    return true;
            }
            return false;
        }
    }

此代码检查是否有一行以 ACTION 开头,然后一行以 INPUT 开头,然后一行以 RESULT 开头。如果这些顺序不重要,那么您可以省略 if () else if () 检查。如果该行不以字符串开头,请将StartsWith 替换为Contains。

【讨论】:

    【解决方案2】:

    这是一种可能的方法:

    StreamReader sr;
    string fileContents;
    
    string[] logFiles = Directory.GetFiles(@"C:\Logs");
    
    foreach (string file in logFiles)
    {
    
        using (StreamReader sr = new StreamReader(file))
        {
    
            fileContents = sr.ReadAllText();
    
            if (fileContents.Contains("ACTION:") || fileContents.Contains("INPUT:") || fileContents.Contains("RESULT:"))
            {
                 // Do what you need to here
            }
    
        }
    }
    

    您可能需要根据您的具体实现需求做一些变化 - 例如,如果单词跨越两行,行是否需要以单词开头,等等。

    已添加

    交替逐行检查:

    StreamReader sr;
    string[] lines;
    
    string[] logFiles = Directory.GetFiles(@"C:\Logs");
    
    foreach (string file in logFiles)
    {
    
        using (StreamReader sr = new StreamReader(file)
        {
    
            lines = sr.ReadAllLines();
    
            foreach (string line in lines)
            {        
                if (line.Contains("ACTION:") || line.Contains("INPUT:") || line.Contains("RESULT:"))
                {
                    // Do what you need to here
                }
            }
    
        }
    }
    

    【讨论】:

    • 逐行可能会出现错误。例如:“AC”“TION”可能在不同的行(如果编码人员没有对文本文件给予任何关注) String.Contains 是最好的函数。
    • @icaptan - 是的。这就是我先做 ReadAllText 示例的原因,以防关键字被分成两行或多行。
    • 如果匹配文本位于两行不同的行,那么它们将被换行符分隔,并且仍然不匹配。您必须先删除所有换行符。
    【解决方案3】:

    看看How to Read Text From a File。您可能还想看看String.Contains() 方法。

    基本上,您将遍历所有文件。对于每个文件,逐行读取并查看是否有任何行包含您的特殊“节”之一。

    【讨论】:

      【解决方案4】:

      就效率而言,您对文本文件没有太多选择。最简单的方法肯定是遍历每一行数据。当您在字符串中抓取一行时,将其拆分为空格。然后将这些单词与您的单词匹配,直到找到匹配项。然后做任何你需要的事情。

      我不知道如何在 c# 中做到这一点,但在 vb 中它会类似于...

      Dim yourString as string
      Dim words as string()
      Do While objReader.Peek() <> -1
         yourString = objReader.ReadLine()
         words = yourString.split(" ")
         For Each word in words()
            If Myword = word Then
               do stuff
            End If
         Next
      Loop
      

      希望有帮助

      【讨论】:

        【解决方案5】:

        此代码示例在大型文本文件中搜索字符串。单词包含在 HashSet 中。它将找到的行写入一个临时文件。

                if (File.Exists(@"temp.txt")) File.Delete(@"temp.txt");
        
                String line;
                String oldLine = "";
                using (var fs = File.OpenRead(largeFileName))
                using (var sr = new StreamReader(fs, Encoding.UTF8, true))
                {
                    HashSet<String> hash = new HashSet<String>();
                    hash.Add("house");
                    using (var sw = new StreamWriter(@"temp.txt"))
                    {
                        while ((line = sr.ReadLine()) != null)
                        {
                            foreach (String str in hash)
                            {
                                if (oldLine.Contains(str))
                                {
                                    sw.WriteLine(oldLine); 
                                    // write the next line as well (optional)
                                    sw.WriteLine(line + "\r\n");                                    
                                }
                            }
                            oldLine = line;
                        }
                    }
                }
        

        【讨论】:

          猜你喜欢
          • 2010-11-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-02-09
          • 2018-07-26
          • 2016-10-05
          • 2015-01-14
          • 2012-09-09
          相关资源
          最近更新 更多