lexura
Goto Top

Textdatei splitten in Anzahl Datensätze aus Originaldatei

Guten Tag an die Profis,

ich stehe vor einem Problem mit einer .txt Datei. Wir erstellen eine .txt datei mit Daten aus einem SQL-Server.
Jeder Datensatz belegt dabei eine feste Satzlänge (855 Zeichen) in der .txt Datei.
Die Daten in der .txt Datei werden fortlaufend geschrieben.

Es wird jeden Tag eine neue Datei mit unterschiedlicher Anzahl an Datensätzen erstellt.

Jetzt ist meine Aufgabe dazu, aus der EINEN .txt Datei für jeden darin enthaltenen Datensatz (je 855 Zeichen) eine eigene .txt Datei zu erstellen und diese dann in einem Unterverzeichnis zur Verfügung zu stellen. Quasi die Originaldatei zu splitten in die Anzahl der enthaltenen Datensätze.

Ein Programmcode in powershell oder vbs wäre für mich die Beste Wahl.

Kann jemand helfen ???

Besten Dank im voraus, Gruß lexura

Content-Key: 229652

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

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

Member: bastla
Solution bastla Feb 13, 2014, updated at Feb 14, 2014 at 10:36:23 (UTC)
Goto Top
Hallo lexura und willkommen im Forum!

Da Du keine näheren Angaben zu den gewünschten Datei-/Verzeichnisnamen machst, verwende ich für die Ausgabe das Tagesdatum:
Ein = "D:\Gesamtdatei.txt"  
Zeichenanzahl = 855
Basisordner = "D:\" 'unter diesem Ordner wird der Unterordner erstellt  

Set fso = CreateObject("Scripting.FileSystemObject")  

Datum = Right(Date, 4) & "-" & Mid(Date, 4, 2) & "-" & Left(Date, 2) 'Datum in der Form "JJJJ-MM-TT"  
Pfad = fso.BuildPath(Basisordner, Datum) 'Ordnerpfad erstellen  

T = fso.OpenTextFile(Ein).ReadAll 'Datei in String einlesen  
Anzahl = Int(Len(T) / Zeichenanzahl) 'Anzahl vollständiger Datensätze ermitteln  

If Not fso.FolderExists(Pfad) Then fso.CreateFolder(Pfad) 'Ordner erzeugen  

'Zählschleife für die formatierte Ausgabe der laufenden Nummer (4-stellig mit führenden Nullen)  
For i = 10001 To 10000 + Anzahl
    'Datei mit dem Namen "JJJJ-MM-TT_####.txt" erzeugen  
    'Dateiinhalt: Teilstring ab Position (Abschnittsnummer - 1) * Zeichenanzahl mit Länge Zeichenanzahl  
    'Abschnittsnummer: i - 10000  
    fso.CreateTextFile(fso.BuildPath(Pfad, Datum & "_" & Right(i, 4)) & ".txt").Write Mid(T, (i - 10001) * Zeichenanzahl + 1, Zeichenanzahl)  
Next
Grüße
bastla
Member: colinardo
Solution colinardo Feb 13, 2014, updated at Feb 14, 2014 at 10:35:13 (UTC)
Goto Top
Hi lexura,
und wenn du Powershell willst:
$infile = "D:\data.txt"   
$outpath = "D:\Ausgabeordner"  
$zeichen = 855
$content = gc $infile | out-string
$length = ($content | measure -Character).Characters
$parts = 0
if($length -gt $zeichen){
  $parts = [int]($length/$zeichen)
}else{
  $parts = 1
  $zeichen = $length
}
for($i=0;$i -lt $parts;$i++){
  echo "$($content.Substring($i*$zeichen,$zeichen))" | out-file "$outpath\$(get-date -Format "yyyy-MM-dd")_$($i+1).txt"  
}
Die Ausgabe der Dateien erfolgt mit dem aktuellen Datum und einem Zähler für die Abschnitte: JJJJ-MM-TT_[Zähler].txt

Grüße Uwe
Member: lexura
lexura Feb 14, 2014 updated at 07:15:59 (UTC)
Goto Top
Vielen vielen Dank !!! Die Scripte sind perfekt. Schön wenn Profis sich so unkompliziert bereit erklären zu helfen.

mit den freundlichsten und hochachtungsvollen Grüßen
Ralf
Member: lexura
lexura Feb 14, 2014 at 10:35:40 (UTC)
Goto Top
Hallo nochmal,
nach den ersten Tests sind jetzt doch noch ein paar Hindernisse aufgetaucht. Das Ziel muss es sein Dateien zu haben die eine feste Satzlänge von 855 Zeichen haben, keinen BOM am Beginn der Datei und kein CRLF am Ende der Datei haben und die Dateien müssen im Format UTF-8 sein.

Ich habe mir das Powershellscript von Uwe als Basis genommen. Eine Kollegin probiert sich in VBS.

Das ich kein Programmierer bin, seht ihr wahrscheinlich gleich an meinem aktuellen Script. Wir hatten vorher schon die Ausgangsdatei vom BOM mit einem Powershell-Script bereinigt. Den Code habe ich mal einfach an das Script von Uwe angefügt. Das geht bestimmt auch eleganter, aber es funktioniert erstmal face-smile

Ich habe jetzt im Ausgangsordner ( ....\noBOM) alle Dateien ohne BOM und in UTF-8 liegen, leider noch inkl. CRLF am Ende.

Kann mir einer das Script vervollständigen, damit bei jeder Datei das CRLF am Ende entfernt wird, kein BOM am Beginn der Dateien steht, sie im UTF-8 Format sind und die Satzlänge genau 855 Zeichen beträgt ???

Hier mein vorläufiges angepasstes Script:

$date = Get-Date -Format "yyyy-MM-dd"
$infile = "D:\Ausgangsdatei.txt"
$outpath = "D:\Uebermittlungsdateien\"
$zeichen = 885
$content = gc $infile | out-string
$length = ($content | measure -Character).Characters
$parts = 0
if($length -gt $zeichen){
$parts = [int]($length/$zeichen)
}else{
$parts = 1
$zeichen = $length
}
for($i=0;$i -lt $parts;$i++){
echo "$($content.Substring($i*$zeichen,$zeichen))" | out-file "$outpath\$($date)_$($i+1).txt"
}

set-location "D:\Uebermittlungsdateien\"
foreach($i in ls -name *.txt)
{
$file = get-content $i
$encoding = New-Object System.Text.UTF8Encoding($False)
[System.IO.File]::WriteAllLines("D:\Uebermittlungsdateien_noBOM\" + $i, $file, $encoding)
}


Um CRLF am Ende einer Datei zu entfernen, haben wir bislang ein VBS benutzt. Dieses kann aber nur mit einer Datei klarkommen und nicht mit allen Dateien im Zielordner.

Hier mal der Ansatz in VBS: (hoffe das kann einer in Powershell nachstellen)


' File: crlf-entfernen.vbs

Option Explicit

Dim WSHShell, fso, FileIn, FileOut
Dim Datei, Text, Txt, i, arrSort, arrTest(), oArgs

Set WSHShell = WScript.CreateObject("WScript.Shell")
Set fso = WScript.CreateObject("Scripting.FileSystemObject")
set oArgs = Wscript.Arguments

' Zuweisen von Admin-Rechten
' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If WScript.Arguments.length =0 Then
Set objShell = CreateObject("Shell.Application")
'Pass a bogus argument with leading blank space, say [ uac]
objShell.ShellExecute "wscript.exe", Chr(34) & _
WScript.ScriptFullName & Chr(34) & " uac", "", "runas", 1
Else
'Add your code here
End If


' Fals ein Argument übergeben wurde, sollte es einen Dateinamen
' enthalten
' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
For i = 0 to oArgs.Count - 1 ' hole alle Argumente
Datei = oArgs.item(i)
If not fso.FileExists( Datei ) then
MsgBox UCase( Datei ) & " existiert nicht!" & vbCRLF & vbCRLF & " . . . das ist das Ende.", , WScript.ScriptName
WScript.Quit
End If
Exit For ' nur das erste Argument reicht
Next


' Gibt's keinen Dateinamen, wird halt das Skript gelesen
' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if Datei = "" then Datei = WScript.ScriptName


' Datei komplett einlesen
' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Set FileIn = FSO.OpenTextFile(Datei, 1 ) ' Datei zum Lesen öffnen

Text = FileIn.ReadAll

FileIn.Close
Set FileIn = nothing


' Inhalt bearbeiten
' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Text = Replace( Text, vbCRLF , "" )
Text = Replace( Text, vbCRLF , "" )


' (Ziel-) Datei schreiben
' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Datei = fso.GetBaseName( Datei ) & "-.txt"

Set FileOut = FSO.OpenTextFile( Datei , 2, true) ' Datei zum Screiben öffnen; 2: immer neu anlegen

FileOut.Write( Text )

FileOut.Close
Set FileOuT = nothing


Hoffe es euch genug erklärt zu haben. Evtl. hat ja jemand noch nen Lösungsansatz für mich.

Gruß Ralf
Member: colinardo
Solution colinardo Feb 14, 2014 updated at 11:13:06 (UTC)
Goto Top
$infile = "D:\Ausgangsdatei.txt"  
$outpath = "D:\Uebermittlungsdateien"  
$zeichen = 855
$content = gc $infile | out-string
$length = ($content | measure -Character).Characters
$parts = 0
if($length -gt $zeichen){
  $parts = [int]($length/$zeichen)
}else{
  $parts = 1
  $zeichen = $length
}
for($i=0;$i -lt $parts;$i++){
  $file = $content.Substring($i*$zeichen,$zeichen).TrimEnd("`r`n")  
  [System.IO.File]::WriteAllText("$outpath\$(get-date -Format "yyyy-MM-dd")_$($i+1).txt",$file)  
}
Ansonsten poste doch mal einen Ausschnitt der Quelldatei (aber bitte mit CodeTags), oder schick so eine Datei mal via PM, damit wir hier nicht raten müssen...Danke.
Sind die Zeilenumbrüche zufällig die Trennung der Abschnitte?, dann könnte man das auch einfacher lösen ...
Grüße Uwe
Member: lexura
lexura Feb 14, 2014 at 11:11:19 (UTC)
Goto Top
Yes, bislang sieht es SUPER aus. KNIEFALL !!!
Sollte bei weiteren Tests noch etwas auffallen, melde ich mich nochmals hier.

DANKE DANKE DANKE !!!
Member: lexura
lexura Feb 17, 2014 at 10:41:59 (UTC)
Goto Top
Nochmals ein großen Dank an bastla und Uwe. Wir haben uns jetzt für die Powershell-Variante entschieden.
Seit heute läuft das fertige Script in unserer Produktionsumgebung einwandfrei.

Hier nochmals das finale Script:

$infile = "D:\Anwendungen\Eingang\Export.txt"
$outpath = "D:\Anwendungen\Ausgang\"
$zeichen = 885
$content = gc $infile | out-string
$length = ($content | measure -Character).Characters
$parts = 0
if($length -gt $zeichen){
$parts = [int]($length/$zeichen)
}else{
$parts = 1
$zeichen = $length
}
for($i=0;$i -lt $parts;$i++){
$file = $content.Substring($i*$zeichen,$zeichen).TrimEnd("`r`n")
[System.IO.File]::WriteAllText("$outpath\UTF-8_$(get-date -Format "yyyy-MM-dd")_$($i+1).txt",$file)
}