如何在目录中的所有文件中搜索字符串?我没有内存异常

时间:2015-12-08 15:07:20

标签: c# .net winforms

我在form1构造函数中调用了两个方法:

DirSearch(@"D:\C-Sharp");
SearchInFiles();

DirSearch方法:

public static void DirSearch(string sDir)
        {
            try
            {
                foreach (string d in Directory.GetDirectories(sDir))
                {
                    foreach (string f in Directory.GetFiles(d))
                    {
                        files.Add(f);
                    }
                    DirSearch(d);
                }
            }
            catch (System.Exception excpt)
            {
                Console.WriteLine(excpt.Message);
            }
        }

SearchInfiles方法:

private void SearchInFiles()
        {
            for (int i = 0; i < files.Count; i++)
            {
                string[] lines = File.ReadAllLines(files[i]);
                for (int x = 0; x < lines.Length; x++)
                {
                    if (lines[x].Contains("setting"))
                    {
                        filesContent.Add(lines[x]);
                    }
                }
            }
        }

我在线上没有内存异常:

string[] lines = File.ReadAllLines(files[i]);

如果可能的话,如何更快地进行搜索?如何避免此异常?

也许我需要以某种方式使它不会在dll文件和其他不可编辑的文件中搜索例如* .cs和* .txt这样的文件我该怎么办?

5 个答案:

答案 0 :(得分:6)

  

如果可能的话,如何更快地进行搜索?如何避免此异常?

该行:

string[] lines = File.ReadAllLines(files[i]);

&#34;它在锡上的含义&#34; - 它从整个文件(在内存中)读取每一行。对于非常大的文件,这将占用大量内存。

避免这种情况的方法是一次将所有行加载到内存中,而是逐行将文件流入内存。

using(var streamReader sr = new StreamReader(files[i]))
{
    string line;
    while((line = sr.ReadLine()) != null)
    {
          if (line.Contains("setting"))
          {
              filesContent.Add(line);
          }
    }
}

请注意,如果使用.NET 4或更高版本,使用File.ReadLines

会变得更加简单
foreach(var line in File.ReadLines(files[i]))
{
  ....
}
  

也许我需要以某种方式使它不会在dll文件和其他不可编辑的文件中搜索例如* .cs和* .txt这样的文件我该怎么办?

您通过向GetFiles overload

提供searchPattern来完成该部分
foreach (string f in Directory.GetFiles(d,"*.txt"))
....

似乎没有办法提供多个文件扩展名,但您可以简单地将2个列表链接在一起

// all txt or cs files
var files = Directory.GetFiles(d,"*.txt").Concat(Directory.GetFiles(d,"*.cs"));
foreach(var f in files)
    ....

答案 1 :(得分:3)

A)不是先获取所有文件然后再处理所有文件,而是在找到文件后立即处理。

因此,不要使用DirSearch中的files.Add,而是使用您找到的参数调用SearchInFile。

B)不要读取文件中的所有行(它们文本文件,不是吗?),但是使用File.ReadLines来处理该行读,所以你可以忘记它,如果它不匹配。

foreach(string line in File.ReadLines(theFile))
{
   // test the "line"
}

答案 2 :(得分:3)

您不仅要一次读入内存中的所有行,而且还要查看目录中存在的每个文件。

这可能是个问题。例如,如果其中一个文件是某个大于2演出的数据文件怎么办?那你就会有记忆问题。

当您在文件列表中添加文件时,还要检查以确保文件属于您想要的类型。

例如。

foreach (string f in Directory.GetFiles(d))
{
    if(f.Contains(".txt") || f.Contains(".cs"))
         files.Add(f);
}

答案 3 :(得分:2)

为什么要将所有名字列入清单?它必须在开始处理第一个列表之前读取整个列表。

为什么在处理前阅读所有行?

public List<string> FindLines(string DirName)
{
    List<string> findLines = new List<string>();
    DirectoryInfo di = new DirectoryInfo(DirName);
    if(di != null && di.Exists) 
    {
        foreach(FileInfo fi in di.EnumerateFiles("*", SearchOption.AllDirectories))
        {
            //Debug.WriteLine(fi.Extension);
            //Debug.WriteLine(fi.FullName);
            if (   string.Compare(fi.Extension, ".cs",   true) == 0 
                || string.Compare(fi.Extension, ".txt",  true) == 0
                || string.Compare(fi.Extension, ".text", true) == 0)
            {
                //findLines.Add(fi.FullName);
                using (StreamReader sr = fi.OpenText())
                {
                    string s = "";
                    while ((s = sr.ReadLine()) != null)
                    {
                        if (s.Contains("setting"))
                            findLines.Add(s);
                    }
                }
            }
        }
    }
    return findLines;
}

答案 4 :(得分:1)

您的问题是一次性将所有行读入内存。

您应该使用流来读取文件,或者一次读取一行。