Lua Academy · Lekcja

Zamykanie plików i obsługa błędów

Proszę prawidłowo zamykać uchwyty plików i obsługiwać błędy io za pomocą pcall.

Lekcja 4 z 412 kroki

Zamykanie plików i obsługa błędów to bezpłatna lekcja Lua Academy na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Lua Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Lua Academy zawiera 4 lekcji w sumie.

Zawsze zamykaj pliki

Każdy plik otwarty za pomocą io.open należy zamknąć przy użyciu f:close(). Niezamknięte pliki powodują wycieki deskryptorów plików. Garbage collector Lua ostatecznie je zamknie, ale zanim to nastąpi, można wyczerpać limity plików systemu operacyjnego. Zawsze zamykaj plik w funkcji, która go otworzyła.

local function readFile(path)
  local f, err = io.open(path, "r")
  if not f then return nil, err end
  local content = f:read("a")
  f:close()   -- always close
  return content
end

local data, err = readFile("config.txt")
if not data then print("Error:", err) end

pcall dla bezpiecznej obsługi operacji wejścia-wyjścia

Owiń operacje na plikach w pcall, aby przechwytywać nieoczekiwane błędy (pełny dysk, odmowa dostępu w trakcie zapisu). Dzięki temu można poprawnie obsłużyć błędy zamiast doprowadzać do awarii programu.

local function safeCopy(src, dst)
  local ok, err = pcall(function()
    local f = io.open(src, "rb")
    if not f then error("Cannot open source: " .. src) end
    local content = f:read("a")
    f:close()
    local g = io.open(dst, "wb")
    if not g then error("Cannot open dest: " .. dst) end
    g:write(content)
    g:close()
  end)
  return ok, err
end

local ok, msg = safeCopy("input.txt", "output.txt")
if not ok then print("Failed:", msg) end

Sprawdzanie powodzenia zapisu

Na systemach z pełnym dyskiem lub problemami z uprawnieniami funkcja f:write() może się nie powieść, nawet jeśli io.open zakończyło się pomyślnie. W krytycznych fragmentach kodu należy sprawdzać wartości zwracane przez operacje zapisu.

local f = io.open("important.txt", "w")
if not f then
  print("Cannot create file")
  return
end

local ok, err = f:write("critical data\n")
if not ok then
  print("Write failed:", err)
  f:close()
  return
end

f:close()
print("Saved successfully")

Wzorzec finally z pcall

Lua nie ma bloku finally, ale można go zasymulować za pomocą pcall. Umieść ryzykowny kod w pcall, a po jego zakończeniu (niezależnie od powodzenia lub błędu) bezwarunkowo wykonaj kod sprzątający, zanim ponownie zgłosisz błąd lub go obsłużysz.

local function withFile(path, mode, fn)
  local f, err = io.open(path, mode)
  if not f then return nil, err end
  local ok, result = pcall(fn, f)
  f:close()   -- always close, even on error
  if not ok then
    return nil, result
  end
  return result
end

local content, err = withFile("data.txt", "r", function(f)
  return f:read("a")
end)
print(content or err)

Komunikaty błędów z io.open

io.open zwraca nil oraz systemowy komunikat błędu i kod błędu. Komunikat zawiera ścieżkę oraz przyczynę błędu systemu operacyjnego ("No such file", "Permission denied" itd.). W raporcie błędu dla użytkownika należy zawsze uwzględnić komunikat błędu.

local paths = {"config.txt", "missing.txt", "/root/secret.txt"}

for _, path in ipairs(paths) do
  local f, err, code = io.open(path, "r")
  if f then
    print(path, "-> ok, size:", f:seek("end"))
    f:close()
  else
    print(path, "-> ERROR:", err, "(code "..tostring(code)..")")
  end
end

Uchwyt pliku jako obiekt

Uchwyt pliku w Lua jest wartością userdata wyposażoną w metody. Po zebraniu uchwytu przez garbage collector plik jest automatycznie zamykany. Nie należy jednak polegać na garbage collectorze, jeśli plik ma zostać zamknięty w określonym czasie — zawsze zamykaj go jawnie. Można sprawdzić, czy plik jest zamknięty, wywołując f:read() — dla zamkniętego uchwytu wystąpi błąd.

local f = io.open("test.txt", "w")
f:write("test\n")

-- Explicit close
f:close()

-- After close, operations fail
local ok, err = pcall(function()
  f:read()   -- attempt to use closed file
end)
print(ok, err)   -- false  [closed file]

Bezpieczny szablon przetwarzania plików

Wielokrotnego użytku szablon bezpiecznego przetwarzania plików: otwórz plik i sprawdź błąd, przetwórz dane za pomocą pcall, a następnie zamknij plik w każdym przypadku. Zwracaj wyniki i błędy w spójny sposób, stosując konwencję nil+message.

local function processFile(path, processor)
  local f, err = io.open(path, "r")
  if not f then return nil, "open failed: " .. err end
  
  local ok, result = pcall(processor, f)
  f:close()
  
  if not ok then
    return nil, "processing failed: " .. result
  end
  return result
end

local lineCount, err = processFile("data.txt", function(f)
  local n = 0
  for _ in f:lines() do n = n + 1 end
  return n
end)
print(lineCount or err)

os.remove i os.rename

os.remove(path) usuwa plik. os.rename(old, new) zmienia nazwę pliku lub przenosi go. Obie funkcje zwracają true po pomyślnym wykonaniu albo nil, errMessage w przypadku błędu. Są to podstawowe funkcje standardowej Lua do operowania na systemie plików.

-- Delete a file
local ok, err = os.remove("temp.txt")
if not ok then print("Remove failed:", err) end

-- Rename / move
ok, err = os.rename("old_name.txt", "new_name.txt")
if not ok then print("Rename failed:", err) end

-- Atomic update pattern
os.rename("config.new", "config.txt")

io.close a f:close

io.close(f) jest równoważne f:close(). Wywołanie io.close() bez argumentu zamyka domyślny plik wyjściowy. W większości kodu należy używać f:close() dla większej czytelności.

local f = io.open("test.txt", "w")
f:write("hello\n")

-- Both are equivalent:
-- f:close()
io.close(f)

-- io.close() with no arg closes default output
io.output("out.txt")
io.write("to file\n")
io.close()   -- closes out.txt, restores stdout

Solidne kopiowanie plików

Kopiowanie pliku na poziomie produkcyjnym z obsługą błędów na każdym etapie: otwarcie źródła, otwarcie miejsca docelowego, kopiowanie partiami, obsługa błędów zapisu oraz zamknięcie obu plików.

local function copyFile(src, dst, chunkSize)
  chunkSize = chunkSize or 65536
  local fsrc, err1 = io.open(src, "rb")
  if not fsrc then return nil, err1 end
  local fdst, err2 = io.open(dst, "wb")
  if not fdst then fsrc:close(); return nil, err2 end
  
  local ok = true
  local chunk = fsrc:read(chunkSize)
  while chunk and ok do
    local w, werr = fdst:write(chunk)
    if not w then ok = false; err2 = werr end
    chunk = fsrc:read(chunkSize)
  end
  fsrc:close(); fdst:close()
  if not ok then os.remove(dst); return nil, err2 end
  return true
end

Szybkie sprawdzenie

Jaki jest najlepszy sposób, aby zagwarantować zamknięcie pliku w Lua nawet w przypadku wystąpienia błędu?

Podsumowanie: zamykanie i obsługa błędów

Podsumowanie:

  • Zawsze jawnie wywołuj f:close() — nie polegaj na garbage collectorze
  • Owijaj operacje wejścia-wyjścia w pcall, aby zapewnić solidną obsługę błędów
  • Używaj schematu "otwórz → pcall → zamknij"
  • os.remove / os.rename służą do operacji na systemie plików
  • W krytycznym kodzie sprawdzaj wartości zwracane przez operacje zapisu
Bezpłatny start

Ucz się Lua dzięki korepetycjom AI — za darmo

Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.

Kursy
40
Lekcje
159

Często zadawane pytania

Czy lekcja „Zamykanie plików i obsługa błędów” jest bezpłatna?

Tak — pełny tekst „Zamykanie plików i obsługa błędów” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Lua Academy, przejdź na CoddyKit PRO. Kurs Lua Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Zamykanie plików i obsługa błędów”?

Proszę prawidłowo zamykać uchwyty plików i obsługiwać błędy io za pomocą pcall. Ćwiczysz Lua Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Lua Academy?

Nie wymagamy żadnego doświadczenia. Lua Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.

Ile czasu zajmuje lekcja „Zamykanie plików i obsługa błędów”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Lua Academy?

Tak. Każda lekcja Lua Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Otwieranie plików za pomocą io.open
  2. Odczytywanie zawartości plików
  3. Zapisywanie i dopisywanie do plików
  4. Zamykanie plików i obsługa błędów
← Powrót do Lua Academy