将2个大型排序的CSV文件组合到一个文件中

将2个大型排序的CSV文件组合到一个文件中

问题描述:

我有一个大小约为50GB的存档文件。将2个大型排序的CSV文件组合到一个文件中

每个星期,我都需要一个CSV文件,并将其与非常大的50GB CSV文件合并。

我是Go的新手,希望Go有一个不错的解决方案。

这些文件看起来像:

"a:123", 101010 
"b:123", 101010 
"some-key-here:123", 101010 
"some-key-here:234", 101010 
+3

如果你在Unix/Linux/OS X上,你应该考虑使用'sort'命令。艰苦的工作已经为你完成。 – Daniel 2013-03-27 21:08:16

虽然我没有编译它自己来检查,这应该做你想做的,一旦你实现compare()功能。它本质上是Mergesort算法的“合并”步骤。由于您已经按照排序顺序得到了这两个文件,因此您只需要合并步骤,这可以通过流式处理完成。

package main 

import (
    "encoding/csv" 
    "io" 
    "log" 
    "os" 
) 

const outFile = "your/output/file/path.ext" 

func main() { 
    // make sure there are only 2 args 
    if len(os.Args) != 3 { 
     log.Panic("\nUsage: command file1 file2") 
    } 

    // open the first file 
    f1, e := os.Open(os.Args[1]) 
    if e != nil { 
     log.Panic("\nUnable to open first file: ", e) 
    } 
    defer f1.Close() 

    // open second file 
    f2, e := os.Open(os.Args[2]) 
    if e != nil { 
     log.Panic("\nUnable to open second file: ", e) 
    } 
    defer f2.Close() 

    // create a file writer 
    w, e := os.Create(outFile) 
    if e != nil { 
     log.Panic("\nUnable to create new file: ", e) 
    } 
    defer w.Close() 

    // wrap the file readers with CSV readers 
    cr1 := csv.NewReader(f1) 
    cr2 := csv.NewReader(f2) 

    // wrap the out file writer with a CSV writer 
    cw := csv.NewWriter(w) 

    // initialize the lines 
    line1, b := readline(cr1) 
    if !b { 
     log.Panic("\nNo CSV lines in file 1.") 
    } 
    line2, b := readline(cr2) 
    if !b { 
     log.Panic("\nNo CSV lines in file 2.") 
    } 

    // copy the files according to similar rules of the merge step in Mergesort 
    for { 
     if compare(line1, line2) { 
      writeline(line1) 
      if line1, b = readline(cr1); !b { 
       copy(cr2, w) 
       break 
      } 
     } else { 
      writeline(line2) 
      if line2, b = readline(cr2); !b { 
       copy(cr1, w) 
       break 
      } 
     } 
    } 

    // note the files will be closed here, since we defered it above 
} 

func readline(r csv.Reader) ([]string, bool) { 
    line, e := r.Read() 
    if e != nil { 
     if e == io.EOF { 
      return nil, false 
     } 
     log.Panic("\nError reading file: ", e) 
    } 
    return line, true 
} 

func writeline(w csv.Writer, line []string) { 
    e := w.Write(line) 
    if e != nil { 
     log.Panic("\nError writing file: ", e) 
    } 
} 

func copy(r csv.Reader, w csv.Writer) { 
    for line, b := readline(r); !b; r, b = readline(r) { 
     writeline(w, line) 
    } 
} 

func compare(line1, line2 string) bool { 
    /* here, determine if line1 and line2 are in the correct order (line1 first) 
     if so, return true, otherwise false 
    */ 
} 

注:这个答案已经被大量编辑,包括内联代码,而不是链接。此外,自第一稿以来,代码已经有了很大的改进,但由于这里没有任何活动,我只是吹走旧版本并重写我的答案。

如果两个文件分别排序,则可以使用合并排序的合并函数将它们合并到排序后的数组中。

通过数组,我的意思是我们可以使用另一个CSV文件即时写入排序数据。

+0

问题的标题显示它已排序。由于文件很大,流式传输比读入数组更好(它可能不适合内存)。 – burfl 2013-04-09 17:50:38