比较文本文件的列

I need some advice on this piece of code. I'm developing a application in Go to read the content of a file line by line and compare one specific column formed by a hash with others in the same file. I'm trying to catch different hashes to the same filename and get an alert that a file has been changed.

Here's an example of the text file. Each line is formed by filename, hash and computer name:

c:\program files\internet explorer\iexplore.exe;0f3c97716fed8b554a7ec0464d50719f;computer1
c:\program files (x86)\google\chrome\application\chrome.exe;d387a06cd4bf5fcc1b50c3882f41a44e;computer1
c:\windows\system32
otepad.exe;AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA;computer1
c:\program files\internet explorer\iexplore.exe;BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB;computer1
c:\program files (x86)\google\chrome\application\chrome.exe;d387a06cd4bf5fcc1b50c3882f41a44e;computer1
c:\windows\system32
otepad.exe;f60a9d3a9461f68de0fccebb0c6cb31a;computer1

When running the code I'm getting the same information twice because I used two for. Obviously I just need one occurrence of each. Results:

go run main.go 
Original:   c:\program files\internet explorer\iexplore.exe 0f3c97716fed8b554a7ec0464d50719f computer1
Violation:  c:\program files\internet explorer\iexplore.exe BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB computer1
------
Original:   c:\windows\system32
otepad.exe AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA computer1
Violation:  c:\windows\system32
otepad.exe f60a9d3a9461f68de0fccebb0c6cb31a computer1
------
Original:   c:\program files\internet explorer\iexplore.exe BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB computer1
Violation:  c:\program files\internet explorer\iexplore.exe 0f3c97716fed8b554a7ec0464d50719f computer1
------
Original:   c:\windows\system32
otepad.exe f60a9d3a9461f68de0fccebb0c6cb31a computer1
Violation:  c:\windows\system32
otepad.exe AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA computer1
------
IGNORE THIS LINE []
IGNORE THIS LINE []

Expected result:

c:\program files\internet explorer\iexplore.exe;0f3c97716fed8b554a7ec0464d50719f;computer1
c:\program files\internet explorer\iexplore.exe;BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB;computer1

c:\windows\system32
otepad.exe;AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA;computer1
c:\windows\system32
otepad.exe;f60a9d3a9461f68de0fccebb0c6cb31a;computer1 

I tried break, continue, variables, etc but I think that I'm having trouble with logic to report only one occurrence.

Here's the code (finally):

package main

import (
    "bufio"
    "fmt"
    "io/ioutil"
    "os"
    "strings"
)

const (
    FILE_DIR = "./logs/"
)

func main() {

    p := fmt.Println

    // List and open all log files
    listOfFiles := listDirFiles(FILE_DIR)
    for _, file := range listOfFiles {

        f, err := os.Open(FILE_DIR + file)
        if err != nil {
            p("Error when opening the file " + FILE_DIR + file + " .")
            break
        }
        defer f.Close()

        var lines []string
        scanner := bufio.NewScanner(f)
        for scanner.Scan() {
            lines = append(lines, scanner.Text()) // Converting the content of a file into a slice
        }

        results := testViolation(lines)
        fmt.Println("IGNORE THIS LINE", results)
    }

}

func testViolation(lines []string) []string {
    var splitLine []string

    for _, f := range lines {
        splitLine = strings.Split(f, ";")

        for _, c := range lines {
            checkLine := strings.Split(c, ";")
            if splitLine[0] == checkLine[0] && splitLine[2] == checkLine[2] && splitLine[1] != checkLine[1] {
                fmt.Println("Original:  ", splitLine[0], splitLine[1], splitLine[2])
                fmt.Println("Violation: ", checkLine[0], checkLine[1], checkLine[2])
                fmt.Println("------")
            }
        }
    }
    return nil
}

func listDirFiles(dir string) []string {

    var filesString []string
    files, _ := ioutil.ReadDir(dir)

    // Convert []os.FileInfo into []string to return
    for _, f := range files {
        filesString = append(filesString, f.Name())
    }
    return filesString
}

I really appreciate your help.

Mario.

Use a map[string]string (e.g. mapName[computerName+fileName] = fileHashvalue, for each line check if the map entry exists for the given computer and file name (concatenated string - computerName + fileName) & if so compare with the existing hash value) you can do this in just one range loop instead of two you are using now. Hope this helps.

on testViolation you has (i deleted google chrome entry to better visibility):

line0 =
c:\program files\internetexplorer\iexplore.exe;
0f3c97716fed8b554a7ec0464d50719f;
computer1

line1:
c:\windows\system32
otepad.exe;
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA;
computer1

line2:
c:\program files\internetexplorer\iexplore.exe;
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB;
computer1

line3:
c:\windows\system32
otepad.exe;
f60a9d3a9461f68de0fccebb0c6cb31a;
computer1

On your loop:

for _, f := range lines {
    splitLine = strings.Split(f, ";")

    for _, c := range lines {
    // To f == line0, you match with c == line2
    // To f == line1, you match with c == line3
    // To f == line2, you match with c == line0
    // To f == line3, you match with c == line1
        checkLine := strings.Split(c, ";")
        if splitLine[0] == checkLine[0] && splitLine[2] == checkLine[2] && splitLine[1] != checkLine[1] {
        // ...
        }
    }
}

So, you need delete line when you find a match. it's not very sexy, but it's work

more simply: I think, you sould build a map["string-untilFirst';'"][]"stringhash+computer" on begin function.

// map[string][]string

So, just you count number element:

for _, v := range myMap {
    if len(v) > 1 {
    // if you need compare computer you can split here or use:
    // map[string]map[string][]string
    // "there are a diff on v[0] and v[1] * len(v)"
    }
}

I hope help you ;) Good continuation on you project !