Przejdź do zawartości

Koncepcje programowania/Wejście-wyjście pliku

Z Wikibooks, biblioteki wolnych podręczników.

Odczytywanie i zapisywanie plików[edytuj]

Wejście/wyjście plików (I/O) jest kluczowym elementem wielu języków programowania, który umożliwia programom odczytywanie i zapisywanie danych do iz plików w systemie plików komputera. W tym artykule przyjrzymy się, jak ogólnie działa plikowe operacje we/wy i jak można je zaimplementować w niektórych popularnych językach programowania.

Odczyt z pliku[edytuj]

Aby odczytać dane z pliku, program musi otworzyć plik, a następnie odczytać jego zawartość. Proces otwierania pliku zwykle obejmuje określenie jego nazwy i lokalizacji (tj. ścieżki do pliku) za pomocą deskryptora pliku. Deskryptor pliku to identyfikator, za pomocą którego program może uzyskać dostęp do danych pliku.

Po otwarciu pliku program może odczytać jego zawartość przy użyciu różnych technik, w zależności od języka i formatu danych. Ogólnie rzecz biorąc, program może odczytywać plik po jednym wierszu na raz, po jednym znaku na raz lub w dużych blokach danych.

Oto przykład, jak odczytać plik w Pythonie:

# Open the file for reading
with open('data.txt', 'r') as f:
    # Read the contents of the file
    data = f.read()
    # Print the data to the console
    print(data)

W tym przykładzie używamy wbudowanej funkcji open w Pythonie, aby otworzyć plik o nazwie „data.txt” w trybie odczytu („r”). Następnie używamy metody read, aby wczytać zawartość pliku do zmiennej o nazwie data. Na koniec drukujemy zmienną danych do konsoli.

Przykład w JavaScript:

const fs = require('fs');

// Read the file
fs.readFile('data.txt', 'utf8', (err, data) => {
  if (err) {
    console.error(err);
    return;
  }
  // Print the contents of the file to the console
  console.log(data);
});

W tym przykładzie używamy wbudowanego modułu fs w Node.js do odczytania pliku o nazwie „data.txt”. Przekazujemy opcję kodowania „utf8”, aby upewnić się, że plik zostanie odczytany jako ciąg znaków. Metoda readFile jako drugi argument przyjmuje funkcję wywołania zwrotnego, która jest wywoływana po odczytaniu pliku. Jeśli wystąpi błąd, drukujemy go na konsoli. W przeciwnym razie wypisujemy zawartość pliku do konsoli za pomocą funkcji console.log.

Przykład w elisp:

;; Open the file for reading
(with-temp-buffer
  (insert-file-contents "data.txt")
  ;; Get the contents of the file as a string
  (let ((data (buffer-string)))
    ;; Print the contents of the file to the message buffer
    (message "%s" data)))

W tym przykładzie używamy wbudowanej funkcji insert-file-contents w Elisp, aby wczytać plik o nazwie „data.txt” do tymczasowego bufora. Następnie pobieramy zawartość bufora jako ciąg znaków za pomocą funkcji buffer-string i przypisujemy ją do danych zmiennych. Na koniec wypisujemy zawartość pliku do bufora komunikatów za pomocą funkcji komunikatu.

Należy zauważyć, że w tym przykładzie założono, że plik „data.txt” znajduje się w bieżącym katalogu roboczym. Jeśli plik znajduje się gdzie indziej, musisz podać pełną ścieżkę do pliku.

Zapisywanie do pliku[edytuj]

Aby zapisać dane do pliku, program musi otworzyć plik do zapisu, a następnie zapisać dane do pliku. Podobnie jak w przypadku czytania pliku, otwieranie pliku do zapisu obejmuje określenie ścieżki do pliku i uzyskanie deskryptora pliku, którego można użyć do zapisania danych w pliku.

Gdy plik jest otwarty do zapisu, program może zapisywać do niego dane przy użyciu różnych technik, takich jak pisanie po jednym wierszu na raz, po jednym znaku na raz lub w dużych blokach danych.

Oto przykład zapisu do pliku w python:

# Open the file for writing
with open('output.txt', 'w') as f:
    # Write data to the file
    f.write("Hello, world!")

W tym przykładzie używamy wbudowanej funkcji open w Pythonie, aby otworzyć plik o nazwie „output.txt” w trybie zapisu („w”). Następnie używamy metody write do napisania łańcucha „Witaj, świecie!” do pliku. Na koniec zamykamy plik za pomocą instrukcji with, która automatycznie zamyka plik, gdy program skończy z niego korzystać.

Przykład w języku JavaScript:

const fs = require('fs');

// Write data to the file
fs.writeFile('output.txt', 'Hello, world!', (err) => {
  if (err) {
    console.error(err);
    return;
  }
  console.log('Data written to file successfully!');
});

W tym przykładzie używamy wbudowanego modułu fs w Node.js, aby napisać ciąg „Witaj, świecie!” do pliku o nazwie „output.txt”. Do zapisu danych do pliku używamy metody writeFile. Metoda przyjmuje jako trzeci argument funkcję wywołania zwrotnego, która jest wywoływana po zapisaniu danych do pliku. Jeśli wystąpi błąd, drukujemy go na konsoli. W przeciwnym razie wypiszemy komunikat o powodzeniu do konsoli.

Przykład w języku elisp:

;; Open the file for writing
(with-temp-file "output.txt"
  ;; Write data to the file
  (insert "Hello, world!"))

(message "Data written to file successfully!")

W tym przykładzie używamy wbudowanego makra with-temp-file w Elisp, aby otworzyć plik o nazwie „output.txt” do zapisu. Następnie używamy funkcji wstawiania, aby napisać ciąg „Witaj, świecie!” do pliku. Na koniec wypisujemy komunikat o powodzeniu do bufora komunikatów za pomocą funkcji komunikatu.

Należy zauważyć, że ten przykład zastępuje istniejącą zawartość pliku „output.txt”. Jeśli chcesz dołączyć dane do istniejącego pliku, możesz zamiast tego użyć makra with-open-file z argumentem :direction :append.

Zamykanie pliku[edytuj]

Po odczytaniu lub zapisie do pliku ważne jest, aby zamknąć plik, aby zwolnić wszelkie powiązane z nim zasoby systemowe. Niezamknięcie pliku może spowodować wycieki pamięci i inne problemy z wydajnością.

Wiele języków programowania zapewnia wbudowane funkcje lub metody zamykania pliku. Na przykład w Pythonie możemy użyć instrukcji with, aby automatycznie zamknąć plik, gdy program zakończy korzystanie z niego:

# Open the file for reading
with open('data.txt', 'r') as f:
    # Read the contents of the file
    data = f.read()
# The file is automatically closed when the `with` block ends

W tym przykładzie plik jest automatycznie zamykany po zakończeniu bloku with, nawet jeśli podczas odczytu pliku wystąpi wyjątek.

W JavaScript plik jest automatycznie zamykany po zakończeniu czytania lub pisania do niego. Nie musisz jawnie zamykać pliku.

Jednak zawsze dobrą praktyką jest zamykanie plików po zakończeniu pracy z nimi, zwłaszcza w innych językach programowania. Jeśli używasz biblioteki lub struktury, która zarządza plikami, postępuj zgodnie z wytycznymi dotyczącymi zamykania plików lub zwalniania zasobów.


W Elisp nie musisz jawnie zamykać pliku po odczytaniu lub zapisie do niego, ponieważ plik jest automatycznie zamykany po zabiciu bufora.

Jeśli jednak pracujesz z dużymi plikami lub długo działającymi skryptami, dobrą praktyką jest jawne zamykanie plików po zakończeniu pracy z nimi. Aby to zrobić, możesz wywołać funkcję kill-buffer na buforze powiązanym z plikiem:

;; Open the file for reading
(with-temp-buffer
  (insert-file-contents "data.txt")
  ;; Do something with the file
  ...
  ;; Close the file
  (kill-buffer))

W tym przykładzie używamy funkcji kill-buffer do zamknięcia bufora powiązanego z plikiem „data.txt” po zakończeniu wczytywania z niego. Zauważ, że ta funkcja nie usuwa samego pliku; zwalnia tylko zasoby powiązane z buforem. Jeśli chcesz usunąć plik, możesz użyć funkcji usuwania pliku.

Wniosek[edytuj]

Wejście/wyjście plików to ważny aspekt programowania, który umożliwia programom odczytywanie i zapisywanie danych do iz plików w systemie plików komputera. Rozumiejąc, jak używać funkcji we/wy plików w swoim języku programowania, możesz tworzyć zaawansowane aplikacje, które wchodzą w interakcję z zewnętrznymi źródłami danych i utrwalają dane do późniejszego wykorzystania.

Obsługa błędów[edytuj]

Praca z wejściem/wyjściem pliku może prowadzić do różnych błędów, takich jak między innymi nie znaleziono pliku, odmowa uprawnień i pełny dysk. Dlatego ważne jest, aby odpowiednio obsłużyć te błędy, aby uniknąć awarii programu lub spowodowania nieoczekiwanego zachowania.

W tym artykule omówimy podstawy obsługi błędów w plikach wejścia/wyjścia, w tym sposoby wykrywania i obsługi typowych błędów, które mogą wystąpić podczas odczytu lub zapisu do plików.

Wykrywanie błędów Pierwszym krokiem w obsłudze błędów jest wykrycie, kiedy wystąpi błąd. W większości języków programowania błędy związane z wejściem/wyjściem pliku są zwykle sygnalizowane przez wyjątek lub kod błędu. Dlatego konieczne jest użycie bloków try-catch lub instrukcji if-else do obsługi tych błędów.

Oto przykład użycia bloku try-catch do obsługi błędów wejścia/wyjścia pliku w Pythonie:

try:
    # Open the file
    file = open("myfile.txt", "r")

    # Read the data from the file
    data = file.read()

    # Close the file
    file.close()

except FileNotFoundError:
    print("File not found!")

except PermissionError:
    print("Permission denied!")

except:
    print("An error occurred!")

W tym przykładzie używamy bloku try-catch, aby otworzyć strumień plików, odczytać dane z pliku i zamknąć plik. Jeśli wystąpi błąd, na przykład nie znaleziono pliku lub odmowa dostępu, odpowiedni wyjątek jest przechwytywany i drukowany jest odpowiedni komunikat o błędzie.

Przykład w języku JavaScript:

const fs = require("fs");

try {
  // Open the file
  const file = fs.readFileSync("myfile.txt", "utf-8");

  // Print the data from the file
  console.log(file);

} catch (err) {
  if (err.code === "ENOENT") {
    console.log("File not found!");
  } else if (err.code === "EACCES") {
    console.log("Permission denied!");
  } else {
    console.log("An error occurred!");
  }
}

W tym przykładzie używamy bloku try-catch, aby odczytać plik i wydrukować jego zawartość. W przypadku wystąpienia błędu, takiego jak nieodnalezienie pliku lub odmowa zezwolenia, sprawdzany jest odpowiedni kod błędu i drukowany jest odpowiedni komunikat o błędzie.

Przykład w jezyku elisp:

;; Open the file
(with-temp-buffer
  (insert-file-contents "myfile.txt")

  ;; Print the data from the file
  (message "%s" (buffer-string)))

;; Handle errors
(condition-case err
    (with-temp-buffer
      (insert-file-contents "myfile.txt")

      ;; Print the data from the file
      (message "%s" (buffer-string)))

  (file-error (message "Error: %s" (error-message-string err)))))

W tym przykładzie używamy makra with-temp-buffer do odczytu z pliku i drukowania jego zawartości. Jeśli wystąpi błąd, na przykład plik nie zostanie znaleziony, zgłaszany jest warunek błędu pliku i drukowany jest odpowiedni komunikat o błędzie przy użyciu łańcucha komunikatów o błędach.

Po wykryciu błędu musimy odpowiednio go obsłużyć. Odpowiednia obsługa błędów zależy od typu błędu i specyficznych wymagań programu.

Oto kilka typowych sposobów radzenia sobie z błędami wejścia/wyjścia pliku:

Ponów operację: jeśli błąd jest tymczasowy, taki jak błąd zapełnienia dysku, możemy ponowić operację po pewnym opóźnieniu.

Rejestruj błąd: Możemy zarejestrować błąd w pliku lub bazie danych w celu dalszej analizy i debugowania.

Wyświetl komunikat dla użytkownika: Jeśli program posiada interfejs użytkownika, możemy wyświetlić użytkownikowi komunikat informujący o wystąpieniu błędu i sugerujący działania naprawcze.

Zakończ program: W niektórych przypadkach, takich jak błąd krytyczny, którego nie można naprawić, najlepiej jest zakończyć program, aby zapobiec dalszym uszkodzeniom lub utracie danych.

Najlepsze praktyki dotyczące obsługi błędów Oto kilka najlepszych praktyk, których należy przestrzegać podczas obsługi błędów wejścia/wyjścia pliku:

Używaj opisowych komunikatów o błędach: Komunikaty o błędach powinny być jasne i zawierać informacje, wskazując przyczynę błędu i sugerując działania naprawcze.

Łagodnie obsługuj błędy: Błędy należy obsługiwać w sposób, który nie powoduje awarii programu ani nie powoduje nieoczekiwanego zachowania.

Użyj bloków try-catch: Bloki try-catch powinny być używane do przechwytywania wyjątków związanych z wejściem/wyjściem pliku.

Prawidłowo zamykaj strumienie plików: Strumienie plików powinny być prawidłowo zamykane przy użyciu metody close, aby uniknąć wycieków zasobów.

Testowanie obsługi błędów: Obsługa błędów powinna zostać dokładnie przetestowana, aby upewnić się, że działa zgodnie z oczekiwaniami i nie wprowadza nowych błędów.

Podsumowując, obsługa błędów jest istotnym aspektem programowania wejścia/wyjścia pliku. Odpowiednio wykrywając i obsługując błędy, możemy zapewnić, że nasze programy są solidne i niezawodne oraz że będą nadal działać nawet w obliczu nieoczekiwanych błędów.