Ich habe mehrere Textdateien mit etwa 100.000 Zeilen und möchte sie in kleinere Textdateien mit jeweils 5000 Zeilen aufteilen.
Ich benutzte:
split -l 5000 filename.txt
Das erstellt Dateien:
xaa
xab
aac
xad
xbe
aaf
dateien ohne Erweiterungen. Ich möchte sie nur so nennen:
file01.txt
file02.txt
file03.txt
file04.txt
oder wenn das nicht möglich ist, möchte ich nur, dass sie die Erweiterung ".txt" haben.
Ich weiß, dass die Frage schon vor langer Zeit gestellt wurde, aber ich bin überrascht, dass niemand die einfachste Unix-Antwort gegeben hat:
split -l 5000 -d --additional-suffix=.txt $FileName file
-l 5000
: Datei in Dateien mit jeweils 5.000 Zeilen aufteilen.-d
: numerisches Suffix. Dadurch wird das Suffix standardmäßig von 00 bis 99 anstatt von aa bis zz verschoben.--additional-suffix
: Hier können Sie das Suffix angeben, hier die Erweiterung$FileName
: Name der zu teilenden Datei.file
: Präfix zum Hinzufügen zu den resultierenden Dateien.Überprüfen Sie wie immer man split
für weitere Details.
Für Mac ist die Standardversion von split
offenbar inaktiv. Sie können die Version GNU mit dem folgenden Befehl installieren. ( siehe diese Frage für mehr GNU utils )
brew install coreutils
dann können Sie den obigen Befehl ausführen, indem Sie split
durch gsplit
ersetzen. Check out man gsplit
für Details.
Hier ist ein Beispiel in C # (weil ich danach gesucht habe). Ich musste eine 23 GB große csv-Datei mit rund 175 Millionen Zeilen aufteilen, um die Dateien betrachten zu können. Ich habe es in Dateien mit einer Million Zeilen aufgeteilt. Dieser Code hat es in etwa 5 Minuten auf meinem Rechner getan:
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
Hier ist ein nativer Windows-Stapel, der die Aufgabe erfüllen sollte.
Jetzt sage ich nicht, dass es schnell sein wird (weniger als 2 Minuten für jede 5Kline-Ausgabedatei) oder dass es gegen Chargensensitivitäten des Batches immun ist. Hängt wirklich von den Eigenschaften Ihrer Zieldaten ab.
Ich habe für meine Tests eine Datei mit dem Namen q25249516.txt
verwendet, die 100 Zeilen Zeilen enthält.
Schnellere Version überarbeitet
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
Beachten Sie, dass ich zum Testen llimit
von 50000 verwendet habe. Überschreibt die frühen Dateinummern, wenn llimit
* 100 der Anzahl der Zeilen in der Datei entspricht (kurieren Sie dies durch Setzen von fcount
auf 1999
und verwenden Sie ~3
anstelle von ~2
in der Dateierbenennungszeile.)
Syntax sieht so aus:
$ split [OPTION] [INPUT [PREFIX]]
dabei ist das Präfix PREFIXaa, PREFIXab, ...
Verwenden Sie einfach das richtige und Sie sind fertig oder verwenden Sie einfach mv zum Umbenennen . Ich denke $ mv * *.txt
sollte funktionieren, testen Sie es jedoch zunächst im kleineren Maßstab.
:)
Sie können vielleicht so etwas mit awk
machen
awk '{outfile=sprintf("file%02d.txt",NR/5000+1);print > outfile}' yourfile
Im Grunde berechnet es den Namen der Ausgabedatei, indem die Datensatznummer (NR) durch 5000 dividiert wird, 1 addiert wird, die Ganzzahl davon und die Nullpunktauffüllung auf 2 Stellen genommen wird.
Standardmäßig druckt awk
den gesamten Eingabesatz, wenn Sie nichts anderes angeben. So schreibt print > outfile
den gesamten Eingabesatz in die Ausgabedatei.
Bei der Ausführung unter Windows können Sie keine einfachen Anführungszeichen verwenden, da dies nicht gefällt. Ich denke, Sie müssen das Skript in eine Datei schreiben und dann awk
sagen, dass sie die Datei verwenden soll, etwa so:
awk -f script.awk yourfile
und script.awk
enthält das Skript folgendermaßen:
{outfile=sprintf("file%02d.txt",NR/5000+1);print > outfile}
Oder es kann funktionieren, wenn Sie dies tun:
awk "{outfile=sprintf(\"file%02d.txt\",NR/5000+1);print > outfile}" yourfile
Dieses Windows-Befehlszeilenprogramm "File Splitter" funktioniert gut: https://github.com/dubasdey/File-Splitter
Es ist Open Source, einfach, dokumentiert, bewährt und für mich gearbeitet.
Beispiel:
fsplit -split 50 mb mylargefile.txt
Meine Anforderung war etwas anders. Ich arbeite oft mit Comma Delimited und Tab Delimited ASCII Dateien, bei denen eine einzelne Zeile ein einzelner Datensatz ist. Und sie sind wirklich groß, also muss ich sie in überschaubare Teile aufteilen (wobei die Kopfzeile erhalten bleibt).
Also kehrte ich zu meiner klassischen VBScript-Methode zurück und bastelte ein kleines .vbs-Skript zusammen, das auf jedem Windows-Computer ausgeführt werden kann (es wird automatisch von der WScript.exe-Skript-Host-Engine für Windows ausgeführt).
Der Vorteil dieser Methode ist, dass Text Streams verwendet werden, sodass die zugrunde liegenden Daten nicht in den Arbeitsspeicher geladen werden (oder zumindest nicht alle gleichzeitig). Das Ergebnis ist, dass es außergewöhnlich schnell ist und nicht wirklich viel Speicher zum Ausführen benötigt. Die Testdatei, die ich gerade mit diesem Skript auf meinem i7 aufteilte, hatte eine Dateigröße von etwa 1 GB, hatte ungefähr 12 Millionen Testzeilen und erstellte 25 Teiledateien (jeweils mit jeweils etwa 500.000 Zeilen) - die Verarbeitung dauerte ungefähr 2 Minuten und es dauerte nicht Es geht nicht mehr als 3 MB Speicher, der an einem beliebigen Punkt verwendet wird.
Der Nachteil dabei ist, dass die Textdatei "Zeilen" hat (dh jeder Datensatz wird durch eine CRLF getrennt), da das Text Stream-Objekt die Funktion "ReadLine" für die Verarbeitung einer einzelnen Zeile verwendet. Aber wenn Sie mit TSV- oder CSV-Dateien arbeiten, ist das perfekt.
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())
hier ist eine in c #, die nicht aus dem Speicher geht, wenn sie in große Stücke aufgeteilt wird! Ich musste die 95M-Datei in 10M-Zeilendateien aufteilen.
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();
Ich habe dafür ein einfaches Programm erstellt, und Ihre Frage hat mir dabei geholfen, die Lösung zu vervollständigen ... Ich habe ein weiteres Feature und einige Konfigurationen hinzugefügt. konfigurierbar). Bitte gehen Sie die Hinweise durch. Ich habe die Codedateien hinzugefügt: https://github.com/mohitsharma779/FileSplit