26705
Goto Top

Textdatei mit 300.000 Zeilen splitten

Moin,

kennt jemand eine Möglichkeit eine Textdatei mit über 300000 Zeilen in nen Haufen kleinere Textdateien mit 2500 Zeilen aufzuteilen?
Hab mich schon an ner Batch probiert aus nem Thread hier probiert (Logfile letzten Zeilen in Txt File mit Batch).
Das funktioniert auch wunderbar, aber nur bis ca. 4000 Zeilen, dann bricht die Batch ab.
Hat jemand noch irgendeine Idee?
Habe hier zur Zeit leider nur Win XP zur Verfügung...

Content-Key: 51534

Url: https://administrator.de/contentid/51534

Printed on: April 19, 2024 at 00:04 o'clock

Member: bastla
bastla Feb 13, 2007 at 10:55:40 (UTC)
Goto Top
Hallo SeppelCeh!

Bei der Lösung per Batch gibt es öfters Probleme mit Sonderzeichen wie "&" oder ">", etc, daher eine VB-Script-Variante:
'SplitTextFile.vbs  
sInFile = WScript.Arguments(0)
If WScript.Arguments.Count < 2 Then
    lMaxLine = 2500
Else
    lMaxLine = CLng(WScript.Arguments(1))
End If

Set fso = Wscript.CreateObject("Scripting.FileSystemObject")  
sPath = fso.GetFile(sInFile).Path
sPath = Left(sPath, InstrRev(sPath, "\") - 1)  
sOutName =  sPath & "\Part_"  
If InstrRev(sInFile, ".") Then  
    sOutType = Mid(sInFile, InstrRev(sInFile, "."))  
End If

lLineNr=0
iFileNr=1001

Set oOut = fso.OpenTextFile(sOutName & Mid(CStr(iFileNr),2) & sOutType, 2, True)
Set oIn = fso.OpenTextFile(sInFile, 1)
Do While Not oIn.AtEndOfStream
	oOut.WriteLine oIn.ReadLine
	lLineNr = lLineNr + 1
	If lLineNr >= lMaxLine Then
		lLineNr = 0
		oOut.Close
		iFileNr = iFileNr + 1
		Set oOut = fso.OpenTextFile(sOutName & Mid(CStr(iFileNr),2) & sOutType, 2, True)
	End If
Loop
oIn.Close
oOut.Close
WScript.Echo "Done."  
Aufruf mit
SplitTextFile.vbs Textdatei ZeilenJeDatei
Alternativ kannst Du auch einfach die Textdatei auf das Script ziehen, dann werden Teildateien mit je 2500 Zeilen erzeugt (siehe "lMaxLine = 2500").

Die Teildateien werden jeweils im Ordner der ursprünglichen Textdatei mit dem gleichen Dateityp abgelegt. Die restliche Namensgebung findet in der Zeile "sOutName = sPath & "\Part_"" statt - "Part_" kannst Du auf Wunsch ersatzlos streichen, der "\" wird benötigt.

In der aktuellen Fassung ist die Anzahl der Teildateien auf 999 beschränkt, durch Änderung der Zeile "iFileNr=1001" auf einen Wert 10001 erhältst Du 4-stellige Dateinamen, also bis zu 9999 Dateien.

Grüße
bastla
Mitglied: 26705
26705 Feb 13, 2007 at 17:37:36 (UTC)
Goto Top
Wunderbar, werde ich morgen früh gleich mal testen.
Wird wohl doch dringend Zeit mich mit VB-Script zu beschäftigen...
Mitglied: 26705
26705 Feb 14, 2007 at 08:41:59 (UTC)
Goto Top
Läuft wunderbar, vielen Dank!!!

Gruß,
Seppel
Member: Celimos
Celimos Jan 11, 2012 at 13:49:31 (UTC)
Goto Top
Hallo zusammen!

Beruflich bedingt kenne ich dieses Forum schon längere Zeit und bin ausgesprochen dankbar dafür, da es mir bereits des Öfteren zu einem Problem entweder einen guten Ansatz oder sogar die Lösung geliefert hat. Da ich diesmal jedoch keine Antwort auf meine Frage gefunden habe, habe ich mich nun registriert und hoffe, dass mir eventuell jemand weiterhelfen kann...

Hier nun mein Problem: Über die Exportfunktion in DATEV Kanzlei-Rechnungswesen habe ich zunächst eine CSV-Datei mit Debitorenstammdaten eines Mandanten erstellt. Leider kann ich diese nicht weiterverarbeiten, da das Programm für die Folgebearbeitung eine Größenbeschränkung von 2 MB hat. Meine Export-Datei hat jedoch eine Dateigröße von 20 MB.
Eine Anfrage bei der DATEV-Hotline brachte mich nicht wirklich weiter, da man mir lediglich vorschlug, die Datei einfach händisch zu splitten. Da die Stammdaten jedoch einmal pro Woche über diesen Weg aktualisiert werden müssen, wäre das nicht wirklich praktikabel...
So gesehen hilft mir die von Bastla programmierte Lösung in gewisser Weise weiter, allerdings kommen bei der Verarbeitung durch das obige VB-Script am Ende auch wieder gesplittete CSV-Dateien mit der Endung .csv raus. Zur weiteren Verarbeitung brauche ich jedoch CSV-Dateien mit der Endung .txt. Darüber hinaus habe ich in der Ursprungsdatei am Anfang auch eine feste Anzahl an Zeilen, die als Header dienen und die zur korrekten Verarbeitung in den gesplitteten Dateien jeweils am Anfang vorhanden sein müssten.
Leider gehen meine VBS-Programmierkenntnisse so ziemlich gen Null, so dass ich nun vor einem für mich "unlösbaren" Problem stehe. Daher hoffe ich nun, dass sich jemand meines Problems annimmt und mir damit sehr weiterhelfen würde...

Vielen Dank im Voraus!


Grüße
Celimos
Member: bastla
bastla Jan 11, 2012 at 17:01:40 (UTC)
Goto Top
Hallo Celimos und willkommen als Mitglied!

Eine an Deine Wünsche angepasste (und etwas aktualisierte sow wie oberflächlich getestete) Fassung des Scripts könnte etwa so aussehen:
'SplitTextFile.vbs  
sInFile = WScript.Arguments(0)
lDataLines = CLng(WScript.Arguments(1))
lHeaderLines = CLng(WScript.Arguments(2))
sOutFolder = WScript.Arguments(3) 'kann natürlich auch hier fix eingetragen werden, zB: sOutFolder = "Parts"  
sOutFileName = "Part_"  
sOutType = ".txt"  

Set fso = CreateObject("Scripting.FileSystemObject")  
sOutPath = fso.GetParentFolderName(fso.GetFile(sInFile).Path) & "\" & sOutFolder  
If Not fso.FolderExists(sOutPath) Then fso.CreateFolder(sOutPath) 'Zielordner bei Bedarf erzeugen  
sOutName = sOutPath & "\" & sOutFileName 'Zielpfad inkl konstantem Namensanteil erstellen  

aText = Split(fso.OpenTextFile(sInFile).ReadAll, vbCrLf) 'gesamten Inhalt in Array einlesen  
lLines = (UBound(aText))'höchste Zeilennummer  
iFiles = Int((lLines + 1) / lDataLines + .99999) 'Anzahl Zieldateien  
iDigits = Int(Log(iFiles) / Log(10)) + 1 'Stellenanzahl für Dateinummer  
lLineNr = lHeaderLines '1. Datenzeile (nullbasiert) der Quelldatei  
lFileNr = 1000001

For i = 1 To iFiles 'Schleife für Zieldateien  
    Set oOut = fso.CreateTextFile(sOutName & Right(CStr(lFileNr), iDigits) & sOutType) 'Zieldatei mit lfd Nummer erstellen  
    'Ausgabe Kopfzeilen  
	For j = 1 To lHeaderLines
        oOut.WriteLine (aText(j - 1))
    Next
    'Ausgabe Zeilen in gewünschter Anzahl  
    For j = 1 To lDataLines
        If lLineNr > lLines Then Exit For 'letzte Datei enthält uU weniger als lDataLines Zeilen  
        oOut.WriteLine (aText(lLineNr)) 'Zeile schreiben  
        lLineNr = lLineNr + 1 'Quelldatei-Zeilennummer erhöhen  
    Next
    oOut.Close 'Zieldatei schließen  
    lFileNr = lFileNr + 1 'ldf Nummer für Zieldatei erhöhen  
Next
WScript.Echo "Done."  
Der Aufruf erfolgt mit
SplitTextFile.vbs CSV-Datei Datenzeilenanzahl Kopfzeilenanzahl
Alternativ können auch in den Zeilen 2 bis 4 anstelle von "WScriptArguments(x)" die gewünschten Werte in das Script eingetragen werden - für die Quelldatei würde das so aussehen:
sInFile = "D:\Pfad zur Datei\Datei.csv"
Die Zieldateien werden im Ordner der Quelldatei (siehe Zeile 9 - dort könnte auch ersatzweise ein anderer Pfad festgelegt werden) mit den Namen "Part_###.txt" erstellt (siehe dazu Zeilen 5 und 6), wobei die Stellenanzahl der laufenden Nummer an die Anzahl der Dateien angepasst wird: Entstehen etwa 79 Dateien, lauten deren Namen "Part_01.txt" bis "Part_79.txt", werden es 1235 Dateien, werden diese "Part_0001.txt" bis "Part_1235.txt" benannt.

Jede Zieldatei enthält die angegebene Anzahl von Kopfzeilen + die angegebene Anzahl von Datenzeilen.

Grüße
bastla

[Edit] Korrektur der Berechnung (s.u.) in Zeile 14 (jetzt 16) und Umstellung auf Angabe eines Zielordners als 4. Aufrufparameter [/Edit]
Member: Celimos
Celimos Jan 12, 2012 at 14:42:42 (UTC)
Goto Top
Hallo Bastla!

zunächst einmal ganz herzlichen Dank, dass Du mir so schnell eine Lösung "gezaubert" hast! Damit hast Du mir wirklich enorm viel Zeit und Nerven erspart.

Leider wollte das Script jedoch auf Anhieb nicht ganz funktionieren, aber durch Deine Kommentare und Erläuterungen glaube ich auch ohne große VB-Scriptkenntnisse dahintergekommen zu sein, wo sich der "Fehlerteufel" eingeschichen hat. Wenn ich das richtig sehe, müsste das Problem in Zeile 14 bei der Zahl hinter der Variable "lDataLines" liegen, denn damit rundet er ja den Integer-Wert auf die nächst höhere ganze Zahl auf - richtig? Somit müsste die Zeile dann sicher wie folgt lauten:

iFiles = Int((lLines + 1) / lDataLines + 1) 'Anzahl Zieldateien

Geäußert hat sich das Problem dadurch, dass bei der Verarbeitung nur Dateien erzeugt wurden, die die maximal definierte Zeichenanzahl enthielten. Da jedoch die Aufsplittung der Gesamtzeilenanzahl nur im Idealfall genau aufgeht und bei einer Gegenprüfung mit der Ursprungsdatei zudem ein paar Datensätze gefehlt haben, konnte ich den Fehler hierauf eingrenzen.

Nach der Korrektur arbeitet das Script jetzt an sich einwandfrei, allerdings hätte ich noch eine "kleine" Bitte: Sofern es für Dich nicht zu viel Aufwand bedeutet und Du das ganze Script nicht noch mal komplett umschreiben musst, würde ich gerne die gesplitteten Dateien zusätzlich in einen Ordner packen, da es sonst bei der Verwendung auf dem Desktop und einer größeren Anzahl an gesplitteten Dateien schnell unübersichtlich wird. Besondes schön wäre es natürlich, wenn diese Funktion wieder so "flexibel" aufgebaut wäre, wie das restliche Script, so dass es möglich ist, oben in der Datei den Ordnernnamen zu definieren und er mir dann an der Stelle, an der sich das Script befindet, einfach die Dateien in den genannten Ordner packt.
Auch hieran habe ich mich heute bereits längere Zeit erfolglos versucht und wäre ausgesprochen dankbar, wenn Du mir nochmals unter die Arme greifen könntest.


Grüße
Celimos
Member: bastla
bastla Jan 12, 2012 at 15:21:05 (UTC)
Goto Top
Hallo Celimos!

Mit dem Fehler in Zeile 14 (das Problem war nicht das Aufrunden auf die nächste ganze Zahl, sondern das kaufmännische Runden nach der 4/5-Regel, wodurch dann eben öfter nicht aufgerundet wird) hast Du recht, die Korrektur ist ganz knapp an der Optimallösung vorbei - es sollte nämlich nur .99999 addiert werden, damit nicht für den Fall, dass es genau ein Vielfaches der gewünschten Zeilenanzahl gibt, eine Datei zuviel (würde dann nur die Kopfzeilen enthalten) erzeugt wird ...

Ich korrigiere das oben noch und baue auch die Verwendung eines (als 4. Parameter beim Scriptaufruf) vorgegebenen Zielordners ein (den Hinweis auf die Zeile 9 - ist jetzt Zeile 10 - hätte ich gestern vielleicht noch etwas deutlicher formulieren können); beide Änderungen ungetestet ...

Grüße
bastla
Member: Celimos
Celimos Jan 18, 2012 at 13:32:02 (UTC)
Goto Top
Hallo Bastla!

entschuldige bitte, dass ich mich erst jetzt wieder melde, aber leider hatte ich die letzten Tage beruflich ziemlich viel um die Ohren...
Nach den letzten Anpassungen läuft Dein Script nun absolut tadellos und erleichtert uns die Arbeit wirklich ungemein! Hierfür nochmals ein herzliches Dankeschön!

Da ich ja in Zukunft nicht immer ankommen und darauf hoffen will, dass mir jemand von Grund auf ein Script programmiert, würde ich mich sehr freuen, wenn Du mir zum Abschluss eventuell noch einen Tipp geben kannst, welche Lektüre ich mir für den Einstieg in die VB-Scriptprogrammierung zulegen könnte. Sofern Du mir dahingehend etwas empfehlen kannst, wäre ich Dir besonders dankbar, wenn diese relativ praxisnah gehalten ist.


Grüße
Celimos
Member: csvmaxi
csvmaxi Jan 15, 2013 updated at 21:55:21 (UTC)
Goto Top
Hallo Bastla,

nach langen suchen im Netz bin ich auf diese Seite und diesen Artikel gestoßen. Ich habe mich bisher noch gar nicht mit VBA beschäftigt, merke aber, dass es einem viel arbeit abnehmen kann.

Ich habe das Script probier und die anfangswerte in die scriptdatei eingefügt. habe meine 60mb große csv auf das script gezogen. Das script macht alles, aber es fehlen die Datenzeiten. Es ist nur die headline vorhanden. kannst Du dir das ggf. erklären.

Besten Dank im Voraus.

Grüße
Thorsten
Member: bastla
bastla Jan 15, 2013 at 21:56:24 (UTC)
Goto Top
Hallo csvmaxi und willkommen im Forum!
Ich habe das Script probier und die anfangswerte in die scriptdatei eingefügt.
Wie sehen die ersten 7 Zeilen des Scripts bei Dir aus?

Und was genau meinst Du mit
Das script macht alles, aber es fehlen die Datenzeiten. Es ist nur die headline vorhanden.

Grüße
bastla

P.S.: Die Sprache ist übrigens VBS, nicht VBA ...
Member: csvmaxi
csvmaxi Jan 16, 2013 at 00:06:49 (UTC)
Goto Top
Hallo Bastla,

1.anbei die Zeilen:

'SplitTextFile.vbs
sInFile = "D:\1.csv"
lDataLines = "3000"
lHeaderLines = "1"
sOutFolder = "Parts"
sOutFileName = "Part_"
sOutType = ".csv"

Set fso = CreateObject("Scripting.FileSystemObject")

2. In den erstellten Dateien ist nur die Kopfzeilevorhanden, jedoch keine Datensätze.

Thats it is.

Scheinst ja nun im Bett zu liegen. Bin Nachtmensch..

Grüße
Thorsten
Member: bastla
bastla Jan 16, 2013 at 07:02:51 (UTC)
Goto Top
Hallo csvmaxi!

Zahlenwerte sind in Basic (also auch VBS) ohne Anführungszeichen zu schreiben - daher:
'SplitTextFile.vbs  
sInFile = "D:\1.csv"  
lDataLines = 3000
lHeaderLines = 1
sOutFolder = "Parts"  
sOutFileName = "Part_"  
sOutType = ".csv"  

Set fso = CreateObject("Scripting.FileSystemObject")  
Grüße
bastla