3

我有一个包含多个子文件夹的文件夹。每个子文件夹中都有许多 .dot 和 .txt 文件。

C# .NET 中是否有一个简单的解决方案可以遍历每个文件并检查该文件的内容是否有关键短语或关键字?

Document Name        Keyword1         Keyword2         Keyword3        ...
  test.dot              Y               N                Y

总结一下:

  1. 选择一个文件夹
  2. 输入要搜索的关键字列表
  3. 然后程序将搜索每个文件并在最后输出类似上面的内容,我不担心创建数据表来显示数据网格,因为我可以这样做。我只需要执行类似于 Notepad++ 的 find in files 选项的 find in files 功能

提前致谢

4

4 回答 4

5

您想要的是递归迭代目录中的文件(也许它是子目录)。

因此,您的步骤是使用 .NET 中的 Getfiles() 循环指定目录中的每个文件。然后如果你遇到一个目录循环它。

使用此代码示例可以轻松完成此操作:

  public static IEnumerable<string>  GetFiles(string path)
  {
        foreach (string s in Directory.GetFiles(path, "*.extension_here"))
        {
              yield return s;
        }


        foreach (string s in Directory.GetDirectories(path))
        {
              foreach (string s1 in GetFiles(s))
              {
                    yield return s1;
              }
        }
  }

有关在 .NET 目录中遍历文件的更深入了解位于此处:

http://blogs.msdn.com/b/brada/archive/2004/03/04/84069.aspx

然后你使用 String 中的 IndexOf 方法来检查你的关键字是否在文件中(我不鼓励使用 ReadAllText,如果你的文件是 5 MB 大,你的字符串也是如此。逐行将减少内存消耗)

于 2012-10-02T13:22:12.413 回答
3

您可以使用Directory.EnumerateFiles搜索模式和递归提示(SearchOption.AllDirectories)。其余的使用 LINQ 很容易:

var keyWords = new []{"Y","N","Y"};
var allDotFiles = Directory.EnumerateFiles(folder, "*.dot", SearchOption.AllDirectories);
var allTxtFiles = Directory.EnumerateFiles(folder, "*.txt", SearchOption.AllDirectories);
var allFiles = allDotFiles.Concat(allTxtFiles);
var allMatches = from fn in allFiles
                 from line in File.ReadLines(fn)
                 from kw in keyWords
                 where line.Contains(kw)
                 select new { 
                     File = fn,
                     Line = line,
                     Keyword = kw
                 };

foreach (var matchInfo in allMatches)
    Console.WriteLine("File => {0} Line => {1} Keyword => {2}"
        , matchInfo.File, matchInfo.Line, matchInfo.Keyword);

请注意,您需要添加using System.Linq;

有没有办法只获取行号?

如果你只想要行号,你可以使用这个查询:

var matches = allFiles.Select(fn => new
{
    File = fn,
    LineIndices = String.Join(",",
                File.ReadLines(fn)
                .Select((l,i) => new {Line=l, Index =i})
                .Where(x => keyWords.Any(w => x.Line.Contains(w)))
                .Select(x => x.Index)),
})
.Where(x => x.LineIndices.Any());

foreach (var match in matches)
    Console.WriteLine("File => {0} Linenumber => {1}"
        , match.File, match.LineIndices);

这有点困难,因为 LINQ 的查询语法不允许传递索引。

于 2012-10-02T13:33:15.270 回答
2

第一步:找到所有文件。正如其他人所提到的,使用 System.IO.Directory.GetFiles() + System.IO.File.ReadAllText() 很容易完成。

第二步:在文件中查找关键字。如果您有一个关键字并且可以使用 IndexOf() 方法完成,这很简单,但是多次迭代文件(特别是如果它很大)是一种浪费。

要在文本中快速找到多个关键字,我认为您应该使用 Aho-Corasick 自动机(算法)。请参阅 CodeProject 上的 C# 实现:http: //www.codeproject.com/Articles/12383/Aho-Corasick-string-matching-in-C

于 2012-10-02T13:28:52.160 回答
0

这是使用 Tim 的原始答案获取行号的方法:

var keyWords = new[] { "Keyword1", "Keyword2", "Keyword3" };
var allDotFiles = Directory.EnumerateFiles(folder, "*.dot", SearchOption.AllDirectories);
var allTxtFiles = Directory.EnumerateFiles(folder, "*.txt", SearchOption.AllDirectories);
var allFiles = allDotFiles.Concat(allTxtFiles);
var allMatches = from fn in allFiles
                 from line in File.ReadLines(fn).Select((item, index) => new { LineNumber = index, Line = item})
                 from kw in keyWords
                 where line.Line.Contains(kw)
                 select new
                 {
                     File = fn,
                     Line = line.Line,
                     LineNumber = line.LineNumber,
                     Keyword = kw
                 };

foreach (var matchInfo in allMatches)
    Console.WriteLine("File => {0} Line => {1} Keyword => {2} Line Number => {3}"
        , matchInfo.File, matchInfo.Line, matchInfo.Keyword, matchInfo.LineNumber);
于 2012-10-02T14:09:38.680 回答