5

I have 4 text files in one folder and a pattern.txt to compare these text files..In pattern.txt i have

insert
update
delete
drop

I need to compare this text file with those four text files and if these patterns matches any line in that text files i have to write those lines in another log file...i had read those files using linq..i need to compare those files and write in a text file with line number..here is my code

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);
            }

EDIT I have already used c# to compare two text files but i need this in 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; 
bala3569
  • 10,832
  • 28
  • 102
  • 146

2 Answers2

4

There might be a simpler solution, but this is at least working if you really want to use 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);
}

Or if you want, you can combine that into one LINQ query (but thats not very readable i think):

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;
Jan
  • 15,802
  • 5
  • 35
  • 59
  • If i give it like this means it is writing n times if there are n matches var result1 = string.Join(",", result.Select(x => x.ToString()).ToArray());foreach (var match in result) {dest.WriteLine(result1);} – bala3569 Dec 21 '10 at 14:49
  • I do not exactly understand what you mean. My LINQ query gives you all matching lines of all files. You won't get lines doubled. – Jan Dec 21 '10 at 14:56
  • ya it gives correctly but is writing n number of times for n number of matches – bala3569 Dec 21 '10 at 15:00
  • For me its writing every matching line one time – Jan Dec 21 '10 at 15:04
4

Since I'm a linq enthusiast, and will sometimes use a tool when it's inappropriate (I agree with @juharr about using grep or something similar for this situation) here is a possible version for you.

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);
}

Then you'd write the output of this function to a file.

using (StreamWriter sw = new StreamWriter("log.txt", true))
{
    foreach (var log in CreateMatchesLog("pattern.txt", @"c:\test"))
    {
        sw.WriteLine(log);
    }
}

I've set append to true in the StreamWriter, because I assume you don't want to lose the contents of the file each time you run the programme.

It looks pretty inefficient (not tested that aspect), but it uses linq and lambdas up the wazoo!

Matt Ellen
  • 11,268
  • 4
  • 68
  • 90