0Pricing
Lua Academy · บทเรียน

การปิดไฟล์และการจัดการข้อผิดพลาด

ปิดตัวจัดการไฟล์อย่างถูกต้องและจัดการข้อผิดพลาดของ io ด้วย pcall

การปิดไฟล์และการจัดการข้อผิดพลาด เป็นบทเรียน Lua Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 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 (เช่น "ไม่พบไฟล์ดังกล่าว" หรือ "ถูกปฏิเสธสิทธิ์") โปรดใส่ข้อความข้อผิดพลาดในรายงานข้อผิดพลาดที่แสดงต่อผู้ใช้เสมอ

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() อย่างชัดเจนเสมอ — อย่าพึ่งพาตัวเก็บขยะ
  • ห่อการทำงานกับ IO ด้วย pcall เพื่อการจัดการข้อผิดพลาดที่รัดกุม
  • ใช้แม่แบบ "เปิด → pcall → ปิด"
  • ใช้ os.remove / os.rename สำหรับการทำงานกับระบบไฟล์
  • ตรวจสอบค่าที่คืนจากการเขียนในโค้ดส่วนสำคัญ

คำถามที่พบบ่อย

บทเรียน “การปิดไฟล์และการจัดการข้อผิดพลาด” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การปิดไฟล์และการจัดการข้อผิดพลาด” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Lua Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Lua Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การปิดไฟล์และการจัดการข้อผิดพลาด”

ปิดตัวจัดการไฟล์อย่างถูกต้องและจัดการข้อผิดพลาดของ io ด้วย pcall คุณปฏิบัติ Lua Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Lua Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Lua Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน

บทเรียน “การปิดไฟล์และการจัดการข้อผิดพลาด” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Lua Academy นี้ได้ไหม

ได้ บทเรียน Lua Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. การเปิดไฟล์ด้วย io.open
  2. การอ่านเนื้อหาไฟล์
  3. การเขียนและเพิ่มข้อมูลลงไฟล์
  4. การปิดไฟล์และการจัดการข้อผิดพลาด
← กลับไปที่ Lua Academy