wake-up-neo.com

Teilen Sie die Textdatei mithilfe der Befehlszeile in mehrere kleinere Textdateien

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. 

60
ashleybee97

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.

61
ursan

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);
18
Alex
@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.)

15
Magoo

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.

:)

7
Ravi

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
7
Mark Setchell

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
5
Fabian Kessler

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())
5
Covenant

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();
2
Mobigital

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

0
User M