使用LINQ比较两个文本文件?

5
我有一个文件夹里面有4个文本文件和一个pattern.txt用来比较这些文本文件。在pattern.txt中,我有:
insert
update
delete
drop

我需要将这个文本文件与那四个文本文件进行比较,如果这些模式匹配那些文本文件中的任何一行,我就必须将这些行写入另一个日志文件中...我使用linq读取了这些文件..我需要比较这些文件并在一个带有行号的文本文件中写入它们..以下是我的代码
var foldercontent = Directory.GetFiles(pathA)
                    .Select(filename => File.ReadAllText(filename))
                    .Aggregate(new StringBuilder(),
                    (sb, s) => sb.Append(s).Append(Environment.NewLine),
                    sb => sb.ToString());

 var pattern =  File.ReadAllLines(pathB).Aggregate(new StringBuilder(),
                    (sb, s) => sb.Append(s).Append(Environment.NewLine),
                    sb => sb.ToString());

using (var dest = File.AppendText(Path.Combine(_logFolderPath, "log.txt")))
            {
      //dest.WriteLine("LineNo : " + counter.ToString() + " : " + "" + line);
            }

编辑: 我已经使用C#比较了两个文本文件,但我需要用LINQ实现。
while ((line = file.ReadLine()) != null)
{
if (line.IndexOf(line2, StringComparison.CurrentCultureIgnoreCase) != -1)
{
dest.WriteLine("LineNo : " + counter.ToString() + " : " + " " + line.TrimStart());
}
counter++;
}
file.BaseStream.Seek(0, SeekOrigin.Begin);
counter = 1; 

你需要存储匹配行来自哪个文件吗? - Matt Ellen
@bala3569:是的,但在日志文件中,您需要存储匹配行来自哪个其他文件吗? - Matt Ellen
@Matt Ellen:我没明白你的意思。 - bala3569
在你的例子中,你存储了行号,但是你没有存储该行来自哪个文件(即文件名),因此这些信息似乎有点无用。 - Matt Ellen
2
你可能想要考虑使用grep而不是为此编写程序。https://dev59.com/HXVD5IYBdhLWcg3wGXpI - juharr
显示剩余4条评论
2个回答

4

可能有更简单的解决方案,但如果您确实想使用LINQ,则以下方法至少是有效的:

var foldercontent = Directory.GetFiles(pathA)
                    .Select(filename => new
                    {
                        Filename = filename,
                        Lines = File.ReadAllLines(filename)
                    })
                    .SelectMany(file => file.Lines.Select((line, idx) => new
                    {
                        LineNumber = idx + 1,
                        Text = line,
                        FileName = file.Filename
                    }));

var pattern = File.ReadAllLines(pathB);

var result = from fileLine in foldercontent
             where pattern.Any(p => fileLine.Text.IndexOf(p, StringComparison.CurrentCultureIgnoreCase) != -1)
             select fileLine;

foreach (var match in result)
{
    System.Diagnostics.Debug.WriteLine("File: {0} LineNo: {1}: Text: {2}", match.FileName, match.LineNumber, match.Text);
}

或者,如果你想要的话,你可以将它们组合成一个LINQ查询(但我认为那不太易读):
var result = from fileLine in (Directory.GetFiles(pathA)
                    .Select(filename => new
                    {
                        Filename = filename,
                        Lines = File.ReadAllLines(filename)
                    })
                    .SelectMany(file => file.Lines.Select((line, idx) => new
                    {
                        LineNumber = idx + 1,
                        Text = line,
                        FileName = file.Filename
                    })))
                where File.ReadAllLines(pathB).Any(p => fileLine.Text.IndexOf(p, StringComparison.CurrentCultureIgnoreCase) != -1)
                select fileLine;

如果我这样写,它会写n次,如果有n个匹配项。var result1 = string.Join(",", result.Select(x => x.ToString()).ToArray());foreach (var match in result) {dest.WriteLine(result1);} - bala3569
我不太明白你的意思。我的LINQ查询会给你所有文件中匹配的行,不会重复出现。 - Jan
是的,它确实给出了正确的结果,但对于n个匹配项,它会写入n次。 - bala3569
对我来说,就是将每个匹配的行只写一次。 - Jan

4

因为我是一个Linq爱好者,有时候会在不合适的情况下使用工具(我同意@juharr关于在这种情况下使用grep或类似工具的观点),所以这里为您提供一种可能的版本。

static IEnumerable<string> CreateMatchesLog(string patternFilePath, string pathToSearch)
{
    string logTemplate = "File {0}, Line: {1}, Pattern: {2}";
    DirectoryInfo di = new DirectoryInfo(pathToSearch);
    var patternlines = File.ReadAllLines(patternFilePath);
    var fileslines = di.EnumerateFiles().Select(fi => File.ReadAllLines(fi.FullName).Select((line, i) => new {fi.FullName, line, i}));

    return from filelines in fileslines
           from pattern in patternlines
           from fileline in filelines
           where fileline.line.Contains(pattern)
           select String.Format(logTemplate, fileline.FullName, fileline.i + 1, pattern);
}

那么您需要将此函数的输出写入文件中。
using (StreamWriter sw = new StreamWriter("log.txt", true))
{
    foreach (var log in CreateMatchesLog("pattern.txt", @"c:\test"))
    {
        sw.WriteLine(log);
    }
}

我已经在 StreamWriter 中设置了 true 的追加模式,因为我假设您不想每次运行程序时都丢失文件的内容。
看起来很低效(未经测试),但它使用了大量的linq和lambda表达式!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接