這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
Part 01 目標
對記錄檔進行過濾,拆分;
Part 02 瞭解與思路
這是實習公司派給我的工作,在我快要淡出鳥的時候。有幾份記錄檔,很大的,以G為單位的。裡面很多不必要的資訊,需要過濾掉。另外,日誌是記錄在一起的,分析起來的時候,沒有條理性,所以,要求根據日期,進行拆分,同一天的日誌為一個檔案,以日期命名,檔案。
編程的重點是Regex的使用和檔案操作。
Part 03 來幾行瞧瞧
因為需要構造正則,所以得知道檔案的格式。直接開啟檔案是個不明智的選擇,對我而言,準確點,對我的電腦來說,開啟大檔案,我的小本本承受不了這樣的負擔。在Linux環境中,其實一條命令就可以了:
head -n 100 # 顯示前面100行;tail -n 100 # 顯示最後100行;sed -n '5,10p' filename # 這樣可以只查看檔案的第5行到第10行;
是不是很方便。但是,我想練習一下golang,所以花了點時間,寫了個小程式:
// Auth:Reluxer// Time:2015-07-23// Name:preview.go// Description:閑得慌,寫了兩個函數package mainimport ( "bufio" "fmt" "io" "os")const ( ViewLineNum = 40)func ReadFileByLine002(filename string) error { f, err := os.OpenFile(filename, os.O_RDONLY, 0660) if err != nil { return err } defer f.Close() sc := bufio.NewScanner(f) for i := 0; i < ViewLineNum; i++ { sc.Scan() fmt.Println(sc.Text()) } return sc.Err()}func ReadFileByLine001(filename string) error { f, err := os.Open(filename) if err != nil { return err } defer f.Close() buf := bufio.NewReader(f) for i := 0; i < ViewLineNum; i++ { line, err := buf.ReadString('\n') if err != nil { if err == io.EOF { fmt.Println("EOF") break } return err } fmt.Print(line) } return nil}func main() { filename := os.Args[1] err := ReadFileByLine002(filename) if err != nil { fmt.Println(err) }}
這樣之後,我看到了檔案的格式是這樣的:
10.88.111.101 - - [18/Jul/2015:00:00:02 +0800] "GET /topics/2014-11-18/2269791.html HTTP/1.1" 200 1557110.88.111.101 - - [18/Jul/2015:00:00:02 +0800] "GET /topics/2014-12-26/2419017.html HTTP/1.1" 200 1517610.88.111.101 - - [18/Jul/2015:00:00:03 +0800] "GET /topics/2012-10-18/3535945.html HTTP/1.1" 200 1525010.88.111.101 - - [18/Jul/2015:00:00:03 +0800] "GET /topics/2014-11-10/2245185.html HTTP/1.1" 200 15250
Part 04 過濾吧
知道了檔案格式,接下來就是過濾掉冗雜的日誌,主要是.css,.js,.jpg,.png,.gif。這部分的代碼如下:
package mainimport ( "bufio" "fmt" "io" "os" "regexp")const ( RegRuler = `(\.js HTTP)|(\.jpg HTTP)|(\.png HTTP)|(\.css HTTP)|(\.gif HTTP)`)func Process(filesrc, fielestore string) error { var fsrc, fdes *os.File var err error fsrc, err = os.OpenFile(filesrc, os.O_RDONLY, 0660) if err != nil { return err } defer fsrc.Close() if fdes, err = os.OpenFile(fielestore, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666); err != nil { return err } defer fdes.Close() sc := bufio.NewScanner(fsrc) reg := regexp.MustCompile(RegRuler) for sc.Scan() { line := sc.Text() match := reg.FindString(line) if match == "" { if _, err = io.WriteString(fdes, line+"\n"); err != nil { return err } } } return sc.Err() return nil}func main() { filename := os.Args[1] filestorename := "no-css-jpg-png-gif-js_log" if err := Process(filename, filestorename); err != nil { fmt.Println(err) return } fmt.Println("ok")}
讓我沒想到的是,程式的已耗用時間超級長,長的我看了一集花千骨,它還沒結束。
另外,這一步在Linux底下,也是敲一敲命令就完工的事情。Linux真是強大到沒邊了。
Part 05 拆分,時間是標準
光是這樣,檔案還是太大,而且沒有條理,所以啊,要按照時間來拆分檔案。那好吧,你說拆分就拆分嘍,我沒意見。
代碼如下:
package mainimport ( "bufio" "fmt" "io" "os" // "path" "regexp")const ( RegRuler = `\[(?P<day>\d{2})/(?P<month>[A-Za-z]{3})/(?P<year>\d{4}):\d{2}:\d{2}:\d{2}\s\+\d{4}\]`)func Process(filesrc string) error { var fsrc, fdes *os.File var err error premonth := "" preday := "" preyear := "" curmonth := "" curday := "" curyear := "" filedes := "" fsrc, err = os.OpenFile(filesrc, os.O_RDONLY, 0660) if err != nil { return err } defer fsrc.Close() sc := bufio.NewScanner(fsrc) reg := regexp.MustCompile(RegRuler) for sc.Scan() { line := sc.Text() // fmt.Println(line) match := reg.FindStringSubmatch(line) // fmt.Println(match) // if match == nil { // if curday == "" && curmonth == "" && curyear == "" { // if fdes, err = os.OpenFile("unkonow.txt", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666); err != nil { // return err // } // } // fmt.Println("here") // } else { if match != nil { for i, name := range reg.SubexpNames() { //Ignore the whole regexp match and unnamed groups if i == 0 || name == "" { continue } switch name { case "month": curmonth = match[i] case "day": curday = match[i] case "year": curyear = match[i] } } // fmt.Println(filedes) if curday != preday || curmonth != premonth || curyear != preyear { fdes.Close() filedes = curyear + "-" + curmonth + "-" + curday if fdes, err = os.OpenFile(filedes, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666); err != nil { return err } } } _, err = io.WriteString(fdes, line+"\n") if err != nil { // fmt.Println("here") fdes.Close() return err } preyear = curyear preday = curday premonth = curmonth // match := //fmt.Fprintf(os.Stdout,"%s\n",scanner.Text()) } fdes.Close() return sc.Err() return nil}func main() { filename := os.Args[1] // fmt.Println(filename) // err := ReadFileByLine001(filename) err := Process(filename) if err != nil { fmt.Println(err) } fmt.Println("ok")}
Part 06 結束吧
到這兒呢,基本就差不多了。該結束了。說一下,感慨。
- 之前的代碼少些了幾行,然後,我的小本本就承受不住,主板過熱,自動關機了,真的是嚇死爹了。
- 編程的過程都是一邊百度,一邊碼代碼,也算是小有收穫。
- 學語言就得實踐,在實踐中學習。