Steuerzeichen per vbs aus txt-Datei entfernen
Hallo zusammen,
ich hab folgendes Problem. Ich exportiere aus einer MS-SQL Datenbank mit bcp eine csv-Datei.
Diese bearbeite ich dann noch mit einem vbs-Script um Zeilenumbrüche zu entfernen. Danach
wird die Datei über sqlldr in eine Oracle Datenbank importiert (alles per Batch).
Das Problem ist, daß in der csv-Datei immer noch Steuerzeichen (NUL bzw. hex 00) vorhanden
sind, mit denen der SQL Loader nich klar kommt.
Damit bin ich auf der Suche nach einer Möglichkeit per Script (vbs) diese Steuerzeichen zu
entfernen.
Bin für jeden Tip dankbar.
ich hab folgendes Problem. Ich exportiere aus einer MS-SQL Datenbank mit bcp eine csv-Datei.
Diese bearbeite ich dann noch mit einem vbs-Script um Zeilenumbrüche zu entfernen. Danach
wird die Datei über sqlldr in eine Oracle Datenbank importiert (alles per Batch).
Das Problem ist, daß in der csv-Datei immer noch Steuerzeichen (NUL bzw. hex 00) vorhanden
sind, mit denen der SQL Loader nich klar kommt.
Damit bin ich auf der Suche nach einer Möglichkeit per Script (vbs) diese Steuerzeichen zu
entfernen.
Bin für jeden Tip dankbar.
Bitte markiere auch die Kommentare, die zur Lösung des Beitrags beigetragen haben
Content-ID: 60677
Url: https://administrator.de/contentid/60677
Ausgedruckt am: 15.11.2024 um 21:11 Uhr
13 Kommentare
Neuester Kommentar
Hallo Eagle303 und willkommen im Forum!
Als eigenständige Lösung für den beschriebenen Zweck könnte das so aussehen:
Aufruf von der Befehlszeile oder aus einer Batchdatei (Annahme: gespeichert unter "C:\Scripts\EntNullen.vbs"):
Die Ausgangsdatei bleibt als Sicherungskopie mit dem zusätzlichen Typ ".bak" erhalten.
Unter der Annahme, dass man/frau/kind derartiges vielleicht öfter brauchen könnte, habe ich gleich weiter ausgeholt - in Dein bestehendes Script könntest Du etwas in der Art einbauen:
Grüße
bastla
[Edit] Löschen einer bereits vorhandenen Sicherungskopie hinzugefügt. [/Edit]
Als eigenständige Lösung für den beschriebenen Zweck könnte das so aussehen:
strToRemove = Chr(0)
If WScript.Arguments.Count < 1 Then
WScript.Echo "Bitte eine Textdatei als Argument übergeben!"
WScript.Quit(1)
Else
strInFile = WScript.Arguments(0)
End If
Set fso = CreateObject("Scripting.FileSystemObject")
If Not fso.FileExists(strInFile) Then
WScript.Echo "Die Datei " & strInFile & " wurde nicht gefunden!"
WScript.Quit(1)
End If
Set objInFile = fso.GetFile(strInFile)
strOutFile = objInFile.Path
If fso.FileExists(objInFile.Name & ".bak") Then fso.DeleteFile(objInFile.Name & ".bak")
objInFile.Name = objInFile.Name & ".bak"
fso.OpenTextFile(strOutFile,2, True).Write Replace(fso.OpenTextFile(objInFile.Path, 1).ReadAll, strToRemove, "")
cscript //nologo "C:\Scripts\EntNullen.vbs" "D:\NochMitNul.csv"
Unter der Annahme, dass man/frau/kind derartiges vielleicht öfter brauchen könnte, habe ich gleich weiter ausgeholt - in Dein bestehendes Script könntest Du etwas in der Art einbauen:
strNeueZeile = Replace(strAlteZeile, Chr(0), "")
Grüße
bastla
[Edit] Löschen einer bereits vorhandenen Sicherungskopie hinzugefügt. [/Edit]
@bastla
Hmmmm, ...ausnahmsweise Veto.
Mit Deinem Schnipsel erfüllst Du natürlich vordergründig die Anforderung Eagle303s (willkommen auch von mir BTW), aber die exportierte/importierte DB hat sich verändert.
@eagle303
Wenn Du, welcher Not auch immer gehorchend, den Weg über eine -csv gehst, um die Tabelleninhalte von A nach B zu bringen, dann musst Du auch dafür sorgen, dass NULL-Werte als solche erkannt, interpretiert und auch als NULL-Werte in die Tabellen-Kopie geschrieben werden.
Dazu musst Du ggf. beim Export die Spalten, die NULLABLE sind, einer Spezialbehandlung unterziehen (z.B. "SELECT ... CASE Telefon IS NULL THEN '<NULL>' Else Telefon as Telefon..) und entsprechend beim Import auch wieder aus einem Platzhalter '<NULL>' einen NULL-Wert machen...
Und die Werte, die z.B. Hex-Werte inclusive x00 enthalten können, eben auch als Text formatiert rausschreiben und beim Import rück-übersetzen.
Oder aber, Du verzichtest auf die pure Text-Ex/Importiererei und benutzt einen Dump.
Oder... es gibt doch im Jahre 2007 keine 2 DBs mehr, die sich nicht über ungünstigstenfalls ODBC miteinander connecten können, oder doch?
Grüße
Biber
Hmmmm, ...ausnahmsweise Veto.
Mit Deinem Schnipsel erfüllst Du natürlich vordergründig die Anforderung Eagle303s (willkommen auch von mir BTW), aber die exportierte/importierte DB hat sich verändert.
@eagle303
Wenn Du, welcher Not auch immer gehorchend, den Weg über eine -csv gehst, um die Tabelleninhalte von A nach B zu bringen, dann musst Du auch dafür sorgen, dass NULL-Werte als solche erkannt, interpretiert und auch als NULL-Werte in die Tabellen-Kopie geschrieben werden.
Dazu musst Du ggf. beim Export die Spalten, die NULLABLE sind, einer Spezialbehandlung unterziehen (z.B. "SELECT ... CASE Telefon IS NULL THEN '<NULL>' Else Telefon as Telefon..) und entsprechend beim Import auch wieder aus einem Platzhalter '<NULL>' einen NULL-Wert machen...
Und die Werte, die z.B. Hex-Werte inclusive x00 enthalten können, eben auch als Text formatiert rausschreiben und beim Import rück-übersetzen.
Oder aber, Du verzichtest auf die pure Text-Ex/Importiererei und benutzt einen Dump.
Oder... es gibt doch im Jahre 2007 keine 2 DBs mehr, die sich nicht über ungünstigstenfalls ODBC miteinander connecten können, oder doch?
Grüße
Biber
@Biber
Wo Du Recht hast, hast Du Recht: NULL != ""
Aber wenn's nun schon mal ein VB-Script gibt:
Grüße
bastla
Wo Du Recht hast, hast Du Recht: NULL != ""
Aber wenn's nun schon mal ein VB-Script gibt:
strNeueZeile = Replace(strAlteZeile, Chr(0), "<NULL>")
Grüße
bastla
*lach*...
Sorry, bastla,
da hast Du nun wieder Recht (und ich das Brett vorm Kopf). *gg
Aber dann wird der Import auch nicht ganz ohne Logik gehen können, es sei denn, es wäre bekannt, welchen String denn der SQL-Loader seinerseits in einen NULL-Wert übersetzt.
Wie geschrieben, Dein Script-Ansatz erfüllt ja alles (-->das, was ich immer süffisant als "...works as designed... bezeichne).
Aber ...bei aller Genügsamkeit, die wir M$-Endkunden gelernt haben:
Etwas Moderneres als Export/Import per .csv-Datei ist doch schon erfunden, oder nicht?
Gruss
Biber
Sorry, bastla,
da hast Du nun wieder Recht (und ich das Brett vorm Kopf). *gg
Aber dann wird der Import auch nicht ganz ohne Logik gehen können, es sei denn, es wäre bekannt, welchen String denn der SQL-Loader seinerseits in einen NULL-Wert übersetzt.
Wie geschrieben, Dein Script-Ansatz erfüllt ja alles (-->das, was ich immer süffisant als "...works as designed... bezeichne).
Aber ...bei aller Genügsamkeit, die wir M$-Endkunden gelernt haben:
Etwas Moderneres als Export/Import per .csv-Datei ist doch schon erfunden, oder nicht?
Gruss
Biber
@Biber
Grüße
bastla
Etwas Moderneres als Export/Import per .csv-Datei ist doch schon erfunden, oder nicht?
Und dann ganz ohne Batch oder Script? *schnief*Aber dann wird der Import auch nicht ganz ohne Logik gehen können ...
Ja nee, is klar, aber täte es nicht ein einfaches UPDATE?Grüße
bastla
@bastla
Klar, bastla, wenn die uns beide da ranlassen würden, dann würden wir die M$-SQL-Daten schneller in die Oracle 10g bekommen als ich "DataPumper" sagen könnte...
Mit Skript-Schnipseln, bissi Batch und generierten INSERT-Statements für 32 Mio Datensätze...
Und alle 5000 Datensätze ein COMMIT-Statement streu' ich auch noch rein...
Andererseits: wenn wir beide grad nicht vor Ort auf Feinheiten achten können, dann wären doch auch z.B. SQL-Clients, die mehr als eine Connection gleichzeitig aufmachen können eine etwas flexiblere Alternative.
So etwas wie "DBVisualizer" oder "SQLTools" oder "SQLWorkbench" oder oder oder...
Die beiden (physikalischen) Server werden doch wohl jeweils eine IP haben und einen Service am Fliegen...
...ja, muss ich denn auf meine alten Tage noch irgendwelche chr(0)'s aus Texten rausflöhen?
Gruß
Biber
Klar, bastla, wenn die uns beide da ranlassen würden, dann würden wir die M$-SQL-Daten schneller in die Oracle 10g bekommen als ich "DataPumper" sagen könnte...
Mit Skript-Schnipseln, bissi Batch und generierten INSERT-Statements für 32 Mio Datensätze...
Und alle 5000 Datensätze ein COMMIT-Statement streu' ich auch noch rein...
Andererseits: wenn wir beide grad nicht vor Ort auf Feinheiten achten können, dann wären doch auch z.B. SQL-Clients, die mehr als eine Connection gleichzeitig aufmachen können eine etwas flexiblere Alternative.
So etwas wie "DBVisualizer" oder "SQLTools" oder "SQLWorkbench" oder oder oder...
Die beiden (physikalischen) Server werden doch wohl jeweils eine IP haben und einen Service am Fliegen...
...ja, muss ich denn auf meine alten Tage noch irgendwelche chr(0)'s aus Texten rausflöhen?
Gruß
Biber
Hallo eagle303!
Obwohl ich eigentlich nicht muss, werde ich trotzdem versuchen, etwas zu Deinem Script beizutragen:
Unter der Annahme, dass deine ".cvs"-Datei ansonsten keine Leerzeilen enthält und Du sie bisher schon zeilenweise durchgehst, könntest Du das Schreiben in die neue Datei davon abhängig machen, dass die Zeile nicht leer ist:
Um auch Zeilen, die nur Leerstellen enthalten, auszuschließen, wäre noch ein zusätzliches "Trim()" möglich, also
Soll tatsächlich nur eine Zeilenschaltung (CRLF) ganz am Ende entfernt werden, könnte ein eigenes Script (gleich kombiniert mit dem Beispiel oben) so aussehen:
Grüße
bastla
Obwohl ich eigentlich nicht muss, werde ich trotzdem versuchen, etwas zu Deinem Script beizutragen:
Unter der Annahme, dass deine ".cvs"-Datei ansonsten keine Leerzeilen enthält und Du sie bisher schon zeilenweise durchgehst, könntest Du das Schreiben in die neue Datei davon abhängig machen, dass die Zeile nicht leer ist:
If Zeile <> "" Then objOutFile.WriteLine Zeile
If Trim(Zeile) <> "" Then objOutFile.WriteLine Zeile
'Ersetze alle
strToReplace = Chr(0)
'durch
strReplaceBy = "<NULL>"
'Schneide am Ende weg
strToCut = vbCrLF 'oder auch nur Chr(10)
intCutLen = Len(strToCut)
If WScript.Arguments.Count < 1 Then
WScript.Echo "Bitte eine Textdatei als Argument übergeben!"
WScript.Quit(1)
Else
strInFile = WScript.Arguments(0)
End If
Set fso = CreateObject("Scripting.FileSystemObject")
If Not fso.FileExists(strInFile) Then
WScript.Echo "Die Datei " & strInFile & " wurde nicht gefunden!"
WScript.Quit(1)
End If
Set objInFile = fso.GetFile(strInFile)
strOutFile = objInFile.Path
'Lösche alte Sicherungskopie
If fso.FileExists(objInFile.Name & ".bak") Then fso.DeleteFile(objInFile.Name & ".bak")
objInFile.Name = objInFile.Name & ".bak"
strFileText = fso.OpenTextFile(objInFile.Path, 1).ReadAll
strFileText = Replace(strFileText, strToReplace, strReplaceBy)
If Right(strFileText, intCutLen) = strToCut Then
strFileText = Left(strFileText, Len(strFileText) - intCutLen)
End If
fso.OpenTextFile(strOutFile, 2, True).Write strFileText
Grüße
bastla
Hallo, ich hab auch noch ne Frage
Ich will alle vbInformation's durch 64er ersetzen
Alle Exclamation durch 48 ersetzen.Bei mir geht das irgendwie net
Könnt ihr mir helfen?
Ich will alle vbInformation's durch 64er ersetzen
Alle Exclamation durch 48 ersetzen.Bei mir geht das irgendwie net
Könnt ihr mir helfen?
Hallo Yugius!
Empfehlen würde ich es Dir nicht - der Code ist mit den vbKonstanten eindeutig besser lesbar.
Wenn es in einem Einzelfall tatsächlich nötig erscheinen sollte, kannst Du ja im Editor ein "Suchen/Ersetzen" drüberlaufen lassen.
Ist das noch immer nicht in Deinem Sinn, dann eben nach obigem Muster:
Das Drumherum bleibt im Prinzip gleich.
Grüße
bastla
Empfehlen würde ich es Dir nicht - der Code ist mit den vbKonstanten eindeutig besser lesbar.
Wenn es in einem Einzelfall tatsächlich nötig erscheinen sollte, kannst Du ja im Editor ein "Suchen/Ersetzen" drüberlaufen lassen.
Ist das noch immer nicht in Deinem Sinn, dann eben nach obigem Muster:
strNeueZeile = Replace(strAlteZeile, "vbExclamation", "48")
Grüße
bastla
Ich dacht mir, das ich ein Skript drufziehe und Schwupps - ALles ist bearbeitet.
Es sind nicht nur die vbKonstanten.War nur ein Beispiel.
Könntst du mir den Gefallen tun und mir nochmal das gesamte Script posten.
Allein krieg ichs immer noch nicht hin ;)
Es sind nicht nur die vbKonstanten.War nur ein Beispiel.
Könntst du mir den Gefallen tun und mir nochmal das gesamte Script posten.
Allein krieg ichs immer noch nicht hin ;)
Hallo Yugius!
Wie gesagt: Eigentlich das Gleiche wie oben ...
"Schwupps" sollte jetzt klappen ...
Grüße
bastla
P.S.: Ich finde die Idee, benannte Konstanten zu ersetzen (auch wenn nur als Beispiel), weiterhin nicht gut.
Wie gesagt: Eigentlich das Gleiche wie oben ...
If WScript.Arguments.Count < 1 Then
WScript.Echo "Bitte eine Datei als Argument übergeben!"
WScript.Quit(1)
Else
strInFile = WScript.Arguments(0)
End If
Set fso = CreateObject("Scripting.FileSystemObject")
If Not fso.FileExists(strInFile) Then
WScript.Echo "Die Datei " & strInFile & " wurde nicht gefunden!"
WScript.Quit(1)
End If
Set objInFile = fso.GetFile(strInFile)
strOutFile = objInFile.Path
'Lösche alte Sicherungskopie
If fso.FileExists(objInFile.Name & ".bak") Then fso.DeleteFile(objInFile.Name & ".bak")
objInFile.Name = objInFile.Name & ".bak"
'Datei einlesen
strFileText = fso.OpenTextFile(objInFile.Path, 1).ReadAll
'ab hier die Ersetzungen
strFileText = Replace(strFileText, "vbExclamation", "48")
strFileText = Replace(strFileText, "vbInformation", "64")
'strFileText = Replace(strFileText, .....
'Datei schreiben
fso.OpenTextFile(strOutFile, 2, True).Write strFileText
Grüße
bastla
P.S.: Ich finde die Idee, benannte Konstanten zu ersetzen (auch wenn nur als Beispiel), weiterhin nicht gut.