在另一个文本文件中搜索一个文本文件的行,速度更快

时间:2012-02-28 23:03:26

标签: c# text-files indexof

是否有更快的方法来搜索一个文本文件的每一行以便在另一个文本文件中出现,而不是在两个文件中一行一行地进行搜索?

我有两个文本文件 - 一个有~2500行(我们称之为TxtA),另一个有~86000行(TxtB)。我想在TxtA中为每一行搜索TxtB,并在找到的每个匹配项中返回TxtB中的行。

我目前将此设置设置为:对于TxtA中的每一行,逐行搜索TxtB以进行匹配。然而,这需要很长时间才能完成。似乎需要1-3个小时才能找到所有比赛。

这是我的代码......

private static void getGUIDAndType()
    {

        try
        {

            Console.WriteLine("Begin.");
            System.Threading.Thread.Sleep(4000);

            String dbFilePath = @"C:\WindowsApps\CRM\crm_interface\data\";
            StreamReader dbsr = new StreamReader(dbFilePath + "newdbcontents.txt");
            List<string> dblines = new List<string>();

            String newDataPath = @"C:\WindowsApps\CRM\crm_interface\data\";
            StreamReader nsr = new StreamReader(newDataPath + "HolidayList1.txt");
            List<string> new1 = new List<string>();

            string dbline;
            string newline;

            List<string> results = new List<string>();

            while ((newline = nsr.ReadLine()) != null)
            {
                //Reset
                dbsr.BaseStream.Position = 0;
                dbsr.DiscardBufferedData();

                while ((dbline = dbsr.ReadLine()) != null)
                {
                    newline = newline.Trim();
                    if (dbline.IndexOf(newline) != -1)
                    {//if found... get all info for now
                        Console.WriteLine("FOUND: " + newline);
                        System.Threading.Thread.Sleep(1000);
                        new1.Add(newline);
                        break;
                    }
                    else
                    {//the first line of db does not contain this line... 
                        //go to next dbline. 
                        Console.WriteLine("Lines do not match - continuing");
                        continue;
                    }
                }
                Console.WriteLine("Going to next new Line");
                System.Threading.Thread.Sleep(1000);
                //continue;
            }

            nsr.Close();

            Console.WriteLine("Writing to dbc3.txt");
            System.IO.File.WriteAllLines(@"C:\WindowsApps\CRM\crm_interface\data\dbc3.txt", results.ToArray());
            Console.WriteLine("Finished. Press ENTER to continue.");

            Console.WriteLine("End.");
            Console.ReadLine();
        }
        catch (Exception ex)
        {
            Console.WriteLine("Error:  " + ex);
            Console.ReadLine();
        }
    }

如果有更快的方法,请告诉我。最好是需要5-10分钟的东西...我听说过索引,但对txt文件没有太多了解。我测试了正则表达式,它并不比indexof快。包含将无法工作,因为这些行永远不会完全相同。

感谢。

3 个答案:

答案 0 :(得分:3)

编辑:请注意,我认为至少将一个文件读入内存是合理的。您可能希望交换下面的查询以避免将“大”文件加载到内存中,但即使是每行1K(例如)1K的86,000行也将少于2G的内存 - 这对于做一些重要的事情来说相对较少。

您每次都在阅读“内部”文件。没有必要这样做。将两个文件加载到内存中并从那里开始。哎呀,对于完全匹配,你可以轻松地在LINQ中完成整个事情:

var query = from line1 in File.ReadLines("newDataPath + "HolidayList1.txt")
            join line2 in File.ReadLines(dbFilePath + "newdbcontents.txt")
            on line1 equals line2
            select line1;

var commonLines = query.ToList();

但对于非连接,它仍然很简单;只需先完全读取一个文件(显式),然后再传输另一个文件:

// Eagerly read the "inner" file
var lines2 = File.ReadAllLines(dbFilePath + "newdbcontents.txt");
var query = from line1 in File.ReadLines("newDataPath + "HolidayList1.txt")
            from line2 in lines2
            where line2.Contains(line1)
            select line1;

var commonLines = query.ToList();

这里没有什么聪明 - 它只是一种编写代码来读取一个文件中所有行的简单方法,然后迭代另一个文件中的行,并针对第一个文件中的所有行进行每行检查。但即使没有任何聪明,我强烈怀疑它会对你表现得足够好。专注于简单,消除不必要的IO,并在尝试做任何更好的事情之前看看它是否足够好。

请注意,在原始代码中,您应该对using变量使用StreamReader语句,以确保它们得到妥善处理。使用上面的代码很容易,甚至不需要它......

答案 1 :(得分:2)

可能有更快的方法,但这个LINQ应用程序应该超过3个小时,并且可以更好地阅读和维护:

var f1Lines    = File.ReadAllLines(f1Path);
var f2LineInf1 = File.ReadLines(f2Path)
                .Where( line => f1Lines.Contains(line))
                .Select(line => line).ToList();

编辑:对于file2中的400000行和file1中的17000行,测试并需要不到1秒的时间。我可以使用File.ReadLines作为大文件,它不会立即加载到内存中。对于较小的文件,我需要使用File.ReadAllLines,因为Contains需要文件1的完整行列表。

如果要将结果记录在第三个文件中:

File.WriteAllLines(logPath, f2LineInf1);

答案 2 :(得分:0)

快速而肮脏,因为我必须去...如果你能在记忆中做到这一点,试着使用这个片段:

    //string[] searchIn = File.ReadAllLines("File1.txt");
    //string[] searchFor = File.ReadAllLines("File2.txt");

    string[] searchIn = new string[] {"A","AB","ABC","ABCD", null, "", "    "};
    string[] searchFor = new string[] {"A","BC","BCD", null, "", "   "};

    matchDictionary;

    foreach(string item in file2Content)
    {
        string[] matchingItems = Array.FindAll(searchIn, x => (x == item) || (!string.IsNullOrEmpty(x) && !string.IsNullOrEmpty(item) ? (x.Contains(item) || item.Contains(x)) : false));
    }