richmen
Goto Top

Textdatei kürzen (Dos-Batchprogramm?)

Hallo,

ich habe zwar schon einige ähnliche Probleme gefunden, jedoch leider nichts für meins.

1) wir starten täglich etwa 20 Excel Makros, die sich gegenseitig aufrufen, d.h. es wird nur das erste manuell gestarten und danach läuft alles weitere auf einem Extra Rechner automatisch.
2) bei den zu verarbeitenden Dateien ist eine Textdatei mit momentan ca. 650.000 Zeilen. Diese sol in diverse Excel-Tabellen mit jeweils 65.000 Zeilen geladen werden.
3) momentan lesen wir die Textdatei zeilenweise, um jeweils 65000 Zeilen in eine neue Textdatei zu schreiben, die dann in Excel geöffnet wird.

Meine Überlegung war nun, beim Öffnen der Textdatei in Excel anzugeben, ab welcher Zeile eingelesen werden soll. Nach der Verarbeitung sollte dann die Textdatei gekürzt werden, um wieder die letzten 65.000 Zeilen zu lesen.

Ich möchte also gerne eine Textdatei kürzen, und zwar immer um 65000 Zeilen. Egal was in den Zeilen enthalten ist.
Mit VBA habe ich keine Möglichkeit dies zu tun, kennt jemand eine Lösung?

Vielleicht mit einem Batchprogramm??

Grüße,
Richard

Content-Key: 66336

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

Printed on: April 20, 2024 at 03:04 o'clock

Member: bastla
bastla Aug 16, 2007 at 08:50:51 (UTC)
Goto Top
Hallo Richmen!

Wenn schon kürzen, dann würde ich vorschlagen, dies am Anfang der Textdatei zu machen. Dazu genügt folgende Batchzeile:
more +65000 Lang.txt > Kurz.txt

Grüße
bastla
Member: Richmen
Richmen Aug 16, 2007 at 08:56:10 (UTC)
Goto Top
Hallo bastla,

dann bekomme ich aber über 10 textdateien, die ich dann wiederum einlesen kann. Dies möchte ich vermeiden.
Damit wird die Datei ja nicht gekürzt, sondern einfach in deine neue geschrieben, sowas könnte ich auch gleich mit VBA realisieren.

Möchte nur die eine Textdatei behalten, und aus dieser eben Zeilen löschen.

Grüße,
Richard
Member: Biber
Biber Aug 16, 2007 at 09:09:38 (UTC)
Goto Top
Moin Richie,

wenn doch aber die gesamte große Textdatei durch Makros verarbeitet wird und zwar logisch gesehen als 10 Dateien zu je 65000 Zeilen...

Wo ist denn der Vorteil, dass die Textdatei in dieser Schleife immer den gleichen Namen behält (nur mit einem immer kürzer werdenden Inhalt)??
Wartbarer wäre es wahrscheinlich schon, wenn die Monster.txt in kleinere Häppchen Monsterchen01.txt, Monsterchen02.txt,...Monsterchen10.txt physisch aufgesplittet werden würde.

Hinterher, nach kompletter Verarbeitung ist doch egal, ob dann eine Monster.txt oder 10 Monsterchenxx.txt gelöscht werden können, oder nicht?

Grüße
Biber
Member: bastla
bastla Aug 16, 2007 at 09:12:05 (UTC)
Goto Top
Hallo Richmen!

Wenn Du nach der Verarbeitung wieder eine Lang.txt, aber mit 65000 Zeilen weniger haben willst, dann schreib eine zweite Batchzeile dazu:
move Kurz.txt Lang.txt

... obwohl ich vermutlich ohnehin das Ganze in einem Arbeitsgang in VBA lösen würde - allerdings ist für mich das Ziel der Verabeitung (... in diverse Excel-Tabellen ...) noch zu wenig konkret.

Grüße
bastla
Member: Richmen
Richmen Aug 16, 2007 at 09:28:24 (UTC)
Goto Top
Ja Biber du hast grundsätzlich recht.
So ist der Prozess heute. Mein Chef möchte das aber gern geändert haben. Lösung hat er auch keine, aber das spielt für mich keine Rolle.. man kennt das ja face-smile
Somit ist es meine Aufgabe einfach eine Lösung zu finden, damit wir nicht jedes mal die monster.txt auf 10 textfiles splitten.

@Bastler
Also das hinundher schieben der Daten oder Dateien ist eine sehr unschöne Lösung.

Ja wie würdest du das in einem Arbeitsgang in VBA lösen, genau danach bin ich auf der Suche.
Was fehlt dir für das Ziel der Verarbeitung.
Wir nehmen praktisch nur die Daten aus der Textdatei und schreiben sie in Exceltabellen. Es wird nichts berechnet o.ä.
Was nicht sein soll ist ein Lineprozessing, da es bei 10x65.000 Zeilen sonst ewig dauert. Also nicht Zeile für Zeile schreiben, sondern auf einen Satz immer 65.000 in Excel einlesen.

Grüße,
Richard
Member: Biber
Biber Aug 16, 2007 at 09:32:39 (UTC)
Goto Top
Moin Richie,

>Was nicht sein soll ist ein Lineprozessing, da es bei 10x65.000 Zeilen sonst ewig dauert. Also nicht Zeile für Zeile schreiben, sondern auf einen Satz immer 65.000 in Excel einlesen.
In eine Excel-Datei verteilt auf 10 Arbeitsblätter?
Kannst Du der Inputdatei ("Monster.txt") und der Exceldatei mal Pfade und Namen geben bitte?

Danke
Biber
Member: Richmen
Richmen Aug 16, 2007 at 09:39:07 (UTC)
Goto Top
Also wir werden die Excel Datei schon auf 10 Stück splitten.
Sonst müssen wir ja eine halbe Stunde warten bis die Datei geöffnet ist.

Die Excelfiles werden benannt:
Kros01.xls
Kros02.xls
Kros03.xls
...

Die Inputdatei ("Monster.txt") heisst:
KROS.ASC

Eine VBA Lösung dafür kennen wir hier keine..

Gruß,
Richard
Member: bastla
bastla Aug 16, 2007 at 19:21:18 (UTC)
Goto Top
Hallo Richmen!

Eine blockweise Lösung nur mit Bordmitteln kann ich zwar nicht anbieten, aber vielleicht hilft auch der folgende VBA-Ansatz:
Const QUELLE As String = "D:\Test"  
Const ASCNAME As String = "KROS.ASC"  
Const ZIEL As String = "D:\Test"  
Const XLSNAME As String = "Kros"  

Sub Import()
x = Timer

Set fso = CreateObject("Scripting.FileSystemObject")  
If fso.FileExists(QUELLE & "\" & ASCNAME) Then  
    aZeilen = Split(fso.OpenTextFile(QUELLE & "\" & ASCNAME, 1).ReadAll, vbCrLf) 'gesamte ASC-Datei einlesen  

    If fso.FileExists(ZIEL & "\" & XLSNAME & "01.xls") Then fso.DeleteFile ZIEL & "\" & XLSNAME & "??.xls" 'XLS-Dateien löschen  

    iLetzte = UBound(aZeilen) 'Zeilenanzahl - 1  
    iDNr = 101 'Zähler für Dateinamen (nur letzte 2 Stellen verwenden)  
    iZeile = 0 'Index für auszulesende Zeilen  
    iMaxDatei = Int((iLetzte + 1) / 65536) 'Anzahl "volle" Tabellen ...  
    If (iMaxDatei * 65536) < (iLetzte + 1) Then iMaxDatei = iMaxDatei + 1 '... und noch eine für den Rest  
    Dim W As Workbook
    
    For iDatei = 1 To iMaxDatei - 1 'Alle vollen Tabellen ...  
        Set W = Workbooks.Add
        W.Activate
        With W.Worksheets(1)
            For j = 1 To 65536
                .Cells(j, 1) = aZeilen(iZeile)
                iZeile = iZeile + 1
            Next
        End With
        AufteilenUndSpeichern W, Right(CStr(iDNr), 2)
        iDNr = iDNr + 1
    Next
    
    If iZeile <= iLetzte Then '... und der Rest  
        Set W = Workbooks.Add
        W.Activate
        With W.Worksheets(1)
            j = 1
            Do While iZeile <= iLetzte
                .Cells(j, 1) = aZeilen(iZeile)
                iZeile = iZeile + 1
                j = j + 1
            Loop
        End With
        AufteilenUndSpeichern W, Right(CStr(iDNr), 2)
    End If
Else
    MsgBox QUELLE & "\" & ASCNAME & " nicht gefunden!", vbCritical  
End If
MsgBox "Gesamtlaufzeit: " & Timer - x  
End Sub

Sub AufteilenUndSpeichern(WB As Workbook, sNummer As String)
'Spalte A mit eingelesener Textzeile mittels "Text in Spalten" aufteilen  
WB.Worksheets(1).Columns("A:A").TextToColumns Destination:=Range("A1"), DataType:=xlDelimited, _  
    TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=False, Tab:=True, _
    Semicolon:=True, Comma:=False, Space:=False, Other:=False, FieldInfo _
    :=Array(Array(1, 1), Array(2, 1), Array(3, 1), Array(4, 1)), TrailingMinusNumbers:=True

WB.SaveAs ZIEL & "\" & XLSNAME & sNummer & ".xls" 'Datei speichern ...  
WB.Close '... und schließen.  
End Sub
Da Du zum Trennzeichen keine Angaben gemacht hast, bin ich von Semikolon ausgegangen (siehe im "Sub Aufteilen" den vom Makrorecorder gelieferten "TextToColumns"-Teil).

Bei meinen Tests auf einem Dual-Core-Rechner (mit ausreichend Speicher!, da die Textdatei vollständig in den Speicher geladen wird) wurden 655.000 Zeilen mit je 4 Feldern (gesamte Satzlänge 70 Zeichen) in etwa 4 Minuten eingelesen und gespeichert.

Grüße
bastla

P.S.: Am Code lässt sich sicher noch einiges ergänzen (Errorhandling) / optimieren / verschönern...
Member: Richmen
Richmen Aug 17, 2007 at 08:18:27 (UTC)
Goto Top
Hi bastla,

wenn ich mir das "trocken" ansehe sieht das ganz gut aus. Leider läuft es bei mir nicht.
Ich bekomme bei dem readall einen Fehler:
Laufzeitfehler '-2147417848(80010108)':
Die Methode 'ReadAll' für das Objekt 'ITextStream' ist fehlgeschlagen.

Hast du eine Idee woran das liegen könnte.

Vielen Dank für deine Hilfe!

Rich
Member: bastla
bastla Aug 17, 2007 at 08:37:44 (UTC)
Goto Top
Hallo Richmen!

Mit der Beschreibung des Fehlers
80010108 2147549448 RPC_E_DISCONNECTED: The object invoked has disconnected from its clients.
kann ich leider nicht wirklich etwas anfangen ...

Versuch das Ganze einmal als VB-Script anzutesten, um zu sehen, ob der Fehler auch unabhängig von Excel auftaucht:
Const QUELLE = "D:\Test"  
Const ASCNAME = "KROS.ASC"  

Set fso = CreateObject("Scripting.FileSystemObject")  
aZeilen = Split(fso.OpenTextFile(QUELLE & "\" & ASCNAME, 1).ReadAll, vbCrLf)  
MsgBox "Eingelesen"  
Das Einlesen meiner Testdatei (wie groß ist übrigens Deine Datendatei?) von einer lokalen Platte dauert so etwa 10 Sekunden ...

Grüße
bastla
Member: Richmen
Richmen Aug 17, 2007 at 09:00:24 (UTC)
Goto Top
Dachte ich mir schon, aber einen Versuchs wars Wert!

Ja leider habe ich den gleichen Fehler wieder.
Die Datei hat etwas über 250MB.

Wenn ich die Textdatei mit einem Doppelklick öffne dauerts auch ca 10 sekunden bis sie offen ist.

Ich habe einen P4 mit 2.8 ghz und 1GB Ram.
Member: bastla
bastla Aug 17, 2007 at 09:21:06 (UTC)
Goto Top
Hallo Richmen!

Dann sieht es fast so aus, als müsstest Du doch sequentiell einlesen - vielleicht komme ich später dazu, das Script noch in diese Richtung umzuschreiben ...

Grüße
bastla
Member: Richmen
Richmen Aug 17, 2007 at 09:39:11 (UTC)
Goto Top
Hallo bastla,

ich habe nun auch einen anderen Lösungsvorschlag bekommen.
Dim fHandle As Long
Dim sFile As String
Dim nBytes As Long
  
' Datei, die "gekürzt" werden soll  
sFile = "c:\temp\MyFile.dat"  
  
' Anzahl Bytes die am Ende entfernt werden sollen  
nBytes = 10
  
' Datei öffnen und Handle erstellen  
fHandle = CreateFile(sFile, GENERIC_WRITE, _
  FILE_SHARE_READ, ByVal 0&, OPEN_EXISTING, _
  FILE_FLAG_SEQUENTIAL_SCAN, 0&)

If fHandle > 0 Then
  ' Dateizeiger an die gewünschte Position setzen  
  Call SetFilePointer(fHandle, -nBytes, ByVal 0&, FILE_END)
    
  ' Aktuelle Position als "END-Position" setzen  
  Call SetEndOfFile(fHandle)
    
  ' Datei schließen  
  Call CloseHandle(fHandle)
Else
  ' Fehler: Evtl. existiert die Datei nicht...  
End If

Muss mir das mal genauer ansehen, aber dies könnte auch funktionieren.

Dein Weg gefällt mir aber auch gut, die Laufzeit würde mich interessieren!..
Member: bastla
bastla Aug 17, 2007 at 09:56:33 (UTC)
Goto Top
Hallo Richmen!

Als Anmerkung zum alternativen Lösungsvorschlag:
Wenn die Aufteilung nicht nach Zeilen, sondern nur nach Speicherplatz (Bytes) erfolgen dürfte, wäre es natürlich einfacher - dann könntest Du außerdem ein beliebiges "Filesplit"-Utility verwenden, um passend große Textdateien zu erhalten ...

Grüße
bastla
Member: bastla
bastla Aug 17, 2007 at 10:51:08 (UTC)
Goto Top
Hallo Richmen!

Die sequentielle Version (ist bei mir übrigens auch kaum langsamer) - zur Sicherheit ohne Verwendung des "FileSystemObject":
Const QUELLE As String = "D:\Test"  
Const ASCNAME As String = "KROS.ASC"  
Const ZIEL As String = "D:\Test"  
Const XLSNAME As String = "Kros"  

Sub ImportSequ()
x = Timer

sQ = Dir(QUELLE & "\" & ASCNAME)  
If sQ <> "" Then  
    sZ = Dir(ZIEL & "\" & XLSNAME & "01.xls")  
    If sZ <> "" Then Kill ZIEL & "\" & XLSNAME & "??.xls" 'XLS-Dateien löschen  

    Open QUELLE & "\" & ASCNAME For Input As 1  
    iDNr = 101 'Zähler für Dateinamen (nur letzte 2 Stellen verwenden)  
    j = 1
    Dim W As Workbook
    Set W = Workbooks.Add
    W.Worksheets(1).Activate

    Do While Not EOF(1)
        If j <= 65536 Then
            Line Input #1, sZeile
            W.Worksheets(1).Cells(j, 1) = sZeile
            j = j + 1
        Else
            AufteilenUndSpeichern W, Right(CStr(iDNr), 2)
            iDNr = iDNr + 1
            j = 1
            Set W = Workbooks.Add
            W.Activate
        End If
    Loop

    AufteilenUndSpeichern W, Right(CStr(iDNr), 2) 'Die letzte Datei auch noch speichern ...  
    Close 1

Else
    MsgBox QUELLE & "\" & ASCNAME & " nicht gefunden!", vbCritical  
End If

MsgBox "Gesamtlaufzeit: " & Timer - x  
End Sub


Sub AufteilenUndSpeichern(WB As Workbook, sNummer As String)
'Spalte A mit eingelesener Textzeile mittels "Text in Spalten" aufteilen  
WB.Worksheets(1).Columns("A:A").TextToColumns Destination:=Range("A1"), DataType:=xlDelimited, _  
    TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=False, Tab:=True, _
    Semicolon:=True, Comma:=False, Space:=False, Other:=False, FieldInfo _
    :=Array(Array(1, 1), Array(2, 1), Array(3, 1), Array(4, 1)), TrailingMinusNumbers:=True
WB.SaveAs ZIEL & "\" & XLSNAME & sNummer & ".xls" 'Datei speichern ...  
WB.Close '... und schließen.  
End Sub

Grüße
bastla
Member: Richmen
Richmen Aug 27, 2007 at 06:14:04 (UTC)
Goto Top
So..


erstmal sorry dass ich mich erst jetzt wieder melde. Aber ich hatte die letzten Tage echt viel um die Ohren.
Leider hab ich es auch noch nicht geschafft das Programm zu testen. Habs aber nicht vergessen.

Habe es schonmal in einem kleinen Projekt laufen lassen, und da sah das ergebnis gut aus.

Es kann noch ein bisschen dauern bevor ich es in dem richtigen Projekt unterbringen kann, darum schreib ich schonmal vorab hier rein.

Also vielen Dank an dieser Stelle für eure Hilfe!!!!

Sollte es nicht laufen oder ich noch Probleme damit haben, werdet ihr sowieso von mir hören! face-wink

Vielen Dank!

Rich