Przetwarzanie plików *.csv.
Czy pliki znajdują się dysku
Aby sprawdzić, czy pliki znajdują się na dysku skorzystamy z wbudowanej funkcji Dir.
Kolejno będziemy pobierali nazwy plików z katalogu TERYT i sprawdzali, czy pierwsze cztery znaki nazwy pliku pasują do poniższych wzorców:
"TERC" "SIMC" "ULIC" "WMRO". Jeżeli przedrostek jest zgodny, pełna nazwa pliku jest przypisywana do odpowiedniej zmiennej.
W przypadku obecności większej liczby plików z takim samym przedrostkiem pobrana zostanie nazwa ostatniego znalezionego pliku,
ale należy się spodziewać błędów przy wczytywaniu danych do tabel.
... ' utwórz ścieżkę do folderu TERYT z plikami pełnymi m_sAppPath = Application.CurrentProject.Path & "\TERYT\" ' pobierz nazwy plików z folderu TERYT sFileCsv = Dir(m_sAppPath) Do Until sFileCsv = "" 'tylko pliki z rozszerzeniem '.csv' If Right$(sFileCsv, 4) = ".csv" Then ' rozpoznaj pliki po 4 pierwszych znakach Select Case Left$(sFileCsv, 4) Case "SIMC" sFileSIMC = sFileCsv Case "TERC" sFileTERC = sFileCsv Case "WMRO" sFileWMRODZ = sFileCsv Case "ULIC" sFileULIC = sFileCsv Case Else End Select Debug.Print sFileCsv End If sFileCsv = Dir Loop ' muszą istnieć wszystkie pliki pełne rejestru TERYT If Len(sFileSIMC) = 0 Or Len(sFileTERC) = 0 Or _ Len(sFileWMRODZ) = 0 Or Len(sFileULIC) = 0 Then MsgBox "Katalog TERYT musi zawierać pliki:" & vbNewLine & _ " SIMC.csv" & vbNewLine & " TERC.csv" & vbNewLine & _ " WMRODZ.csv" & vbNewLine & " ULIC.csv", vbCritical Exit Sub End If ...
Usuwanie znacznika BOM.
Na początku każdego pobranego pliku *.csv znajduje się (może znajdować się)
znacznik BOM (Byte Order Mark). Jest to niedrukowalny (niewidoczny) znak używany
w wielobajtowym kodowaniu znaków, określający kolejności bajtów.
Znacznik BOM zapisywany jest na początku pliku i dla plików UTF-8 ma postać EF BB BF:
Chr$(&HEF) & Chr$(&HBB) & Chr$(&HBF) = 
Po otwarciu pliku i wczytaniu do bufora pierwszej linii pliku za pomocą instrukcji Line Input # sprawdzamy, czy trzy pierwsze znaki określają znacznik BOM. Jeżeli tak, to usuwamy te znaki z bufora i zmieniamy wartość zmiennej fBOM na True, by nie sprawdzać w następnych liniach obecności znacznika BOM.
... ' ustaw wartość znacznika BOM-Utf8 sBOM_Utf8 = Chr$(&HEF) & Chr$(&HBB) & Chr$(&HBF) ff = FreeFile Open sFilePath For Input As #ff ' czytaj po jednej linii do końca pliku Do While Not EOF(ff) Line Input #ff, sBuffer ' usuń znacznik BOM z pierwszej linii If fBOM = False Then If InStr(1, sBuffer, sBOM_Utf8, vbBinaryCompare) > 0 Then sBuffer = Mid(sBuffer, 4) End If fBOM = True End If ...
Konwersja tekstu z formatu UTF8 na format ASCII.
Pobrane pliki *.csv kodowane są w UTF-8 i po bezpośrednim pobraniu zawartości pliku do tabel otrzymamy niezbyt czytelny tekst. Poniżej przykładowe trzy pozycje pliku WMRODZ.csv:
- część = część
- wieĹ› = wieś
- przysiółek = przysiółek
Zagadnienie konwersji tekstu z formatu UTF-8 na format ASCII przedstawiłem na stronie: UTF8 »» ASCII.. Zaprezentowana tam funkcja tekstUTF8ToAscii(sUTF8 As String) As String konwertuje ciąg znaków z formatu UTF-8 na format Unicode (domyślną stroną kodową ASCII).
Option Compare Database Option Explicit #If VBA7 Then Private Declare PtrSafe Function MultiByteToWideChar Lib "kernel32" ( _ ByVal CodePage As Long, _ ByVal dwFlags As Long, _ ByVal lpMultiByteStr As String, _ ByVal cchMultiByte As Long, _ ByVal lpWideCharStr As LongPtr, _ ByVal cchWideChar As Long) As Long #Else Private Declare Function MultiByteToWideChar Lib "kernel32.dll" ( _ ByVal CodePage As Long, _ ByVal dwFlags As Long, _ ByVal lpMultiByteStr As String, _ ByVal cchMultiByte As Long, _ ByVal lpWideCharStr As Long, _ ByVal cchWideChar As Long) As Long #End If Private Const CP_UTF8 As Long = 65001 Public Function tekstUTF8ToAscii(sUTF8 As String) As String Dim lLenAscii As Long Const MB_ERR_INVALID_CHARS = 8 Const ERROR_INVALID_FLAGS = 1004 ' pobierz wielkość potrzebnego buforu na wyjściowy ciąg znaków ASCII lLenAscii = MultiByteToWideChar(CP_UTF8, 0&, sUTF8, Len(sUTF8), 0&, 0&) ' przygotuj bufor na przyjęcie ciągu po konwersji na Ascii tekstUTF8ToAscii = String$(lLenAscii, vbNullChar) ' konwertuj wejściowy ciąg na ASCII lLenAscii = MultiByteToWideChar(CP_UTF8, 0&, sUTF8, Len(sUTF8), _ StrPtr(tekstUTF8ToAscii), lLenAscii) End Function
Plik CSV
CSV (ang. Comma-S/eparated Values, wartości rozdzielone przecinkiem) – format przechowywania danych w plikach tekstowych. Poszczególne pola są oddzielone od siebie przecinkami (,), a każde z pól zajmuje tylko tyle miejsca, by pomieścić dane. Istnieje wiele implementacji standardu pliku w formacie CSV – wiele z nich nie trzyma się ściśle wszystkich określonych poniżej zasad.
- • Końce linii
- Poszczególne rekordy rozdzielone są znakami końca linii vbNewLine (vbCrLf).
- Ostatnia linia w pliku może nie zawierać znaku końca.
- Znak vbNewLine (vbCrLf) może być elementem pola, które musi wtedy być ujęte w cudzysłowy.
- • Separator
- Wartości pól zgodnie z nazwą formatu rozdzielone są przecinkami.
- Jako separator pól bywa także stosowany znak średnika ';' (lub inny zgodnie z ustawieniami regionalnymi systemu) albo tabulator, jednak jest to niezalecane. W jednym pliku może być użyty tylko jeden rodzaj separatora.
- • Cudzysłów
- Wartości pól mogą być ujęte w cudzysłowy.
- Wartości zawierające używany znak separatora (przecinek, średnik, znak tabulacji lub znaki końca linii) muszą być ujęte w cudzysłów.
- Aby w treści pola umieścić cudzysłów należy wpisać znak cudzysłowu dwukrotnie, całą wartość ujmując w cudzysłów.
- • Uwagi
- Spacje i inne białe znaki (w szczególności te przyległe do separatorów) należą do pól.
- Pierwsza linia może stanowić nagłówek zawierający nazwy pól rekordów, jednak pierwszy wiersz pliku CSV w/g standardu ma takie samo znaczenie jak pozostałe.
Filtr konwersji CSV z pakietu Microsoft Office pracuje przy założeniu, że plik CSV używa przecinka jako separatora, tymczasem Microsoft Excel i Access wyświetlają i zapisują plik CSV w formacie zgodnym z ustawieniami regionalnymi systemu, czyli w przypadku języka polskiego używa średnika, zamiast przecinka do rozdzielania pól. Aby umożliwić automatyczną konwersję, tworzone są dedykowane makra.
W oparciu o artykuł: Wikipedia. Plik csv
Czy pierwszy wiersz zawiera nazwy pól?
We wszystkich pełnych plikach Rejestru TERYT pierwszy wiersz zawiera trzyznakowy znacznik BOM (zazwyczaj niewidoczny w większości edytorów).
Za znacznikiem BOM znajdują się rozdzielone średnikami ';' nazwy poszczególnych pól.
Poniżej przedstawiam dwie pierwsze linijki pliku WMRODZ.csv:
 RM;NAZWA_RM;STAN_NA
00 część; 2013-02-28
Przy przetwarzaniu plików pełnych Rejestry TERYT mamy wcześniej przygotowane tabele, więc w trakcie wczytywania danych musimy pominąć pierwszą linię każdego pliku *.csv
Public Function fCsvWMRodzToTable(ByVal sFilePath As String, _ Optional ByVal sDelim As String = ";", _ Optional ByVal fFirstRowHasFieldNames As Boolean = True) As Boolean ... ff = FreeFile Open sFilePath For Input As #ff ' czytaj po jednej linii do końca pliku Do While Not EOF(ff) Line Input #ff, sBuffer ' nie uwzględniaj pustych wierszy pani Marysi (a takie się zdarzały) If Len(sBuffer) > 0 Then ' pierwszy pełny wiersz zawiera nazwy pól If fFirstRowHasFieldNames = True Then ' następne linie zawieraja już dane fFirstRowHasFieldNames = False Else ' konwertuj tekst z Utf8 na ASCII sBuffer = tekstUTF8ToAscii(sBuffer) ' rozdziel tekst względem separatora sFields() = Split(sBuffer, sDelim, , vbBinaryCompare) ...
Przeglądanie danych Rejestry TERYT.
W przykładowej bazie zamieściłem dodatkowe dwa formularze służące do przeglądania danych. Pierwszy z nich zawiera formant ComboBox za pomocą którego można wyświetlić dane w hierarchicznej strukturze drzewa TreeView. Więcej o formancie kombi w widoku TreeView znajdziesz na stronie Kombi w widoku TreeView
Rejestr TERYT. Pole kombi w widoku TrreeView
Drugi z formularzy zawiera pięć hierarchicznych (kaskadowych) pól kombi Wybór pozycji w pierwszym polu kombi, ogranicza możliwość wyboru w drugim polu kombi tylko do pozycji powiązanych z wybraną wcześniej pozycją. Po wyborze elementu w drugim polu kombi, lista pozycji w trzecim polu kombi zostaje ograniczona do pozycji należących do wybranego wcześniej elementu drugiego pola kombi itd. Więcej o powiązanych hierarchicznie polach kombi znajdziesz na stronie Hierarchicznie pola kombi
Rejestr TERYT. Hierarchiczne pola kombi