Input/output with files
ในการเขียนโปรแกรมคอมพิวเตอร์ ในขณะที่โปรแกรมทำงานข้อมูลทั้งหมดนั้นถูกเก็บอยู่ในหน่วยความจำ เมื่อโปรแกรมทำงานเสร็จสิ้นหรือโปรแกรมถูกปิดลงข้อมูลเหล่านั้นก็จะหายไป อย่างไรก็ตาม เราสามารถบันทึกข้อมูลในโปรแกรมลงบนไฟล์ได้ การบันทึกข้อมูลลงบนไฟล์นั้นทำให้ข้อมูลถูกบันทึกลงดิสอย่างถาวร และเราสามารถอ่านข้อมูลเหล่านั้นมาใช้ในภายหลังได้
ในบทนี้ คุณจะได้เรียนรู้เกี่ยวกับการอ่านข้อมูลจากไฟล์และการเขียนข้อมูลลงไปบนไฟล์ในภาษา Ruby ในภาษา Ruby นั้นมีคลาสและเมธอดมาตรฐานเป็นจำนวนมากที่ให้เราสามารถทำงานกับไฟล์ได้ เช่น คลาส File
และ IO
เป็นต้น
การเปิดและปิดไฟล์
ก่อนที่เราจะอ่านข้อมูลจากไฟล์หรือเขียนข้อมูลลงไปบนไฟล์ สิ่งแรกที่เราจะต้องทำก็คือเปิดไฟล์ขึ้นมาก่อน ในภาษา Ruby เราสามารถเปิดไฟล์ด้วยเมธอด open
ซึ่งเป็นเมธอดที่อยู่ในคลาส File
นี่เป็นรูปแบบการเปิดไฟล์ด้วยเมธอดดังกล่าว
file = File.open(file_name, mode)
จากรูปแบบการเปิดไฟล์ file_name
นั้นเป็นชื่อของไฟล์ที่เราต้องการเปิด และ mode
นั้นเป็น String ที่ระบุโหมดการเปิดเพื่อบอกว่าเราต้องการเปิดไฟล์เพื่ออ่านหรือเขียน หรือทั้งสองอย่าง นี่เป็นรายการของโหมดทั้งหมดสำหรับการเปิดไฟล์
โหมด | คำอธิบาย |
---|---|
r | เปิดไฟล์เพื่ออ่านเท่านั้น เริ่มที่จุดเริ่มต้นของไฟล์ |
r+ | เปิดไฟล์เพื่ออ่านและเขียน เริ่มที่จุดเริ่มต้นของไฟล์ |
w | เปิดไฟล์เพื่อเขียนเท่านั้น สร้างไฟล์ใหม่ หรือถ้ามีไฟล์อยู่แล้วลบข้อมูลเดิมออก |
w+ | เปิดไฟล์เพื่ออ่านและเขียน สร้างไฟล์ใหม่ หรือถ้ามีไฟล์อยู่แล้วลบข้อมูลเดิมออก |
a | เปิดไฟล์เพื่อเขียนต่อท้าย สร้างไฟล์ใหม่ถ้าหากยังไม่มี |
a+ | เปิดไฟล์เพื่อเขียนต่อท้ายและอ่าน สร้างไฟล์ใหม่ถ้าหากยังไม่มี |
b | เปิดไฟล์ในโหมดไบนารีไฟล์ โหมดนี้จะใช้ร่วมกับโหมดด้านบน |
ค่าเริ่มต้นของการเปิดไฟล์นั้นจะถูกเปิดในโหมด Text ไฟล์เสมอ ยกเว้นแต่ว่าคุณระบุโหมดเป็น b
เพื่อเปิดไฟล์ในโหมดไบนารี มาดูตัวอย่างของการเปิดไฟล์ในรูปแบบต่างๆ
f1 = File.open("file1.txt", "r")
f2 = File.open("file2.txt", "w+")
f3 = File.open("data", "wb")
ในตัวอย่าง เราได้เปิดไฟล์สามไฟล์จากการเรียกใช้งานเมธอด open
สามครั้ง ซึ่งเมธอดนี้จะส่งค่ากลับเป็นออบเจ็คของไฟล์ที่เราสามารถนำไปใช้อ่านหรือเขียนข้อมูลบนไฟล์ได้ต่อไป
ในคำสั่งแรกในตัวแปร f1
นั้นเป็นการเปิดไฟล์ในรูปแบบ Text สำหรับอ่านข้อมูล ตัวแปร f2
เปิดไฟล์ในรูปแบบ Text สำหรับอ่านและเขียน และสุดท้ายตัวแปร f3
เป็นการเปิดไฟล์ในโหมดไบนารีสำหรับเขียนข้อมูล ในการเปิดไฟล์ในโหมดไบนารี โหมด b
นั้นต้องอยู่หลังจากโหมดปกติเสมอ
File.open("myfile.txt") # Current directory
File.open("../myfile.txt") # In parent directory
File.open("D:/Project/ruby/files/myfile.txt") # Absolute path
สำหรับการระบุชื่อของไฟล์เพื่อเปิดนั้น คุณสามารกำหนดแบบอ้างอิงจากไฟล์เดอร์ปัจจุบันหรือที่อยู่แบบเต็มของไฟล์ก็ได้ ดังตัวอย่างด้านบน
การอ่านข้อมูลจากไฟล์
หลังจากที่เราได้แนะนำเมธอดสำหรับการเปิดไฟล์ไปแล้ว ต่อไปมาดูตัวอย่างการอ่านไฟล์ในภาษา Ruby กัน เราจะเขียนโปรแกรมสำหรับอ่านไฟล์จาก myfile.txt
ซึ่งเป็น Text ไฟล์ และนำข้อมูลที่อ่านได้มาแสดงผลออกหน้าจอ และนี่เป็นตัวอย่างข้อมูลในไฟล์ของเรา
More and more I find myself wondering
if it's all worth fighting for.
For a feature without fear...
Yeah, it's worth it.
และนี่เป็นโค้ดของโปรแกรมสำหรับอ่าน Text ไฟล์ในภาษา Ruby
file = File.open("myfile.txt", "r")
while line = file.gets
puts line
end
file.close
ในตัวอย่างนั้นเป็นโค้ดสำหรับอ่านไฟล์ในภาษา Ruby ในตอนแรกเราได้เปิดไฟล์ myfile.txt
ด้วยเมธอด open
และกำหนดโหมดของการเปิดเป็น r
ซึ่งหมายความว่าเราต้องการเปิดไฟล์นี้เพื่ออ่านข้อมูล
while line = file.gets
หลังจากนั้นเราใช้เมธอด gets
เพื่ออ่านข้อมูลจากไฟล์ที่ละบรรทัด เมธอดนี้จะอ่านข้อมูลทีละบรรทัดและเก็บค่าที่อ่านได้ไว้ในตัวแปร line
และเราได้ใช้คำสั่ง while เพื่อวนอ่านไฟล์จนกว่าจะถึงจุดจบของไฟล์ (End of file หรือ EOF) และเมื่อถึงจุดจบของไฟล์ค่าที่ได้จากเมธอด gets
จะเป็น nil
และเราได้แสดงข้อมูลที่อ่านมาได้ออกทางหน้าจอ
file.close
ในตอนท้ายเราได้ปิดไฟล์ด้วยเมธอด close
เพื่อให้ไฟล์ระบบปฏิบัติการสามารถนำไปใช้กับโปรแกรมอื่นๆ ได้ต่อไป สิ่งที่สำคัญในการทำงานกับไฟล์ก็คือเราต้องปิดไฟล์เสมอเมื่อใช้งานเสร็จ
การเขียนข้อมูลลงไปบนไฟล์
หลังจากที่เราได้อ่านข้อมูลจากไฟล์เรียบร้อยแล้ว ต่อไปมาดูการเขียนข้อมูลลงไปบนไฟล์กันบ้าง การเขียนข้อมูลลงบนไฟล์นั้นจะช่วยให้เราสามารถบันทึกข้อมูลไว้ในไฟล์ และสามารถอ่านข้อมูลเหล่านั้นขึ้นมาใช้ในภายหลัง
ตัวอย่างของการเขียนไฟล์ก็คือเมื่อคุณพิมพ์งานที่โปรแกรมอย่าง Microsoft Word คุณสามารถบันทึกไฟล์งานของคุณเพื่อเปิดในภายหลังได้ หรือแม้กระทั่งเมื่อตอนที่คุณเล่นเกม คุณสามารถบันทึกสถานะของเกมที่คุณเล่น ทำให้คุณสามารถกลับมาเล่นต่อจุดเดิมได้
ดังนั้นในตัวอย่างของเราจะเป็นการเขียนข้อความง่ายๆ ลงไปบนไฟล์ นี่เป็นตัวอย่างการเขียนข้อมูลลงบน Text ไฟล์ในภาษา Ruby
file = File.open("myfile2.txt", "w")
file.puts("Thus the heavens and the earth,")
file.puts("and all the host of them, were finished.")
file.puts("And on the seventh day God ended His work")
file.close
ในตัวอย่าง เราได้เปิดไฟล์ myfile2.txt
ในโหมดสำหรับการเขียนข้อมูลลงไปบนไฟล์ ในการเปิดไฟล์ด้วยโหมดนี้ ถ้าหากมีไฟล์อยู่แล้วข้อมูลเดิมจะถูกลบออกและแทนที่ด้วยข้อมูลใหม่
file.puts("Thus the heavens and the earth,")
file.puts("and all the host of them, were finished.")
file.puts("And on the seventh day God ended His work")
หลังจากนั้นเราเขียนข้อมูลลงบนไฟล์ด้วยเมธอด puts
สำหรับการเขียนข้อมูลลงบนไฟล์ด้วยเมธอดนี้นั้น มันจะเพิ่มการขึ้นบรรทัดใหม่ (\n
) ให้อัตโนมัติ ซึ่งหมายความว่าเราได้เขียนข้อมูลลงบนไฟล์ทีละบรรทัดนั่นเอง
file.close
และเมื่อเขียนไฟล์เสร็จแล้ว อย่าลืมที่จะปิดไฟล์ด้วยเมธอด close
เสมอ หลังจากนั้นเปิดดูไฟล์ที่เราเพิ่งจะเขียนไป นี่จะเป็นข้อมูลที่อยู่ในไฟล์ myfile2.txt
Thus the heavens and the earth,
and all the host of them, were finished.
And on the seventh day God ended His work
การเขียนข้อมูลต่อท้ายไฟล์เดิม
ในตัวอย่างก่อนหน้านั้นเราได้เปิดไฟล์ด้วยโหมด w
นั่นหมายความว่าทุกครั้งที่โปรแกรมเปิดไฟล์ขึ้นมา มันจะลบข้อมูลเดิมเพื่อเขียนไฟล์ใหม่เสมอ ในบางครั้ง คุณอาจจะต้องการเขียนข้อมูลเพื่อต่อท้ายไฟล์เดิม โดยที่ข้อมูลเดิมยังอยู่ แน่นอนว่าคุณสามารถทำเช่นนั้นได้ด้วยการเปิดไฟล์ด้วยโหมดเขียนต่อท้ายนั่นเอง
print("Enter your note: ")
note = gets.chomp
file = File.open("mynote.txt", "a")
file.puts(note)
file.close
ในตัวอย่าง เป็นโปรแกรมบันทึกโน้ตหรือสิ่งที่เราอยากจะทำ ในโปรแกรมนั้นเราต้องการบันทึกสิ่งใหม่เพิ่มเข้าไปเรื่อยๆ โดยที่ข้อมูลเดิมที่เคยบันทึกก็ยังอยู่ ดังนั้นเราจึงเปิดไฟล์ด้วยโหมด a
เพื่อเขียนข้อมูลต่อท้ายไฟล์เดิม และไฟล์ใหม่จะถูกสร้างถ้าหากมันไม่มีอยู่
ทุกอย่างนั้นยังคงเหมือนเดิม เราได้เขียนข้อมูลลงบนไฟล์ด้วยเมธอด puts
และปิดไฟล์ด้วยเมธอด close
หลังจากที่เขียนข้อมูลเสร็จ
Enter your note: Hello World
Enter your note: Learning Ruby
Enter your note: Climbing in the weekend
นี่เป็นผลลัพธ์การทำงานของโปรแกรม เราได้รันโปรแกรมสามครั้งและกรอกโน้ตที่เราต้องการบันทึกลงไปบนไฟล์ ตอนนี้ให้คุณลองเปิดดูไฟล์ mynote.txt
เพื่อดูข้อมูลที่เรามี
การลบและการเปลี่ยนชื่อไฟล์
หลังจากที่เราสร้างไฟล์แล้ว ในบางครั้งเราก็อาจจะต้องการเปลี่ยนชื่อของไฟล์หรือลบไฟล์นั้นออกไปจากคอมพิวเตอร์ Ruby มีเมธอดสำหรับการเปลี่ยนชื่อและลบไฟล์ ซึ่งเมธอดเหล่านี้เป็นเมธอดที่มาจากคลาส File
File.rename("old_name", "new_name")
File.delete("myfile")
ในตัวอย่าง เมธอด rename
ใช้สำหรับเปลี่ยนชื่อไฟล์เดิมให้เป็นชื่อใหม่ ในตัวอย่างเราได้เปลี่ยนชื่อไฟล์ old_name
ให้เป็น new_name
ต่อมาเมธอด delete
นั้นใช้สำหรับลบไฟล์ออกไปจากคอมพิวเตอร์ของคุณ โดยระบุชื่อไฟล์ที่ต้องการลบให้กับเมธอด
ในการใช้งานเมธอดทั้งสองนั้นไฟล์จะต้องมีอยู่จริง ไม่เช่นนั้นจะเกิดข้อผิดพลาด Errno::ENOENT
ขึ้น อย่างไรก็ตาม เราสามารถใช้เมธอด exist?
เพื่อตรวจสอบว่ามีไฟล์อยู่ได้ นี่เป็นตัวอย่าง
print("Enter file name to delete: ")
file_name = gets.chomp
if File.exist?(file_name)
File.delete(file_name)
puts "#{file_name} has deleted"
else
puts "File #{file_name} does not exist"
end
ในตัวอย่าง โปรแกรมได้ถามให้กรอกชื่อไฟล์ที่ต้องการลบผ่านทางคีย์บอร์ด ก่อนลบไฟล์เราได้ตรวจสอบว่าไฟล์มีอยู่หรือไม่ด้วยเมธอด exist?
ซึ่งเมธอดนี้ส่งค่ากลับเป็น Boolean
Enter file name to delete: myfile.txt
myfile.txt has been deleted
นี่เป็นผลลัพธ์การทำงานของโปรแกรม
การจัดการข้อผิดพลาดเกี่ยวกับไฟล์
ในการทำงานกับไฟล์นั้นข้อผิดพลาดบางอย่างอาจเกิดขึ้นได้ ยกตัวอย่างเช่น การเปิดไฟล์ที่ไม่มีอยู่ การอ่านไฟล์ที่อ่านจบแล้ว หรือแม้กระทั่งการเขียนลงบนไฟล์ที่ปิดไปแล้ว ไม่ว่าจะด้วยเหตุผลใดก็ตาม ข้อผิดพลาดเหล่านี้สามารถทำให้โปรแกรมของเราหยุดทำงานได้
ในกรณีนี้ เราสามารถใช้คำสั่ง rescue
เพื่อตรวจสอบข้อผิดพลาดเหล่านั้นได้ถ้าหากมันเกิดขึ้น หลังจากนั้นเราสามารถจัดการกับข้อผิดพลาดที่เกิดขึ้นให้เหมาะสมกับโปรแกรมของเรา นี่เป็นตัวอย่าง
begin
file = File.open("myfile.txt", "r")
s = file.read
file.gets #=> nil
file.readline #=> EOFError: end of file reached
rescue EOFError => e
puts "No more line to read"
puts e.inspect
rescue => e
# Standard error
puts e.inspect
end
ในตัวอย่างนั้นเป็นโปรแกรมสำหรับอ่านข้อมูลจากไฟล์ myfile.txt
ที่เป็นไฟล์จากตัวอย่างแรกในบทนี้ ในตอนนี้ เราได้ใช้เมธอด read
ในการอ่านไฟล์ซึ่งเมธอดนี้อ่านข้อมูลของไฟล์ทั้งหมดเพียงครั้งเดียวมาเก็บไว้ในตัวแปร s
file.gets #=> nil
ต่อมาเราได้อ่านไฟล์อีกครั้งด้วยเมธอด gets
เนื่องจากข้อมูลในไฟล์ถูกอ่านหมดแล้ว ข้อมูลที่ได้จากเมธอดจึงเป็น nil
นั่นหมายความตัวชี้ไฟล์อยู่ที่ตำแหน่งสุดท้ายของไฟล์ หรือไม่มีข้อมูลเหลือให้อ่านแล้ว
file.readline #=> EOFError: end of file reached
หลังจากนั้นเราพยายามอ่านไฟล์อีกครั้งด้วยเมธอด readline
ในคำสั่งนี้นั้นทำให้เกิดข้อผิดพลาด EOFError
ขึ้นนั่นเป็นเพราะว่าสำหรับเมธอดนี้ถ้าหากเราพยายามอ่านไฟล์ที่อ่านเสร็จแล้ว มันจะส่งข้อผิดพลาดดังกล่าวขึ้นมา ซึ่งแตกต่างจากเมธอด gets
ที่จะส่งค่ากลับเป็น nil
แทน
begin
...
# Do something that may raise error
rescue
...
# Handle here
end
ดังนั้นในการที่จะป้องกันไม่ให้โปรแกรมหยุดทำงาน เราได้คำสั่ง begin
และ rescue
เข้ามาช่วย ซึ่งใโค้ดที่คาดว่าจะเกิดข้อผิดพลาดขึ้นจะเขียนไว้ในบล็อคของคำสั่ง begin
และเมื่อเกิดข้อผิดพลาดขึ้น โปรแกรมจะข้ามมาทำงานในบล็อคของคำสั่ง rescue
ที่ตรงกับประเภทของข้อผิดพลาดที่กำหนดไว้ในบล็อคทันที
No more line to read
#<EOFError: end of file reached>
และนี่เป็นผลลัพธ์การทำงานของโปรแกรม ที่เกิดข้อผิดพลาดขึ้นในกรณีที่เราอ่านไฟล์จากไฟล์ที่อ่านเสร็จ (End of file หรือ EOF) แล้ว
มาดูอีกตัวอย่างสำหรับการเปิดไฟล์ที่ไม่มีอยู่ ซึ่งสามารถทำให้เกิดข้อผิดพลากได้เช่นกัน
begin
file = File.open("notfound.txt", "r")
while line = file.gets
puts line
end
file.close
rescue Errno::ENOENT => e
# File does not exist
puts e.message
rescue => e
# Standard error
puts e.message
end
ในตัวอย่าง สมมติว่าโปรแกรมของเราพยายามเปิดไฟล์ที่ไม่มีอยู่ ถ้าหากเป็นเช่นนั้นโปรแกรมจะเกิดข้อผิดพลาด Errno::ENOENT
ขึ้น
rescue Errno::ENOENT => e
# File does not exist
puts e.message
ดังนั้นเราได้ใช้บล็อคคำสั่ง rescue เพื่อในการตรวจจับข้อผิดพลาดที่อาจจะเกิดขึ้น และภายในบล็อคของคำสั่ง rescue
เราสามารถแสดงข้อความบางอย่างเพื่อบอกกับผู้ใช้งานได้ ในตัวอย่าง เราได้แสดงข้อมูลของข้อผิดพลาดด้วยเมธอด message
จากออบเจ็ค Errno::ENOENT
No such file or directory @ rb_sysopen - notfound.txt
นี่เป็นผลลัพธ์การทำงานของโปรแกรม หลังจากที่เราพยายามเปิดไฟล์ที่ไม่มีอยู่
ในบทนี้ คุณได้เรียนรู้เกี่ยวกับการทำงานกับไฟล์ในภาษา Ruby เราได้พูดถึงการอ่านข้อมูลจากไฟล์และการเขียนข้อมูลลงบนไฟล์ พร้อมทั้งการเขียนข้อมูลต่อท้ายไฟล์เดิมในกรณีที่เราต้องการให้ข้อมูลเดิมยังอยู่ นอกจากนี้ เราได้พูดถึงการจัดการข้อผิดพลาดที่อาจจะเกิดขึ้นเมื่อทำงานกับไฟล์โดยการใช้คำสั่ง begin
และ rescue