Anzeige
Anzeige
HERBERS
Excel-Forum (Archiv)
20+ Jahre Excel-Kompetenz: Von Anwendern, für Anwender
Inhaltsverzeichnis

CSV importieren, umwandeln, zusammenfassen

Forumthread: CSV importieren, umwandeln, zusammenfassen

CSV importieren, umwandeln, zusammenfassen
08.01.2018 10:00:50
Buchmann
Hallo zusammen,
ich komme leider nicht mehr weiter mit einem aktuellen Projekt.
Von Kollegen wurde ich gebeten, ein Makro zu schreiben, dass mehrere CSV Dateien einlesen kann und da dann eine bestimmte Zeile aus jeder CSV Datei in einem Tabellenblatt untereinanderschreibt.
Das habe ich auch hinbekommen. Allerdings musste ich das immer machen, da ich die Verzeichnisse in dem Makro direkt eingetragen hatte und keine andere Idee hatte, wie man das benutzerfreundlich machen kann...
Nun habe ich versucht, das Makro so umzubauen, dass auch ein Benutzer ohne VBA Kenntnisse diese Auswertung verwenden kann. Insbesondere ohne jedes Mal das Makro anpassen zu müssen.
Leider funktioniert es nicht.
Ich habe die CSV Dateien in einem separaten Makro in XLS Dateien umgewandelt und im zweiten Schritt die Zusammenführung der einzelnen XLS Dateien durchgeführt.
Hier das Makro für die Umwandlung:
Sub ConvertCSVtoXLSX2()
Dim strVerzeichnis As String
Dim strZielVerz As String
Dim strDatei As String
Dim strTyp As String
Dim strDateiname As String
Dim varFile As Variant
Dim iSubst, iCounter, iRow, iColumn As Integer
Dim strSourceFile, strTargetFile As String
Dim strBuffer, strFile, strPath, strCreateFile As String
Dim strBufferArray() As String
Dim objFso As Object
Dim FileExists As Boolean
Application.ScreenUpdating = False
strTyp = "*.csv"
strVerzeichnis = "C:\****\****\****\Prozessauswertung CSV Dateien\Test_ANSI\CSV\TEST-CSV\"
strZielVerz = "C:\****\****\****\Prozessauswertung CSV Dateien\Test_ANSI\CSV\TEST-CSV\XLSX\"
strDateiname = Dir(strVerzeichnis & strTyp)
Do Until strDateiname = ""
strSourceFile = strVerzeichnis & strDateiname
strTargetFile = strZielVerz & Split(strDateiname, ".")(0) & ".xls"
Set objFso = CreateObject("Scripting.FileSystemObject")
FileExists = objFso.FileExists(strSourceFile)
If FileExists Then
ActiveWorkbook.ActiveSheet.Cells.Clear
Open strSourceFile For Input As #1
iRow = 0
Do Until EOF(1)
iRow = iRow + 1
Line Input #1, strBuffer
If Application.International(xlDecimalSeparator) = "." Then
strBuffer = Replace(strBuffer, ",", ".")
Else
strBuffer = Replace(strBuffer, ".", ",")
End If
strBufferArray = Split(strBuffer, ";")
For iColumn = LBound(strBufferArray) To UBound(strBufferArray)
If IsNumeric(strBufferArray(iColumn)) Then
ThisWorkbook.Worksheets("Tabelle1").Range("A1").Offset(iRow - 1, iColumn). _
Value = CDbl(strBufferArray(iColumn))
Else
ThisWorkbook.Worksheets("Tabelle1").Range("A1").Offset(iRow - 1, iColumn). _
Value = strBufferArray(iColumn)
End If
Next iColumn
Loop
Close #1
Else
'Falls Datei nicht existiert
End If
Application.DisplayAlerts = False
ActiveWorkbook.SaveAs strTargetFile, xlWorkbookDefault
Application.DisplayAlerts = True
strDateiname = Dir
Loop
Application.ScreenUpdating = True
End Sub

Hier der Code für die Zusammenführung der einzelnen XLS-Dateien mit Herausziehen zweier einzelnen Zeilen aus den in XLS umgewandelten CSV-Dateien:
Sub CSV_Import()
Application.ScreenUpdating = False
Dim dateien, i
Dim owkb As Workbook
Dim Bereich As Range
Dim tstring As String
dateien = Application.GetOpenFilename("xls-Dateien (*.xls), *.xls", MultiSelect:=True)
If IsArray(dateien) Then
For i = 1 To UBound(dateien)
Workbooks.Open dateien(i), local:=True
Set owkb = ActiveWorkbook
With ThisWorkbook
'Benötigte Werte Auswählen und kopieren
ActiveSheet.Range("A47:AD47").Copy
Windows("02_****_CSV-Auswertung-Zeile47-48.xlsm").Activate
'Auswählen des Tabellenblatts in das die Werte kopiert werden sollen
Sheets("Zeile47").Select
Cells(i, 1).Select
ActiveSheet.Paste
End With
Application.CutCopyMode = False
owkb.Close False
Next i
End If
If IsArray(dateien) Then
For i = 1 To UBound(dateien)
Workbooks.Open dateien(i), local:=True
Set owkb = ActiveWorkbook
With ThisWorkbook
'Benötigte Werte Auswählen und kopieren
ActiveSheet.Range("A48:AD48").Copy
Windows("02_****_CSV-Auswertung-Zeile47-48.xlsm").Activate
'Auswählen des Tabellenblatts in das die Werte kopiert werden sollen
Sheets("Zeile48").Select
Cells(i, 1).Select
ActiveSheet.Paste
End With
Application.CutCopyMode = False
owkb.Close False
Next i
End If
Application.ScreenUpdating = True
End Sub

Der Versuch, diese beiden Makros zusammenzuführen hat an sich funktioniert. Allerdings habe ich versucht, die Verzeichniss über verschiedene Dialoge zu öffnen und damit weiter zu arbeiten. Allerdings funktioniert es nicht.
Hat jemand hier eine Idee, wie das vernünftig machbar ist?
Vielen Dank schon im Voraus!
Grüße,
Bastian
Anzeige

11
Beiträge zum Forumthread
Beiträge zu diesem Forumthread

Betreff
Datum
Anwender
Anzeige
AW:Problem: Folderauswahl?
08.01.2018 10:19:42
Phi
@Bastian
ist das Problem, dass ein in VBA unerfahrener User 2 Ordner auswählen können soll?
Der gezeigte Code könnte dann zusammengefasst werden.
Grüße
AW: AW:Problem: Folderauswahl?
08.01.2018 11:03:37
Buchmann
@Phi:
Das ist der Kern des Problems.
Ich habe es mit folgendem Makro versucht, allerdings scheitere ich daran, die über eine Function ausgewählten Verzeichnisse im Makro weiterverwenden zu können.
Hier mal der Code, soweit wie ich im Moment bin:

Option Explicit
Sub ConvertInsertSummarize()
Dim strVerzeichnis
Dim strVerzeichnis2 As String
Dim strZielVerz As String
Dim strZielVerz2 As String
Dim strDatei As String
Dim strTyp As String
Dim strDateiname
Dim strOrdnername
Dim varFile As Variant
Dim iSubst, iCounter, iRow, iColumn As Integer
Dim strSourceFile, strTargetFile As String
Dim strBuffer, strFile, strPath, strCreateFile As String
Dim strBufferArray() As String
Dim objFso As Object
Dim FileExists As Boolean
Application.ScreenUpdating = False
strTyp = "*.csv"
strVerzeichnis = GivePath
'strVerzeichnis = Application.GetOpenFilename(fileFilter:="Textdateien (*.csv), *.csv",  _
MultiSelect:=True)
strOrdnername = "\XLSX-DATA\"
MsgBox "Nun müssen Sie den Ordner für den Ablageort der XLS Dateien definieren. " & Chr(13) &  _
Chr(13) & _
"Den Ordner bitte in der nächsthöheren Ebene der CSV-Files erstellen."
strZielVerz2 = GivePath 'ZielVerzeichnis für XLS Dateien festlegen
strZielVerz = GivePath 'ZielVerzeichnis für Ergebnisdatei
'MsgBox strVerzeichnis
'MsgBox strVerzeichnis & strOrdnername
strDateiname = Dir(strVerzeichnis & strTyp)
Do Until strDateiname = ""
strSourceFile = strVerzeichnis & strDateiname
strTargetFile = strZielVerz & Split(strDateiname, ".")(0) & ".xls"
Set objFso = CreateObject("Scripting.FileSystemObject")
FileExists = objFso.FileExists(strSourceFile)
If FileExists Then
ActiveWorkbook.ActiveSheet.Cells.Clear
Open strSourceFile For Input As #1
iRow = 0
Do Until EOF(1)
iRow = iRow + 1
Line Input #1, strBuffer
If Application.International(xlDecimalSeparator) = "." Then
strBuffer = Replace(strBuffer, ",", ".")
Else
strBuffer = Replace(strBuffer, ".", ",")
End If
strBufferArray = Split(strBuffer, ";")
For iColumn = LBound(strBufferArray) To UBound(strBufferArray)
If (IsNumeric(strBufferArray(iColumn)) And (Not (iColumn = 31))) Then
ThisWorkbook.Worksheets("Tabelle1").Range("A1").Offset(iRow - 1, iColumn). _
Value = CDbl(strBufferArray(iColumn))
Else
ThisWorkbook.Worksheets("Tabelle1").Range("A1").Offset(iRow - 1, iColumn). _
NumberFormat = "@"
ThisWorkbook.Worksheets("Tabelle1").Range("A1").Offset(iRow - 1, iColumn). _
Value = "'" & strBufferArray(iColumn)
End If
Next iColumn
Loop
Close #1
Else
'Falls Datei nicht existiert
End If
Application.DisplayAlerts = False
ActiveWorkbook.SaveAs strTargetFile, xlWorkbookDefault
Application.DisplayAlerts = True
strDateiname = Dir
Loop
ActiveWorkbook.ActiveSheet.Cells.Clear
Application.ScreenUpdating = True
End Sub
Hier noch der Code der Function "GivePath"

Public Function GivePath() As String
Dim fDialog As FileDialog
Dim result As Integer
'Dateidialog für Auswahl
Set fDialog = Application.FileDialog(msoFileDialogFolderPicker)
On Error Resume Next
With fDialog
.AllowMultiSelect = False
.Title = "Ablagepfad für Excel-Dateien auswählen"
.Filters.Delete
.InitialFileName = "c:\Standardordner" & "\" 'Wichtig = "\"
result = .Show
If (result  0) Then
GivePath = Trim(.SelectedItems.Item(1))
Else
GivePath = ""
End If
End With
End Function
Ich habe beim Ursprungs-Makro die CSV Dateien über folgenden Befehl ausgewählt:

strVerzeichnis = Application.GetOpenFilename(fileFilter:="Textdateien (*.csv), *.csv",  _
MultiSelect:=True)
Da VBA aber mit dieser Auswahl bzw. über GetOpenFileName keinen String hat, auf den ich dann im Makro zugreifen kann, habe ich es so abgeändert:

strVerzeichnis = GivePath
Allerdings gibt Excel dann einen Fehler bei

strDateiname = Dir(strVerzeichnis & strTyp)
aus.
@Phi: Wie würdest du die beiden Makros zusammenfassen? Ich möchte das Makro so einfach und verständlich aufbauen, damit möglichst keine Fehler verursacht werden können und ich nicht jedes Mal den Kollegen dabei doch helfen muss...
Anzeige
AW: AW:Problem: Folderauswahl?
08.01.2018 11:54:40
Phi
Abgesehen davon, dass der Code etwas umständlich ist, ist alles vorhanden.
Hier eine Beispiel, der es Usern erlaubt, per Dialog viele CSV-Dateine auszuwählen, danach einen Ziel-Ordner für die Ergebnisse mit der Wahl, einen Unterordner anzulegen.
Wenn das passen sollte, kann man deinen Code (gekürzt) anfügen. Der gezegte Code ist schwer lesbar, ist es möglich eine CSV als Beispiel hochzuladen?

Sub Test()
Dim Fd As FileDialog
'CSV for Reading
Fd1 = Application.GetOpenFilename("csv-Dateien, *.csv", , , , True)
For i = 1 To UBound(Fd1) 'diese Dateien werden bearbeitet
Debug.Print Fd1(i)
Next i
out:
'Output Directory
With Application.FileDialog(msoFileDialogFolderPicker)
.AllowMultiSelect = False
.InitialFileName = "c:\temp\" ' "Nein" Then Debug.Print Fd2 & "\" & SubFolder 'hier wird das Ergebnis  _
gespeichert
End Sub
(Ausgabe ins Direktfenster der VB-Editors)
Grüße
Anzeige
AW: AW:Problem: Folderauswahl?
08.01.2018 12:59:45
Buchmann
@Phi:
Eine CSV-Datei kann ich dir leider nicht zur Verfügung stellen.
Im Grunde genommen stehen da alle Prozessparameter Zeilenweise drin, die bei der Fertigung eines Produktes entstehen.
Ist es notwendig, die CSV erst in eine .XLS Datei umzuwandeln oder gibt es da auch einfachere, elegantere Varianten?
Meinen Code kann ich doch bei deinem Vorschlag vor dem "End Sub" einfügen, damit es passt, oder?
Natürlich muss ich dann meine Ordnerauswahl rausnehmen, da das ja bei deinem Vorschlag passiert.
Vielen Dank nochmal :)
Anzeige
AW: Vorschlag
08.01.2018 13:42:38
Phi
Kopiere den Code in die Zieldatei und benennen ein Blatt, in dem alle Daten gesammelt werden mit "Ziel".
Die Auswahl der zu kopierenden Zellen muss angepassst werden.
Wenn alles passt, sollte in einem weiteren Blatt einige erklärenden Texte und eine Grafik, die bei Klick den Makro startet, eingefügt werden.

Sub iPhi()
Dim Fd As FileDialog
Dim ZielOrdner As String, SubOrdner As String
Einstellungen (False)
'CSV for Reading
inpCSV = Application.GetOpenFilename("csv-Dateien, *.csv", , , , True)
If Not IsArray(inpCSV) Then MsgBox "mehrere Dateien auswählen": Exit Sub
'Output Directory
With Application.FileDialog(msoFileDialogFolderPicker)
.AllowMultiSelect = False
.InitialFileName = "c:\temp\" ' "Nein" Then MkDir ZielOrdner & SubOrdner: ZielOrdner = uielordner & SubOrdner
'Debug.Print ZielOrdner  'hier wird das Ergebnis gespeichert
'CSV-Dateien einlesen
For i = 1 To UBound(inpCSV) 'diese Dateien werden bearbeitet
lr = Sheets("Ziel").Cells(Rows.Count, 1).End(xlUp).Row + 1
Sheets.Add , , , inpCSV(i)
'ActiveSheet.UsedRange.Copy Sheets("Ziel").Cells(lr, 1)
ActiveSheet.Range("B3").Copy Sheets("Ziel").Cells(lr, 1) '>>>>>>>>>
ActiveSheet.Delete
Next i
Einstellungen (True)
End Sub
Sub Einstellungen(ByVal flag As Boolean)
Application.ScreenUpdating = flag
Application.DisplayAlerts = flag
End Sub

Anzeige
AW: Vorschlag
08.01.2018 15:39:58
Buchmann
Hallo Phi,
an sich funktioniert das Makro sehr gut. Danke dafür.
Leider trennt Excel allerdings die CSV Dateien nicht auf. D.h. es steht die komplette Zeile in einer Zelle.
Was muss an dem Makro angepasst werden, damit die Werte (insgesamt sind es 35 Stück), die mit Semikolons getrennt sind, auch in die einzelnen Zellen geschrieben werden?
Anzeige
AW: Text-in-Spalten
08.01.2018 15:44:45
Phi
ohne dies ausprobieren zu können, ist dies nur raten. In jedem Fall muss vor dem Kopieren alles Notwendige gemacht werden, z.B. Text-in-Spalten. Das kann sehr gut mit dem Rekorder aufgezeichnet werden.
Grüße
AW: Text-in-Spalten
09.01.2018 08:32:04
Buchmann
Guten Morgen Phi,
das mit dem Trennen habe ich hinbekommen.
Nun noch eine Frage:
Ist es möglich, nach dem Import eine Messagebox auszugeben mit der Anzahl der CSV-Dateien, die importiert wurden?
Leider habe ich nicht herausgefunden, ob ich bei dem Befehl
inpCSV = Application.GetOpenFilename("csv-Dateien, *.csv", , , , True)

auch die Anzahl irgendwie herausfinden kann...
Danke dir!
Anzeige
AW: Ubound()
09.01.2018 09:33:32
Phi
ohne es noch einmal geprüft zu haben: Wegen der Mehrfachauswahl ins "inpCSV" ein Array, d.h. die Anzahl der Dateien ist

Application.StatusBar = ubound(inpCSV)
(da die msgbox den Ablauf unterbricht, setze ich sie sehr ungern ein)
AW: Ubound()
09.01.2018 13:16:56
Buchmann
Das hat funktioniert. Danke dir.
Nun habe ich noch eine Sache:
Wir haben in der CSV auch DMC Codes in Klarschrift stehen, aus denen Excel eine 4,012387E+20 macht.
Wie kann ich das beim Import der CSV Datei einrichten, dass diese Spalte als Text ausgegeben wird und dann dementsprechend der richtige Wert dort angezeigt wird?
Ich habe das Import-Prozedere einer CSV-Datei eben mit dem Makro-Recorder aufgezeichnet, aber da bin ich mir nicht sicher, wie ich das in den Code einbauen soll und ob das überhaupt machbar ist...
Hier der Code vom Import:
Sub CSVImportRecorded()
With ActiveSheet.QueryTables.Add(Connection:= _
"TEXT;C:\****\****\****\CSV\***************0090000033.csv" , Destination:=Range("$A$1")) _
.Name = "1055006150031710090000033"
.FieldNames = True
.RowNumbers = False
.FillAdjacentFormulas = False
.PreserveFormatting = True
.RefreshOnFileOpen = False
.RefreshStyle = xlInsertDeleteCells
.SavePassword = False
.SaveData = True
.AdjustColumnWidth = True
.RefreshPeriod = 0
.TextFilePromptOnRefresh = False
.TextFilePlatform = 65001
.TextFileStartRow = 1
.TextFileParseType = xlDelimited
.TextFileTextQualifier = xlTextQualifierDoubleQuote
.TextFileConsecutiveDelimiter = False
.TextFileTabDelimiter = False
.TextFileSemicolonDelimiter = True
.TextFileCommaDelimiter = False
.TextFileSpaceDelimiter = False
.TextFileColumnDataTypes = Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  _
1, 1, 1,_
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 1)
.TextFileTrailingMinusNumbers = True
.Refresh BackgroundQuery:=False
End With
End Sub

Anzeige
AW: Ratespiel
09.01.2018 13:37:34
Phi
Hallo,
mit QueryTables arbeite ich nicht, deswegen etwas raten:
Bei Text-in-Spalten kann man das Format angeben, der oben gezeigte String

.TextFileColumnDataTypes = Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  _
1, 1, 1,_
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 1)
könnte ähnlich sein: 1 für Zahlen, 2 für Text. Dann müßte man nur die Spalte abzählen und eine 2 eintragen.
(ohne es am Beispiel auszuprobieren sind Antworten immer etwas vage)
Anzeige

Beliebteste Forumthreads (12 Monate)

Anzeige
Anzeige
Anzeige