【问题标题】:Batch file to split .csv file用于拆分 .csv 文件的批处理文件
【发布时间】:2013-12-16 03:14:46
【问题描述】:

我有一个非常大的 .csv 文件 (>500mb),我希望在命令提示符下将其分解为更小的 .csv 文件。 (基本上是想在Windows中找到一个linux的“拆分”功能”。

这必须是一个批处理脚本,因为我的机器只安装了 windows 并且请求软件很痛苦。我遇到了一些示例代码 (http://forums.techguy.org/software-development/1023949-split-100000-line-csv-into.html),但是,当我执行批处理时它不起作用。我得到的只是一个输出文件,当我要求它每 20 000 行解析一次时,它只有 125kb。

有没有人遇到过类似的问题,您是如何解决这个问题的?

【问题讨论】:

  • 如果您使用的是 Windows,那么它不是 DOS。您正在谈论 Windows 命令提示符 (cmd.exe)
  • 使用GnuWin CoreUtils的拆分?
  • 想到了这一点,但在我的工作地点获取软件又是一件痛苦的事。由于所有贡献,此问题已得到解决。

标签: windows batch-file csv command-prompt


【解决方案1】:

试试这个:

@echo off
setLocal EnableDelayedExpansion

set limit=20000
set file=export.csv
set lineCounter=1
set filenameCounter=1

set name=
set extension=
for %%a in (%file%) do (
    set "name=%%~na"
    set "extension=%%~xa"
)

for /f "tokens=*" %%a in (%file%) do (
    set splitFile=!name!-part!filenameCounter!!extension!
    if !lineCounter! gtr !limit! (
        set /a filenameCounter=!filenameCounter! + 1
        set lineCounter=1
        echo Created !splitFile!.
    )
    echo %%a>> !splitFile!

    set /a lineCounter=!lineCounter! + 1
)

如上面的代码所示,它将原始的 csv 文件拆分为多个 csv 文件,限制为 20 000 行。您所要做的就是相应地更改!file!!limit! 变量。希望能帮助到你。

【讨论】:

  • 在我的 PC (core i7) 上,每兆字节大约需要 30 秒。给它 4 小时,它会拆分你的 500 MB csv。
  • 感谢 Dale,不幸的是,这段代码给出的输出与我给出的链接相同。输出了一个126kb的同名文件,内容和我之前做的差不多。
  • 你应该可以通过初始化设置lineCounter=1+%limit%filenameCounter=0来加快这个速度;然后在增加filenameCounter 之后将set splitfile 移动到if 化合物中。这样,文件名将每 20,000 行设置一次,而不是每一行...
  • 可悲的是,我相信这是注定的。环境变量可能包含的字符串长度(~8K)是有限制的,如果您有 1,000 列,那么您不必在每列中有太多数据即可超过该长度 - 列分隔符将占用 1,000 个字符作为一个开始!否则,戴尔的计划似乎是合理的……
  • 感谢您的脚本。是否可以改进处理带有 UTF8 字符的 CSV?
【解决方案2】:

一个可以做到这一点的免费 Windows 应用

http://www.addictivetips.com/windows-tips/csv-splitter-for-windows/

【讨论】:

  • 感谢伙伴 - 简单模式!
  • 不错的程序。快速简单。
  • 惊人的工具,完全符合我的需要,超级快速且易于使用。
  • 很好,无需安装
  • 美丽。快速地。干净的。作品。喜欢它。
【解决方案3】:

使用 cgwin 命令 SPLIT。 样品

每 500 行拆分一个文件计数:

split -l 500 [filename.ext]

默认情况下,它会在扩展名后添加 xa,xb,xc... 到文件名

要生成带有数字并以正确扩展名结尾的文件,请使用以下

split -l 1000 sourcefilename.ext destinationfilename -d --additional-suffix=.ext

-d或-l的位置无所谓,

  • "-d"--numeric-suffixes 相同
  • "-l"--lines 相同

更多信息:split --help

【讨论】:

    【解决方案4】:

    如果拆分非常大的文件,我找到的解决方案是对this 的改编,将 PowerShell “嵌入”在批处理文件中。 这工作很快,与我尝试过的许多其他事情相反(我不知道这里发布的其他选项)。

    下面mysplit.bat的使用方式是

    mysplit.bat <mysize> 'myfile'

    注意:该脚本旨在使用第一个参数作为分割大小。它目前被硬编码为 100Mb。解决这个问题应该不难。

    注意 2:电影名应该用单引号括起来。引用的其他替代方法显然不起作用。

    注意 3:它以给定的字节数分割文件,而不是在给定的行数。对我来说,这已经足够好了。 可能会添加一些代码行来完成每个块读取,直到下一个 CR/LF。这将分成整行(而不是固定数量的行),而不会牺牲处理时间。

    脚本mysplit.bat:

    @REM Using https://stackoverflow.com/questions/19335004/how-to-run-a-powershell-script-from-a-batch-file
    @REM and https://stackoverflow.com/questions/1001776/how-can-i-split-a-text-file-using-powershell
    @PowerShell  ^
        $upperBound = 100MB;  ^
        $rootName = %2;  ^
        $from = $rootName;  ^
        $fromFile = [io.file]::OpenRead($from);  ^
        $buff = new-object byte[] $upperBound;  ^
        $count = $idx = 0;  ^
        try {  ^
            do {  ^
                'Reading ' + $upperBound;  ^
                $count = $fromFile.Read($buff, 0, $buff.Length);  ^
                if ($count -gt 0) {  ^
                    $to = '{0}.{1}' -f ($rootName, $idx);  ^
                    $toFile = [io.file]::OpenWrite($to);  ^
                    try {  ^
                        'Writing ' + $count + ' to ' + $to;  ^
                        $tofile.Write($buff, 0, $count);  ^
                    } finally {  ^
                        $tofile.Close();  ^
                    }  ^
                }  ^
                $idx ++;  ^
            } while ($count -gt 0);  ^
        }  ^
        finally {  ^
            $fromFile.Close();  ^
        }  ^
    %End PowerShell%
    

    【讨论】:

    • csv 分割为多个字节可能不是所有想法中最好的。不应分割行。
    • @Stephan - 我认为你的陈述可能是真的,也可能不是。这一切都取决于一个人需要什么。我实际上需要拆分一个巨大的 csv,并在规定的行号或规定的字节数处进行同样的工作。这实际上是促使我编写这个脚本的需要。
    • 当然这取决于您的需求。只是想说明。 csv 在一行中间某处的某个值的中间结束或开始对我来说似乎是一场噩梦。但是 f 没关系,这似乎是一个很好的答案(也是唯一一个按大小而不是行号拆分的答案)。
    • @Stephan - 权衡(如果实际上有任何权衡)速度与“准确性”(牺牲行数以支持字节数)可能是值得的。 This comment 引号与接受的答案拆分为 500 MB 的 csv 文件,采用 i7(未知速度),在 4 小时内。我在大约 2 分钟内用我的脚本在 i5 中拆分了一个 4.5Gb 的 txt 文件。
    【解决方案5】:

    这将在newfile1.csv 中为您提供1 to 20000
    和文件newfile2.csv中的行20001 to the end

    它也克服了每行 8K 字符的限制。

    这使用了一个名为 findrepl.bat 的辅助批处理文件,来自 - https://www.dropbox.com/s/rfdldmcb6vwi9xc/findrepl.bat

    findrepl.bat 放在与批处理文件相同的文件夹中或路径上。

    它比普通的批处理文件更健壮,也更快。

    findrepl /o:1:20000 <file.csv >newfile1.csv
    findrepl /o:20001   <file.csv >newfile2.csv
    

    【讨论】:

    • 此链接没有任何内容。
    【解决方案6】:

    我在寻找类似解决方案时发现了这个问题。我修改了@Dale 给出的答案以适合我的目的。我想要一些更灵活并且有一些错误捕获的东西。只是想我可以把它放在这里给任何寻找同样东西的人。

    @echo off
    setLocal EnableDelayedExpansion
    GOTO checkvars
    
    :checkvars
        IF "%1"=="" GOTO syntaxerror
        IF NOT "%1"=="-f"  GOTO syntaxerror
        IF %2=="" GOTO syntaxerror
        IF NOT EXIST %2 GOTO nofile
        IF "%3"=="" GOTO syntaxerror
        IF NOT "%3"=="-n" GOTO syntaxerror
        IF "%4"==""  GOTO syntaxerror
        set param=%4
        echo %param%| findstr /xr "[1-9][0-9]* 0" >nul && (
            goto proceed
        ) || (
            echo %param% is NOT a valid number
            goto syntaxerror
        )
    
    :proceed
        set limit=%4
        set file=%2
        set lineCounter=1+%limit%
        set filenameCounter=0
    
        set name=
        set extension=
    
        for %%a in (%file%) do (
            set "name=%%~na"
            set "extension=%%~xa"
        )
    
        for /f "usebackq tokens=*" %%a in (%file%) do (
            if !lineCounter! gtr !limit! (
                set splitFile=!name!_part!filenameCounter!!extension!
                set /a filenameCounter=!filenameCounter! + 1
                set lineCounter=1
                echo Created !splitFile!.
            )
            cls
            echo Adding Line !splitFile! - !lineCounter!
            echo %%a>> !splitFile!
            set /a lineCounter=!lineCounter! + 1
        )
        echo Done!
        goto end
    :syntaxerror
        Echo Syntax: %0 -f Filename -n "Number Of Rows Per File"
        goto end
    :nofile
        echo %2 does not exist
        goto end
    :end
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-06-16
      • 2014-08-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-01
      • 1970-01-01
      相关资源
      最近更新 更多