Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

เชี่ยวชาญ Input & Output (IO) ใน Ruby: คู่มือฉบับสมบูรณ์

I/O ย่อมาจาก Input/Output

โดย input (อินพุท) เราหมายถึงข้อมูลและข้อมูลทั้งหมดที่เข้ามาในสิ่งใดสิ่งหนึ่ง (คอมพิวเตอร์, เมธอด Ruby, สมองคุณ)

ตัวอย่างของ input:

  • ปุ่มที่คุณกดบนคีย์บอร์ด
  • การคลิกเมาส์
  • หนังสือที่คุณอ่าน

โดย output (เอาต์พุท) เราหมายถึงทุกอย่างที่ออกมาเป็นผลลัพธ์ของ input

ตัวอย่างของ output:

  • ผลลัพธ์ของ 1 + 1
  • การเขียนสรุปบทความที่คุณอ่าน
  • กาแฟ

ใน Ruby เมื่อเราพูดถึง i/o เรามักหมายถึงการอ่านไฟล์ การทำงานกับ network sockets และการพิมพ์ข้อมูลบนหน้าจอ

การทำความเข้าใจคลาส IO

IO ยังเป็นคลาสใน Ruby อีกด้วย

มันคือคลาสพาเรนต์ (parent class) สำหรับออบเจ็กต์อื่นๆ เช่น File และ Socket

ออบเจ็กต์ IO ทั้งหมดมีอันดับการดำเนินการเหล่านี้:

  • open / close
  • read
  • write

ออบเจ็กต์ IO พัฒนาบน file descriptors

ทุกกระบวนการ (process) ที่รันอยู่ในคอมพิวเตอร์ของคุณ มีตารางข้อมูลภายใน

ส่วนหนึ่งของตารางนี้รวมรายการ file descriptors

File descriptor คือ การแมปปิ้งระหว่างจำนวนเต็มและชื่อไฟล์

คุณสามารถดูรายการ file descriptors นี้ใน Linux ได้

ด้วยคำสั่งนี้:

# สมมติว่าคุณเปิด irb ไว้หน้าต่างอื่น
ls -lh /proc/`pgrep irb`/fd/
# lrwx------ 1 jesus jesus 64 Feb 3 15:54 0 -> /dev/pts/3
# lrwx------ 1 jesus jesus 64 Feb 3 15:54 1 -> /dev/pts/3
# lrwx------ 1 jesus jesus 64 Feb 3 15:54 2 -> /dev/pts/3

คุณสามารถสร้าง file descriptor ใหม่ใน Ruby ด้วยเมธอด sysopen

ตัวอย่าง:

fd = IO.sysopen('/dev/null', 'w') # 10

ตอนนี้คุณสามารถเปิดช่องทางการสื่อสารกับ file descriptor นี้ (10)

เช่นนี้:

io = IO.new(fd)

และเขียนลงไป:

io << 'orange'

สังเกตว่า IO ไม่สนใจว่า file descriptor ของคุณแมปไปที่ไฟล์จริง อุปกรณ์ (อย่างฮาร์ดดิสก์) หรือ network socket

วิธีเปิด File Descriptor สำหรับการเขียน

เมื่อคุณสร้าง file descriptor ใหม่ด้วย sysopen หรือเปิดไฟล์ด้วย File.open คุณมีตัวเลือกบางอย่าง

โดยค่าเริ่มต้น การสื่อสารเป็น read-only

คุณสามารถระบุโหมดได้:

  • r (อ่าน, ค่าเริ่มต้น)
  • w (เขียน)
  • w+ (อ่านและเขียน)
  • a (ผนวก/append)

ตัวอย่าง:

fd = IO.sysopen('/dev/tty1', 'w+')

สิ่งนี้เปิด /dev/tty1 ด้วยโหมดอ่าน + เขียน

3 สตรีม IO มาตรฐาน

เมื่อคุณเปิดโปรแกรมใหม่ (เอดิเตอร์, เทอร์มินัล, ตัวแปลภาษา Ruby, ฯลฯ) มันจะเปิดช่องทางการสื่อสาร 3 ช่องทางโดยค่าเริ่มต้น

3 file descriptors

พวกมันคือ:

  • stdin (อินพุท)
  • stdout (เอาต์พุท)
  • stderr (ข้อผิดพลาด)

ใน Ruby คุณสามารถเข้าถึงได้โดยตรง ใช้รูปแบบค่าคงที่ (constant form) หรือรูปแบบตัวแปร глобаль (global variable form)

ตัวอย่าง:

$stdout << "abc\n"

เมื่อคุณเขียนไปที่ $stdout มันเหมือนการเรียกเมธอด puts

Standard output ผูกมัดกับเทอร์มินัลของคุณ

lrwx------ 1 jesus jesus 64 Feb 3 15:54 0 -> /dev/pts/3

/dev/pts/3 นี้คืออุปกรณ์เสมือน (virtual device) ที่เทอร์มินัลอ่านเพื่อแสดงข้อความบนหน้าจอ

Standard error ใช้สำหรับ output เช่นกัน แตให้โอกาสเทอร์มินัลนำเสนอเนื้อหานี้แบบต่างออกไป เช่น ฟอนต์ใหญ่กว่า หรือสีต่างจากข้อความทั่วไป

คุณสามารถใช้เมธอด warn เพื่อพิมพ์ไปที่ standard error

Standard input คือที่ที่อินพุทผู้ใช้อ่านมา

คุณสามารถใช้เมธอด gets เพื่ออ่านจาก standard input

วิธี Flush STDOUT และปิด Buffering

ออบเจ็กต์ IO มี buffer ภายใน

ปริมาณข้อมูล อินพุทจะถูกเก็บไว้ก่อนที่จะอ่านได้

นั่นคือเหตุผลที่บางครั้งคุณใช้ puts...

แตไม่เห็นอะไรจนกว่าโปรแกรมจะจบ หรือ buffer เต็ม!

คุณสามารถปิด buffering ได้แบบนี้:

$stdout.sync = true

หรือคุณสามารถ flush buffer ด้วยมือ:

$stdout.flush

ด้วย buffer ปิด คุณจะเห็น output โดยไม่ต้องรอ

การอ่านเป็นชิ้นๆ (Chunks)

เมื่อคุณอ่านจากออบเจ็กต์ IO คุณ read จนกว่าสตรีมจะจบด้วยสัญญาณ END-OF-FILE (EOF) สตรีมถูกปิด หรือคุณรับจำนวนไบต์เฉพาะ

สำหรับการเขียนโปรแกรมเครือข่ายและไฟล์ใหญ่ การอ่านเป็นชิ้นเล็กๆ ช่วยได้

คุณสามารถอ่านเป็นชิ้นๆ ได้แบบนี้:

data = ""
until io.eof?
  data << io.read(2048)
end

ด้วยโค้ดนี้คุณสามารถประมวลผลข้อมูลเมื่อมันพร้อมได้ โดยไม่ต้องรอดาวน์โหลดทั้งหมดเสร็จ

สังเกตว่า eof? จะ "block" (บล็อก)

Blocking หมายถึงโค้ดของคุณจะไป นอนจนกว่า ระบบปฏิบัติการจะส่งสัญญาณว่ามี ข้อมูลใหม่ที่จะอ่าน

วิธีใช้ IO Pipes สำหรับการสื่อสารสองทาง

Ruby อนุญาตให้คุณสร้าง pipes

Pipe คือคู่ของ file descriptors ที่เชื่อมต่อกัน

นี่ใช้สำหรับ Inter-Process Communication (IPC)

ตัวอย่าง:

read, write = IO.pipe

คุณสามารถใช้กับเมธอด fork (ไม่มีใน Windows) เพื่อสร้างสำเนาของกระบวนการปัจจุบัน

สองกระบวนการนี้สามารถสื่อสารผ่าน pipe ได้

ตัวอย่าง:

if fork
  write.close
  puts "Message received: #{read.gets}"
  read.close
else
  read.close
  write << "Buy some bananas!"
  write.close
end

ซึ่งให้ผลลัพธ์:

# Message received: Buy some bananas!

วิธีใช้ Kernel Open Method

Ruby มีเมธอด open ที่ยืดหยุ่นมาก

มันอนุญาตให้คุณเปิดไฟล์ และอ่านข้อมูลจาก URL และแม้แต่อย่าง pipe เพื่อรันคำสั่งภายนอก

ตัวอย่าง:

open "abc.txt"

นั่นคือเหตุผลที่ เมธอดนี้ควรหลีกเลี่ยง

มันเป็นความเสี่ยงด้านความปลอดภัยที่มันทำได้ทั้งหมดนี้

แทนที่จะดีกว่าคือใช้เมธอด open เฉพาะที่คุณต้องการ

ตัวอย่าง:

File.open # File IO
IO.popen # Process open
URI.parse(...).open # URL open

ทั้งหมดนี้คืนค่าออบเจ็กต์ IO

สรุป

คุณได้เรียนรู้เกี่ยวกับ input/output ใน Ruby! คุณได้เรียนรู้เกี่ยวกับ file descriptors, คลาส IO, buffering, การอ่านเป็นชิ้นๆ และสตรีม IO มาตรฐาน

เชี่ยวชาญ Input & Output (IO) ใน Ruby: คู่มือฉบับสมบูรณ์

อย่าลืมแชร์บทความนี้ถ้าคุณชอบ

ขอบคุณที่อ่านครับ