我有大约100,000行的多个文本文件,我想将它们分成每个5000行的较小的文本文件。
我用了:
split -l 5000 filename.txt
创建文件:
xaa
xab
aac
xad
xbe
aaf
没有扩展名的文件。我只想称呼它们为:
file01.txt
file02.txt
file03.txt
file04.txt
或者,如果这不可能,我只希望他们使用“ .txt”扩展名。
我有大约100,000行的多个文本文件,我想将它们分成每个5000行的较小的文本文件。
我用了:
split -l 5000 filename.txt
创建文件:
xaa
xab
aac
xad
xbe
aaf
没有扩展名的文件。我只想称呼它们为:
file01.txt
file02.txt
file03.txt
file04.txt
或者,如果这不可能,我只希望他们使用“ .txt”扩展名。
Answers:
我知道这个问题已经问了很久了,但是我很惊讶没有人给出最直接的unix答案:
split -l 5000 -d --additional-suffix=.txt $FileName file
-l 5000
:将文件分成5,000行的文件。-d
:数字后缀。这将使后缀默认从00到99,而不是从a到zz。--additional-suffix
:让您指定后缀,此处为扩展名$FileName
:要分割的文件名。file
:添加到结果文件的前缀。与往常一样,请man split
查看更多详细信息。
对于Mac,split
显然是默认版本的。您可以使用以下命令安装GNU版本。(有关更多GNU utils,请参见此问题)
brew install coreutils
然后您可以将替换split
为来运行上述命令gsplit
。查看man gsplit
详细信息。
-d
并且--additional-suffix
不再支持该选项(OSX 10.12.6)
brew install coreutils
,然后在上面的命令中替换split
为gsplit
。
-t
用户指定的定界符而不是换行符上分割的标志。然后,您可以使用该-l
标志来指定要在输出文件中分组的拆分数。
这是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);
@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数据的文件进行测试。
修订更快的版本
快速眼动
@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
请注意,我使用llimit
了50000进行测试。如果llimit
* 100比文件中的行数更重要,则将覆盖早期的文件编号(通过设置fcount
为1999
并~3
代替~2
文件重命名行来进行固化。)
您也许可以用 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
(NR-1)/5000+1
我的要求有些不同。我经常使用逗号分隔和制表符分隔的ASCII文件,其中一行是一条数据记录。而且它们确实很大,因此我需要将它们分成可管理的部分(同时保留标题行)。
因此,我恢复了我的经典VBScript方法,并将一个小的.vbs脚本混在一起,该脚本可以在任何Windows计算机上运行(它由Window上的WScript.exe脚本宿主引擎自动执行)。
这种方法的好处是它使用文本流,因此不会将基础数据加载到内存中(或者至少不会一次全部加载到内存中)。结果是它运行速度极快,并且实际上不需要太多内存即可运行。我刚刚在i7上使用此脚本分割的测试文件大小约为1 GB,进行了大约1200万行测试,并制作了25个零件文件(每个文件约50万行)–处理过程大约需要2分钟,在任何时候都不会超过3 MB的内存。
需要注意的是,由于文本流对象使用“ ReadLine”功能一次只能处理一行,因此它依赖于具有“行”(意味着每个记录都用CRLF分隔)的文本文件。但是,嘿,如果您使用的是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())
这个“文件拆分器” Windows命令行程序运行良好:https://github.com/dubasdey/File-Splitter
它是开源的,简单的,有文档的,经过验证的,并且为我工作。
例:
fsplit -split 50 mb mylargefile.txt
这是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();
我为此创建了一个简单的程序,您的问题帮助我完成了解决方案...我增加了一项功能,并增加了一些配置。如果您想每隔几行添加一个特定的字符/字符串(可配置)。请仔细阅读笔记。我已经添加了代码文件:https : //github.com/mohitsharma779/FileSplit
split
(Unix / Linux实用程序),但是使用batch-file
Windows标记。