File 分割两个大型CSV文件,在结果文件中保留文件A和B之间的关系

File 分割两个大型CSV文件,在结果文件中保留文件A和B之间的关系,file,csv,awk,split,File,Csv,Awk,Split,我有两个大的CSV文件(大约1GB)。它们都共享彼此之间的关系(ID就像外键一样)。结构很简单,逐行显示,但可以显示值字符串中带有换行符的CSV单元格 37373;“某些TXT-CRCF或其他换行符-”;3838383;“sasa ssss” 一个文件是p文件,另一个是T文件。T相当于P文件大小的70%(P>T)。我必须把它们切割成更小的部分,因为它们对于我必须导入的程序来说太大了。。。我不能简单地使用split-l100000,因为我将失去必须保留的ID=ID关系!关系可以是1:1、2:3、4

我有两个大的CSV文件(大约1GB)。它们都共享彼此之间的关系(ID就像外键一样)。结构很简单,逐行显示,但可以显示值字符串中带有换行符的CSV单元格

37373;“某些TXT-CRCF或其他换行符-”;3838383;“sasa ssss”

一个文件是p文件,另一个是T文件。T相当于P文件大小的70%(P>T)。我必须把它们切割成更小的部分,因为它们对于我必须导入的程序来说太大了。。。我不能简单地使用
split-l100000
,因为我将失去必须保留的ID=ID关系!关系可以是1:1、2:3、4:6或1:5。所以愚蠢的文件分割是没有选择的,我们必须检查我们创建一个新文件的地方。这是一个简化了CSV结构的示例,我希望在其中剪切文件(上面的几行是分开的P | T uu 00x文件,我们继续到P或T结束)。两个文件中的行都被排序,所以不需要在整个文件中搜索ID

文件“p”(空行表示清晰):

CSV_FILE_P;HEADER;GOES;HERE
564788402;1;1;"^";"01"
564788402;2;1;"^";"01"
564788402;3;1;"^";"01"

575438286;1;1;"^";"01"
575438286;1;1;"^";"01"
575438286;2;1;"37145859"
575438286;2;1;"37145859"
575438286;3;1;"37145859"
575438286;3;1;"37145859"

575439636;1;1;"^"
575439636;1;1;"^"

# lets say ~100k line limit of file P is somewhere here and no more 575439636 ID lines , so we cut.

575440718;1;1;"^"
575440718;1;1;"^"
575440718;2;1;"10943890"
575440718;2;1;"10943890"
575440718;3;1;"10943890"
575440718;3;1;"10943890"

575441229;1;1;"^";"01"
575441229;1;1;"^";"01"
575441229;2;1;"4146986"
575441229;2;1;"4146986"
575441229;3;1;"4146986"
575441229;3;1;"4146986"
文件T(空行表示清晰)

CSV_FILE_T;HEADER;GOES;HERE
564788402;4030000;1;"0204"

575438286;6102000;1;"0408"
575438286;6102000;0;"0408"
575439636;7044010;1;"0408"
575439636;7044010;0;"0408"

# we must cut here since bigger file "P" 100k limit has been reached
# and we end here because 575439636 ID lines are over.

575440718;6063000;1;"0408"
575440718;6063000;0;"0408"

575441229;8001001;0;"0408"
575441229;8001001;1;"0408"
你能不能帮我把这两个文件分成10万行(大约10万行),分别是T_001文件和相应的p_001文件等等?因此,文件部分之间的ID匹配。我相信awk将是最好的工具,但我在这个领域没有太多经验。最后一件事——CSV头应该保存在每个文件中。
我有强大的AIX机器来处理这个问题(linux也是可能的,因为AIX命令有时是有限的)

您可以使用awk解析开始的ID,然后检查当前ID是否与最后一个ID相同。只有在不同的情况下,才允许关闭当前输出文件并打开新文件。此时,记录用于跟踪下一个文件的ID。您可以在文本文件或内存中跟踪此id。我在内存中做过,但是像这样的大文件可能会给你带来麻烦。在内存中跟踪比打开多个文件并从中读取更容易

然后您只需要区分第一个文件(输出和记录)和第二个文件(输出和使用预记录的数据)

代码对字段中CRLF的可能性进行了非常猛烈的检查-如果该行不是以看起来像ID的内容开头,那么它将输出该行,并且不会对其进行进一步的测试。如果CRLF后面紧跟着一个数字和分号,这就是一个问题!但这可能不太可能

运行时使用:gawk-f parser.awk p T

我不能保证这是有效的

BEGIN {
    MAXLINES = 100000
    block = 0
    trackprevious = 0
}


FNR == 1 {
    # First line is CSV header
    csvheader = $0

    if (FILENAME == "-")
    {
        _error = 1
        print "Error: Need filename on command line"
        exit 1
    }

    if (trackprevious)
    {
        _error = 1
        print "Only one file can track another"
        exit 1
    }

    if (block >= 1)
    {
        # New file - track previous output...
        close(outputname)
        Tracking[block] = idval

        print "Output for " FILENAME " tracks previous file"
        trackprevious = 1
    }
    else
    {
        print "Chunking output (" MAXLINES ") for " FILENAME
    }

    linecount = 0
    idval = 0
    block = 1

    outputprefix = FILENAME "_block"
    outputname = sprintf("%s_%03d", outputprefix, block)

    print csvheader > outputname
    next
}


/^[0-9]+;/ {
    linecount++

    newidval = $0
    sub(/;.*$/, "", newidval)
    newidval = newidval + 0     # make a number

    startnewfile = 0

    if (trackprevious && (idval != newidval) && (idval == Tracking[block]))
    {
        startnewfile = 1
    }
    else if (!trackprevious && (idval != newidval) && (linecount > MAXLINES))
    {
        # Last ID value found before new file:
        Tracking[block] = idval
        startnewfile = 1
    }

    if (startnewfile)
    {
        close(outputname)
        block++

        outputname = sprintf("%s_%03d", outputprefix, block)
        print csvheader > outputname
        linecount = 1
    }

    print $0 > outputname
    idval = newidval
    next
}

{
    linecount++
    print $0 > outputname
}

为什么一台强大的AIX机器需要被它破坏?CSV显然不是解决方案的正确数据格式。使用数据库是的,但我不是DB管理员,无法创建、导入、使用JOIN然后再次导出DB解决方案。我需要awk、tail、head或其他工具解决方案。需要这些小文件的程序从CSV文件中导入,这是我的目标-获得保留关系的100000行文件。。。我在一家大型IT公司工作,不能自己创建和管理DB。DB guy正在休假,工作必须在明天完成。因此,stackoverflow社区是我最后的希望。如果删除空行,这有关系吗?我们根本不需要这样做(空行是为了让您第一眼看到关系,我已经输入了它们)。我们可能在不同的CSV“单元格”处有一个CRLF(或其他)换行符,所以在引号之间-这使得CSV中有时出现一个新的空行。。。但到目前为止,我只发现了一个地方有如此“糟糕的数据”(因为这个字段是一个人的名字——在我们国家没有白字:)…)。我可以删除此问题手册。在第二次sprintf中发现了一个错误(拼写错误!),但它似乎工作正常!谢谢,我还没有测试它。但这看起来像是聪明的(~100k)每文件行黑客攻击(不会在一个部分文件中丢失任何记录),但文件T呢?它应同时拆分,以覆盖P_block_xxx文件中的所有ID=ID记录(T中的对应ID行应放置在T_block_xxx处,以形成可用的文件对)。我们不需要在T文件中搜索数据,它是经过排序的(如示例所示)。导入程序要求同时导入两个,P和T文件。是的,我刚刚阅读了原始帖子,我看到了。它也不能保持标题(足够简单)。P和T匹配吗?Ie:如果P中有100*“575438286”,那么T中也有100*?(编辑:关系可以是1:1、2:3、4:6或1:5。我明白了。更困难)您可以做的是解析P,同时为T生成一个跟踪文件。然后解析T。或者您可以打开P和T,同时扫描它们。随着ID的排序,这也同样容易。我会回来告诉你:-)是的,如果100个ID,在这两个文件中,简单的
分割就足够了,我不会问任何人怎么做。但是现在我将使用tail-n1和head-n1来获得第一个和最后一个P_块uid,然后使用hmm dunno grep来计算大T文件中出现的第一个ID,然后使用grep来获得最后一个ID的最后一次出现,然后使用tail+head组合来将想要的部分切割成新的>T_块xxx。不是awk而是bash风格。。。T文件看起来像已排序的,所以不需要爬网和搜索相应的ID!只需搜索开始和最后一行,然后削减这一部分和中提琴!