Access

  MS Access 2010+  |  Przetwarzanie plików  |   VBA 7.0

• Przetwarzanie plików.

„Przetwarzanie plików” - moje skromne uwagi.

Dla mnie szerokie zagadnienie „Przetwarzanie plików” jest zbyt szerokie by je opisać. Mnie praktycznie interesuje dostęp do plików w trybie odczytu i zapisu do plików binarnych. Dlatego też większość przykładów dotyczyć będzie odczytu i zapisu 24 bitowych bitmap *.bmp.
Pliki tekstowe stałej szerokości mnie nie interesują. Jeżeli chodzi o pliki tekstowe to spróbuję ułatwić sobie pisanie stron z przykładami - pliki *.html. Być może plik CSV jest godzien uwagi, ale MS Access dostarcza narzędzi do odczytu i zapisu tego typu plików. Nie mniej jednak sam zapis i odczyt pliku CSV jest prosty (czytaj nie jest mocno skomplikowany) więc być może stworzę jakiś przykładzik.

O pliku XML może będzie kiedyś. Temat ten zacząłem dość dawno temu, ale nie wiem kiedy temat uznam za skończony. Wstępnie opracowane dwa przykłady znajdują się na stronach:

  • Plik WMRODZ.xml zawiera wykaz rodzajów miejscowości i ich identyfikatorów
  • Plik TERC.xml zawiera wykaz identyfikatorów i nazw jednostek podziału terytorialnego

następne dwa przykłady są gdzieś na dysku

  • Plik SIMC.xml zawierający zbiór identyfikatorów i nazw miejscowości
  • Plik ULIC.xml zawierający zbiór identyfikatorów i nazw ulic.

ale dużo wody upłynie zanim przykłady te ujrzą światło dzienne .

Funkcja sprawdzająca argumenty otwarcia pliku.

Przed pobraniem zawartości pliku do zmiennej typu String bądź tablicy bajtów, lub zapisem danych do pliku powinniśmy wcześniej sprawdzić, czy operacja odczytu/zapisu jest możliwa. Wystąpić może kilka różnych przyczyn, które uniemożliwią nam odczytanie danych z pliku lub zapisanie danych do pliku.

Otwarcie pliku.

Plik możemy otworzyć za pomocą instrukcji Open opisanej na stronie Plik. Instrukcja Open.
W przypadku operacji odczytu danych z pliku, warunkiem koniecznym jest by plik istniał. Możemy to sprawdzić w bardzo łatwy sposób za pomocą wbudowanej funkcji Dir:

If Len(Dir(sFilePath)) > 0 Then => plik istnieje

  • W przypadku gdy plik sFilePath nie istnieje, a my chcemy wykonać operację
  • odczytu danych z nieistniejącego pliku, to za pomocą metody Raise obiektu Err powinniśmy wygenerować wtedy błąd wykonania o numerze 53 (File Not found), który będziemy musieli potem obsłużyć.
  • zapisu danych do pliku sFilePath, a plik nie istnieje, to plik zostanie utworzony jeśli tryb otwarcia pliku będzie typu Append, Binary, Output lub Random.

Aby sprawdzić, czy możemy odczytywać dane z pliku sFilePath spróbujmy go otworzyć w trybie dostępu binarnym (Binary) i do odczytu (Read).

Open sFilePath For Binary Access Read As #ff
    ' nie rób nic
Close #ff

Aby sprawdzić, czy możemy zapisywać dane do pliku sFilePath spróbujemy go otworzyć w trybie dostępu binarnymBinary do zapisu (Write).

Open sFilePath For Binary Access Write As #ff
    ' nie rób nic
Close #ff

  • Jeżeli otwierany w trybie do „Zapisu” plik ma ustawiony atrybut vbReadOnly generowany jest błąd wykonania o numerze 75 (Path/File access error). W takim przypadku nie będziemy mogli zapisać danych do takiego pliku.
  • Jeżeli otwierany do „Odczytu” lub „Zapisu” plik został wcześniej otwarty przez inny proces „Na wyłączność”, generowany jest błąd wykonania numerze 70 (Permission denied). W takim przypadku nie będziemy mogli odczytać, ani zapisać danych do takiego pliku.
  • Gdy otwierany plik został wcześniej otwarty przez inny proces, a podany tryb dostępu jest niedozwolony generowany jest błąd nr 55 (File already open). Dotyczy to trybu otwarcia pliku AppendOutput, dla których plik otwarty z innym numerem należy zamknąć.

Dodatkowe argumenty funkcji sprawdzającej

Aby uzyskać potrzebne dane z pliku, nie musimy odczytywać bezpośrednio całej zawartości pliku i ją przetwarzać w celu uzyskania potrzebnych danych. Dane z pliku możemy pobrać jednorazowo określając:

  • numer początkowego bajtu, znaku lub linii, od którego ma być dokonana operacja odczytu,
  • ilość bajtów, znaków, linii które mają być pobrane,
  • oraz w niektórych przypadkach powinniśmy określić znak końca linii. Dopuszczalny jest znak Chr$(13) lub vbNewLine (Chr$(13) & Chr$(10).

Pomocnicza funkcja sprawdzająca poprawność argumentów funkcji odczytujących i zapisujących dane do pliku.

⊗Public Function plikCheckArguments(ByVal sFilePath As String, _
                  ByVal fToWrite As Boolean, _
         Optional ByVal lStart As Long = 1, _
         Optional ByVal lCount As Long = -1, _
         Optional ByVal sCharsEnd As String = vbNewLine, _
         Optional ByVal sProcName As String = "") As Boolean
  • Pomocnicza funkcja plikCheckArguments (...) sprawdzająca poprawność argumentów funkcji odczytujących i zapisujących dane do pliku.
  • argumenty:
    • sFilePath
    • pełna ścieżka do pliku, na którym będzie wykonywana operacja zapis lub odczytu
      • dla operacji „Odczytu” plik sFilePath musi istnieć, w przeciwnym wypadku generowany jest błąd wykonania o numerze 53 (File Not found)
      • dla operacji „Zapisu” plik sFilePath nie może mieć atrybutu vbReadOnly. Gdy ma ustawiony atrybutu vbReadOnly, generowany jest wtedy błąd wykonania o numerze 75 (Path/File access error).
      • gdy plik sFilePath jest otwarty przez inny proces „Na wyłączność”, generowany jest błąd wykonania o numerze 70 (Permission denied)
      • gdy plik sFilePath został wcześniej otwarty przez inny proces, a podany tryb dostępu jest niedozwolony generowany jest błąd nr 55 (File already open). Dotyczy to trybu otwarcia pliku AppendOutput, dla których plik otwarty z innym numerem należy zamknąć.
    • fToWrite
    • argument określa tryb w jakim ma być otwarty plik sFilePath. Dla wartości True plik ma być otwarty w trybie „Do zapisu”. Dla wartości False plik ma być otwarty w trybie „Do odczytu”.
    • lStart
    • Domyślna wartość = 1. Numer początkowego bajtu (znaku, linii) od którego ma być dokonana operacja odczytu lub zapisu, Dla wartości argumentu lStart < 1 generowany jest błąd wykonania o numerze errInvalidStart = vbObjectError + err_plikError + 1, (err_plikError = 100)
    • lCount
    • Domyślna wartość = - 1. Ilość bajtów (znaków, linii) do operacji odczytu lub zapisu. Dla domyślnej wartości = -1 odczytane zostaną wszystkie bajty, (znaki, linie) od pozycji lStart. Wartość argumentu nie może być mniejsza od -1, ani równa Zero. Generowany jest wtedy błąd wykonania o numerze errInvalidCount = vbObjectError + err_plikError + 2, (err_plikError = 100)
    • sCharsEnd
    • argument nieobowiązkowy. Domyślna wartość = vbNewLine. Znak określający koniec linii. Dopuszczalny jest znak Chr$(13) lub vbNewLine (Chr$(13) & Chr$(10). Ewentualnie (przy zapisie) ciąg zerowej długości "". Dla innych wartości argumentu sCharsEnd generowany jest błąd wykonania o numerze errInvalidEnd = vbObjectError + err_plikError + 3, (err_plikError = 100)
    • sProcName
    • argument nieobowiązkowy. Domyślna wartość = "". nazwa funkcji wywołującej. W przypadku wywołania (wystąpienia) błędu przekazywana jest jako argument Source := sProcName metody Err.Raise. Jeżeli nazwa funkcji wywołującej nie zostanie przekazana, wartość argumentu sProcName ustawiana jest na nazwę bieżącej funkcji sProcName = conProcName, gdzie stała conProcName = "Funkcja plikCheckArguments(...)"
  • zwraca:
  • Przy powodzeniu zwraca True.
  • autor: Zbigniew Bratko
  • data: 11.01.2018
Option Compare Database
Option Explicit

'dolna granica zakresu numerów błędów dotyczących plików
Public Const err_plikError          As Long = 100
 
' plik nie istnieje
Public Const errFileNotFound     As Long = 53  ' File not found
' plik otwarty przez inny proces; podany tryb dostępu jest niedozwolony
Public Const errFileAlreadyOpen  As Long = 55  ' File already open
' Dostęp zabroniony. Plik został otwarty przez inny proces "Na wyłączność"
Public Const errPermissionDenied As Long = 70  ' Permission denied
' Plik ma ustawiony atrybut vbReadOnly. Nie jest możliwy zapis
Public Const errReadOnly         As Long = 75  ' Path/File access error
 
' Numer początkowy bajtu (znaku, linii), nie może być mniejszy niż 1
Public Const errInvalidStart     As Long = vbObjectError + err_plikError + 1
' Ilość bajtów (znaków, linii) do operacji odczytu lub zapisu
' nie może być mniejsza od -1, ani równa Zero
Public Const errInvalidCount     As Long = vbObjectError + err_plikError + 2
' Dopuszczalny jest znak Chr$(13) lub vbNewLine (Chr$(13) & Chr$(10).
' Ewentualnie (przy zapisie) ciąg zerowej długości ""
Public Const errInvalidEnd       As Long = vbObjectError + err_plikError + 3
 
Public Function plikCheckArguments(ByVal sFilePath As String, _
                                  ByVal fToWrite As Boolean, _
                                  Optional ByVal lStart As Long = 1, _
                                  Optional ByVal lCount As Long = -1, _
                                  Optional ByVal sCharsEnd As String = vbNewLine, _
                                  Optional ByVal sProcName As String = "") As Boolean
 
On Error GoTo Err_Handler
Dim ff                    As Integer
Const conProcName         As String = "Funkcja plikCheckArguments(...)"

	' nazwa funkcji wywołującej nie została przekazana,
	' ustaw nazwę na bieżącą funkcję
	If Len(sProcName) = 0 Then sProcName = conProcName
	 
	' jeżeli odczytujemy dane z pliku, to plik musi istnieć
	If fToWrite = False And Len(Dir(sFilePath)) = 0 Then
		Err.Raise errFileNotFound
	End If

	' sprawdź numer początkowy bajtu (znaku, linii) do odczytu
	If lStart < 1 Then Err.Raise errInvalidStart

	' sprawdź poprawność ilości bajtów (znaków, linii) do odczytu
	If lCount = 0 Or lCount < -1 Then Err.Raise errInvalidCount

	' sprawdź poprawność znaku końca linii
	If Len(sCharsEnd) > 0 Then
		If Not (sCharsEnd = Chr$(13) Or sCharsEnd = vbNewLine) Then
			Err.Raise errInvalidEnd
		End If
	Else
		' przy odczycie, końcem linii nie może być ciąg zerowej długości
		If fToWrite = False Then Err.Raise errInvalidEnd
	End If

	' plik istnieje - spróbuj go otworzyć do odczytu lub zapisu
	' gdy wystąpi błąd, zostanie on obsłużony w kodzie obsługi błędów
	If Len(Dir(sFilePath)) > 0 Then
		ff = FreeFile
		If fToWrite = True Then
			Open sFilePath For Binary Access Write As #ff
		Else
			Open sFilePath For Binary Access Read As #ff
		End If
		Close #ff
	End If
	 
	plikCheckArguments = True

	Exit_Here:
	Exit Function

	Err_Handler:
	Select Case Err.Number
		Case 0 ' nie ma błędu
		Case errFileNotFound
			Err.Raise errFileNotFound, sProcName, _
								"Plik " & sFilePath & "nie istnieje !"
		Case errFileAlreadyOpen
			Err.Raise errFileAlreadyOpen, sProcName, _
								"Plik " & sFilePath & vbNewLine & _
								"jest otwarty przez inny proces !"
		Case errPermissionDenied
			Err.Raise errPermissionDenied, sProcName, _
								"Brak dostępu do pliku " & sFilePath & vbNewLine & _
								"Plik jest otwarty na wyłączność !"
		Case errReadOnly
			Err.Raise errReadOnly, sProcName, _
								"Nie można zapisywać danych do pliku" & sFilePath & vbNewLine & _
								"Plik jest tylko do odczytu !"
		Case errInvalidStart
			Err.Raise errInvalidStart, sProcName, _
								"Niewłaściwa wartość argumentu lStart." & vbNewLine & _
								"Prawidłowo: [lStart] > 0"
		Case errInvalidCount
			Err.Raise errInvalidCount, sProcName, _
								"Niewłaściwa wartość argumentu lCount." & vbNewLine & _
								"Prawidłowo: [lCount = -1] lub [lCount > 0]"
		Case errInvalidEnd
			Err.Raise errInvalidEnd, sProcName, _
								"Niewłaściwa wartość argumentu sCharsEnd." & vbNewLine & _
								"Znakiem końca linii może być:" & vbNewLine & _
								" • vbCr = Chr(13)" & vbNewLine & _
								" • vbCrLf = Chr(13) & Chr(10)" & vbNewLine & _
								" • vbNewLine" & vbNewLine & _
								" • "" "" - ciąg zerowej długości (tylko przy zapisie do pliku)."
		Case Else
			Err.Raise Err.Number, sProcName, _
								"Nieprzewidziany błąd!" & vbNewLine & _
								Err.Description
	End Select
	Resume Exit_Here

End Function