使用命令行将文本文件拆分为较小的多个文本文件

时间:2014-08-11 17:57:08

标签: batch-file split command cygwin text-files

我有多个文本文件,大约有100,000行,我想将它们拆分成每行5000行的较小文本文件。

我用过:

split -l 5000 filename.txt

创建文件:

xaa
xab
aac
xad
xbe
aaf

没有扩展名的文件。我只想打电话给他们:

file01.txt
file02.txt
file03.txt
file04.txt

或者如果不可能,我只希望他们有“.txt”扩展名。

9 个答案:

答案 0 :(得分:64)

我知道很久以前就已经问过这个问题,但我很惊讶没有人给出最简单的unix答案:

split -l 5000 -d --additional-suffix=.txt $FileName file
  • -l 5000:将文件拆分为每行5,000行的文件。
  • -d:数字后缀。这将使后缀默认为00到99而不是aa到zz。
  • --additional-suffix:允许您指定后缀,此处为扩展名
  • $FileName:要拆分的文件的名称。
  • file:添加到结果文件的前缀。

与往常一样,请查看man split了解详情。

对于Mac,split的默认版本显然是愚蠢的。您可以使用以下命令安装GNU版本。 (see this question for more GNU utils

brew install coreutils

然后您可以将split替换为gsplit来运行上述命令。查看man gsplit了解详情。

答案 1 :(得分:19)

以下是C#中的一个示例(因为这就是我要搜索的内容)。我需要分割一个23 GB的csv文件,大约有1.75亿行,以便能够查看文件。我把它分成每个一百万行的文件。这段代码在我的机器上大约5分钟就完成了:

var list = new List<string>();
var fileSuffix = 0;

using (var file = File.OpenRead(@"D:\Temp\file.csv"))
using (var reader = new StreamReader(file))
{
    while (!reader.EndOfStream)
    {
        list.Add(reader.ReadLine());

        if (list.Count >= 1000000)
        {
            File.WriteAllLines(@"D:\Temp\split" + (++fileSuffix) + ".csv", list);
            list = new List<string>();
        }
    }
}

File.WriteAllLines(@"D:\Temp\split" + (++fileSuffix) + ".csv", list);

答案 2 :(得分:15)

@ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET /a fcount=100
SET /a llimit=5000
SET /a lcount=%llimit%
FOR /f "usebackqdelims=" %%a IN ("%sourcedir%\q25249516.txt") DO (
 CALL :select
 FOR /f "tokens=1*delims==" %%b IN ('set dfile') DO IF /i "%%b"=="dfile" >>"%%c" ECHO(%%a
)
GOTO :EOF
:select
SET /a lcount+=1
IF %lcount% lss %llimit% GOTO :EOF
SET /a lcount=0
SET /a fcount+=1
SET "dfile=%sourcedir%\file%fcount:~-2%.txt"
GOTO :EOF

这是一个应该完成任务的本机Windows批处理。

现在我不会说它会很快(每个5Kline输出文件不到2分钟)或者它会对批量字符敏感性免疫。确实取决于目标数据的特征。

我使用了一个名为q25249516.txt的文件,其中包含100Klines数据供我测试。


修订更快的版本

REM

@ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET /a fcount=199
SET /a llimit=5000
SET /a lcount=%llimit%
FOR /f "usebackqdelims=" %%a IN ("%sourcedir%\q25249516.txt") DO (
 CALL :select
 >>"%sourcedir%\file$$.txt" ECHO(%%a
)
SET /a lcount=%llimit%
:select
SET /a lcount+=1
IF %lcount% lss %llimit% GOTO :EOF
SET /a lcount=0
SET /a fcount+=1
MOVE /y "%sourcedir%\file$$.txt" "%sourcedir%\file%fcount:~-2%.txt" >NUL 2>nul
GOTO :EOF

请注意,我使用了50000的llimit进行测试。如果llimit * 100比文件中的行数更接近,则会覆盖早期文件编号(通过将fcount设置为1999并使用~3代替{来解决问题{1}}在文件重命名行中。)

答案 3 :(得分:8)

您可以使用awk

执行此类操作
awk '{outfile=sprintf("file%02d.txt",NR/5000+1);print > outfile}' yourfile

基本上,它通过记录编号(NR)并将其除以5000来计算输出文件的名称,加1,将其整数和零填充加到2位。

默认情况下,awk在您未指定任何其他内容时打印整个输入记录。因此,print > outfile将整个输入记录写入输出文件。

当您在Windows上运行时,您不能使用单引号,因为它不喜欢它。我认为你必须把脚本放在一个文件中然后告诉awk使用这个文件,如下所示:

awk -f script.awk yourfile

script.awk将包含如下脚本:

{outfile=sprintf("file%02d.txt",NR/5000+1);print > outfile}

或者,如果你这样做可能会有效:

awk "{outfile=sprintf(\"file%02d.txt\",NR/5000+1);print > outfile}" yourfile

答案 4 :(得分:7)

语法如下:

$ split [OPTION] [INPUT [PREFIX]] 

其中前缀是 PREFIXaa,PREFIXab,...

只需使用正确的一个即可完成或只使用mv进行重命名。 我认为  $ mv * *.txt 应该工作,但首先在较小的规模上进行测试。

:)

答案 5 :(得分:5)

我的要求有点不同。我经常使用逗号分隔和制表符分隔的ASCII文件,其中单行是单个数据记录。而且它们非常大,所以我需要将它们分成可管理的部分(同时保留标题行)。

所以,我恢复了我的经典VBScript方法,并将一个小的.vbs脚本混合在一起,可以在任何Windows计算机上运行(它由Window上的WScript.exe脚本主机引擎自动执行)。

此方法的好处是它使用文本流,因此基础数据不会加载到内存中(或者至少不会一次加载到内存中)。结果是它非常快,并且它确实不需要太多内存来运行。我在i7上使用这个脚本分割的测试文件大约是1 GB的文件大小,有大约1200万行测试和25个部分文件(每个文件大约有500k行) - 处理大约需要2分钟而且没有任何时候都要使用超过3 MB的内存。

这里需要注意的是,它依赖于具有&#34; line&#34;的文本文件。 (意思是每个记录用CRLF分隔),因为文本流对象使用&#34; ReadLine&#34;用于一次处理一行的功能。但是,嘿,如果你正在使用TSV或CSV文件,它是完美的。

Option Explicit

Private Const INPUT_TEXT_FILE = "c:\bigtextfile.txt"  'The full path to the big file
Private Const REPEAT_HEADER_ROW = True                'Set to True to duplicate the header row in each part file
Private Const LINES_PER_PART = 500000                 'The number of lines per part file

Dim oFileSystem, oInputFile, oOutputFile, iOutputFile, iLineCounter, sHeaderLine, sLine, sFileExt, sStart

sStart = Now()

sFileExt = Right(INPUT_TEXT_FILE,Len(INPUT_TEXT_FILE)-InstrRev(INPUT_TEXT_FILE,".")+1)
iLineCounter = 0
iOutputFile = 1

Set oFileSystem = CreateObject("Scripting.FileSystemObject")
Set oInputFile = oFileSystem.OpenTextFile(INPUT_TEXT_FILE, 1, False)
Set oOutputFile = oFileSystem.OpenTextFile(Replace(INPUT_TEXT_FILE, sFileExt, "_" & iOutputFile & sFileExt), 2, True)

If REPEAT_HEADER_ROW Then
    iLineCounter = 1
    sHeaderLine = oInputFile.ReadLine()
    Call oOutputFile.WriteLine(sHeaderLine)
End If

Do While Not oInputFile.AtEndOfStream
    sLine = oInputFile.ReadLine()
    Call oOutputFile.WriteLine(sLine)
    iLineCounter = iLineCounter + 1
    If iLineCounter Mod LINES_PER_PART = 0 Then
        iOutputFile = iOutputFile + 1
        Call oOutputFile.Close()
        Set oOutputFile = oFileSystem.OpenTextFile(Replace(INPUT_TEXT_FILE, sFileExt, "_" & iOutputFile & sFileExt), 2, True)
        If REPEAT_HEADER_ROW Then
            Call oOutputFile.WriteLine(sHeaderLine)
        End If
    End If
Loop

Call oInputFile.Close()
Call oOutputFile.Close()
Set oFileSystem = Nothing

Call MsgBox("Done" & vbCrLf & "Lines Processed:" & iLineCounter & vbCrLf & "Part Files: " & iOutputFile & vbCrLf & "Start Time: " & sStart & vbCrLf & "Finish Time: " & Now())

答案 6 :(得分:5)

这个“File Splitter”Windows命令行程序运行良好:https://github.com/dubasdey/File-Splitter

它是开源的,简单的,记录的,经过验证的,并为我工作。

示例:

fsplit -split 50 mb mylargefile.txt

答案 7 :(得分:2)

这是c#中的一个,当分成大块时不会耗尽内存!我需要将95M文件拆分为10M x行文件。

var fileSuffix = 0;
int lines = 0;
Stream fstream = File.OpenWrite($"{filename}.{(++fileSuffix)}");
StreamWriter sw = new StreamWriter(fstream);

using (var file = File.OpenRead(filename))
using (var reader = new StreamReader(file))
{
    while (!reader.EndOfStream)
    {
        sw.WriteLine(reader.ReadLine());
        lines++;

        if (lines >= 10000000)
        {
              sw.Close();
              fstream.Close();
              lines = 0;
              fstream = File.OpenWrite($"{filename}.{(++fileSuffix)}");
              sw = new StreamWriter(fstream);
        }
    }
}

sw.Close();
fstream.Close();

答案 8 :(得分:0)

我为此创建了一个简单的程序,您的问题帮助我完成了解决方案...... 我添加了一个功能和一些配置。 如果你想在每几行之后添加一个特定的字符/字符串(可配置)。请仔细阅读说明。 我添加了代码文件: https://github.com/mohitsharma779/FileSplit