Закрытие файлов и обработка ошибок
Корректно закрывайте файловые дескрипторы и обрабатывайте ошибки io с помощью pcall.
«Закрытие файлов и обработка ошибок» — бесплатный урок Lua Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Lua Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Lua Academy содержит 4 уроков всего.
Всегда закрывайте файлы
Каждый файл, открытый с помощью io.open, необходимо закрыть вызовом f:close(). Незакрытые файлы приводят к утечке файловых дескрипторов. Сборщик мусора Lua со временем закроет их, но до этого можно исчерпать ограничения OS на количество открытых файлов. Всегда закрывайте файл в той функции, которая его открыла.
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
Оборачивайте операции с файлами в pcall, чтобы перехватывать неожиданные ошибки: переполнение диска, отказ в разрешении во время записи и другие. Это позволяет корректно обрабатывать ошибки вместо аварийного завершения программы.
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Проверка успешности записи
В системах с заполненным диском или проблемами с разрешениями f:write() может завершиться ошибкой даже после успешного выполнения io.open. На критически важных участках проверяйте возвращаемое значение операций записи.
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")Шаблон finally с pcall
В Lua нет блока finally, но его можно имитировать с помощью pcall. Оберните потенциально опасный код в pcall, а после возврата pcall — независимо от успеха или ошибки — безусловно выполните очистку, прежде чем повторно вызвать ошибку или обработать её.
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)Сообщения об ошибках от io.open
io.open возвращает nil, сообщение системной ошибки и код ошибки. Сообщение содержит путь и причину ошибки OS («No such file», «Permission denied» и т. д.). Всегда включайте сообщение об ошибке в отчёт, который показываете пользователю.
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Дескриптор файла как объект
Дескриптор файла Lua — это userdata с методами. При сборке мусора для дескриптора файл автоматически закрывается. Однако не полагайтесь на сборщик мусора, если закрытие должно произойти вовремя: всегда закрывайте файл явно. Проверить, закрыт ли файл, можно с помощью f:read(): для закрытого дескриптора эта операция вызывает ошибку.
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]Шаблон безопасной обработки файлов
Универсальный шаблон безопасной обработки файлов: открыть файл с проверкой ошибки, выполнить обработку с помощью pcall, закрыть файл во всех случаях. Последовательно возвращайте результаты и ошибки, используя соглашение nil плюс сообщение.
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 и os.rename
os.remove(path) удаляет файл. os.rename(old, new) переименовывает или перемещает файл. При успехе обе функции возвращают true, а при ошибке — nil, errMessage. Это основные функции стандартного Lua для управления файловой системой.
-- 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 и f:close
io.close(f) эквивалентна f:close(). Вызов io.close() без аргумента закрывает файл вывода по умолчанию. В большинстве случаев используйте f:close() для большей ясности.
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Надёжное копирование файлов
Копирование файла для рабочего приложения с обработкой ошибок на каждом этапе: открыть исходный файл, открыть файл назначения, копировать данные блоками, обработать ошибки записи и закрыть оба файла.
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Быстрая проверка
Как лучше всего гарантировать, что файл в Lua всегда будет закрыт, даже если произойдёт ошибка?
Повторение: закрытие и обработка ошибок
Краткое резюме:
- Всегда явно вызывайте
f:close()— не полагайтесь на сборщик мусора - Оборачивайте операции ввода-вывода в pcall для надёжной обработки ошибок
- Используйте шаблон «открыть → pcall → закрыть»
- Применяйте
os.removeиos.renameдля операций с файловой системой - На критически важных участках проверяйте возвращаемые значения записи
Часто задаваемые вопросы
Урок «Закрытие файлов и обработка ошибок» бесплатный?
Да — полный текст урока «Закрытие файлов и обработка ошибок» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Lua Academy, подпишись на CoddyKit PRO. Курс Lua Academy содержит 4 уроков всего.
Чему я научусь в уроке «Закрытие файлов и обработка ошибок»?
Корректно закрывайте файловые дескрипторы и обрабатывайте ошибки io с помощью pcall. Ты практикуешь Lua Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Lua Academy?
Предыдущий опыт не требуется. Lua Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.
Сколько времени занимает урок «Закрытие файлов и обработка ошибок»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Lua Academy?
Да. Каждый урок Lua Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Открытие файлов с io.open
- Чтение содержимого файлов
- Запись и добавление в файлы
- Закрытие файлов и обработка ошибок