โมดูล `io` ในภาษาไพธอน
บทความนี้อธิบายเกี่ยวกับโมดูล io ในภาษาไพธอน
เราจะอธิบายโมดูล io ในภาษาไพธอนพร้อมตัวอย่างการใช้งานจริง
YouTube Video
โมดูล io ในภาษาไพธอน
การประมวลผลข้อมูลขาเข้า/ขาออก (I/O) เป็นรากฐานของการทำงานกับข้อมูลทุกรูปแบบ เช่น ไฟล์ เครือข่าย และ I/O มาตรฐาน โมดูล io ของไพธอนมีคลาสนามธรรม (abstract classes) ที่รวมการประมวลผลข้อมูลขาเข้า/ขาออกเหล่านี้ไว้ด้วยกัน แนวคิดสำคัญในการเข้าใจโมดูลนี้ คือแนวคิดเรื่อง "สตรีม (stream)"
สตรีมคืออะไร?
สตรีมคือการไหลของข้อมูลที่เป็นนามธรรมสำหรับการอ่านและเขียนข้อมูลแบบต่อเนื่องตามลำดับ
ไม่ว่าจะอ่านข้อมูลไฟล์ทีละไบต์หรือส่งและรับข้อมูลผ่านเครือข่าย สิ่งเหล่านี้สามารถจัดการในรูปแบบของ data stream ได้ทั้งหมด
ด้วยการทำให้อุปกรณ์เหล่านี้เป็นนามธรรมขึ้น เราจึงสามารถจัดการกับไฟล์, หน่วยความจำ และเครือข่าย (ซึ่งเป็นแหล่ง I/O ต่างชนิดกัน) ด้วยการดำเนินการพื้นฐานเช่น การอ่านและเขียนในรูปแบบเดียวกัน
โมดูล io ของไพธอนมีส่วนติดต่อเดียวสำหรับสตรีม ทำให้สามารถจัดการข้อมูลทั้งแบบข้อความและข้อมูลเลขฐานสองได้อย่างมีประสิทธิภาพ
โครงสร้างพื้นฐานของโมดูล io
โมดูล io มีโครงสร้างเป็นสามชั้นตามธรรมชาติของสตรีม
-
เลเยอร์ Raw (
RawIOBase)RawIOBaseจัดการ I/O ระดับไบต์ที่ต่ำที่สุด เช่นตัวรับไฟล์ของระบบปฏิบัติการและอุปกรณ์ -
เลเยอร์ Buffered (
BufferedIOBase)BufferedIOBaseมีแคช (buffer) สำหรับช่วยเพิ่มประสิทธิภาพในการทำงาน I/OBufferedReaderและBufferedWriterเป็นตัวอย่างที่พบได้บ่อย -
เลเยอร์ Text (
TextIOBase)TextIOBaseแปลงลำดับไบต์เป็นสตริงและจัดการการเข้ารหัส โดยปกติเมื่อเปิดไฟล์ด้วยฟังก์ชันopen()จะใช้TextIOWrapperที่อยู่ในเลเยอร์นี้
ด้วยโครงสร้างนี้ โมดูล io สามารถแยกการจัดการข้อมูลแบบข้อความและข้อมูลเลขฐานสอง (binary) ออกจากกัน พร้อมทั้งรองรับการนำไปใช้ร่วมกันได้อย่างยืดหยุ่น
โครงสร้างพื้นฐานของโมดูล io
RawIOBase จัดการตัวรับไฟล์ของระบบปฏิบัติการที่เลเยอร์ล่างสุด, มี BufferedIOBase ซึ่งเป็นตัวแคชในชั้นถัดขึ้นไป และ TextIOBase ที่เลเยอร์บนสุดสำหรับแปลงเป็นสตริง
1import io
2
3# Check the core base classes hierarchy
4print(io.IOBase.__subclasses__())- โค้ดนี้ใช้ตรวจสอบกลุ่มคลาสนามธรรมที่สืบทอดมาจาก
IOBaseคุณจะเห็นTextIOBase,BufferedIOBaseและRawIOBaseซึ่งแสดงถึงโครงสร้างเป็นลำดับชั้น
io.IOBase: คลาสพื้นฐานของทุกคลาส
IOBase เป็นคลาสนามธรรมพื้นฐานของอ็อบเจ็กต์ I/O ทั้งหมด โดยกำหนดเมธอดหลักๆ เช่น close(), flush(), และ seekable() ปกติเราจะไม่ใช้งานโดยตรง แต่จะเข้าถึงผ่านคลาสที่สืบทอด
1import io
2
3f = io.StringIO("data")
4print(f.seekable()) # True
5print(f.readable()) # True
6print(f.writable()) # True
7f.close()- ตัวอย่างนี้แสดงให้เห็นว่าเมธอดหลักๆ ใน
IOBaseสามารถใช้ได้ในคลาสระดับสูงที่สืบทอดมาseekable()และreadable()มีประโยชน์สำหรับการตรวจสอบคุณสมบัติของสตรีม
io.RawIOBase: เลเยอร์ระดับต่ำสุด
RawIOBase เป็นเลเยอร์ที่ใกล้กับตัวรับไฟล์ของระบบปฏิบัติการมากที่สุด และไม่ได้ทำการบัฟเฟอร์ ตัวอย่างการใช้งานที่พบได้ทั่วไปคือ FileIO ซึ่งเป็นคลาสสำหรับอ่านและเขียนทีละไบต์
1import io, os
2
3# Create a low-level FileIO object (no buffering)
4fd = os.open('raw_demo.bin', os.O_RDWR | os.O_CREAT)
5raw = io.FileIO(fd, mode='w+')
6raw.write(b'abc123')
7raw.seek(0)
8print(raw.read(6)) # b'abc123'
9raw.close()FileIOเป็นคลาสที่ใช้งานได้จริงจากRawIOBaseโดยทุกคำสั่งอ่านและเขียนจะทำงานกับข้อมูลในรูปแบบbytesสามารถเพิ่มประสิทธิภาพได้โดยนำไปรวมกับเลเยอร์BufferedIOBaseที่สูงขึ้น
io.BufferedIOBase: เลเยอร์กลาง (มีบัฟเฟอร์)
BufferedIOBase เป็นเลเยอร์กลางที่ทำหน้าที่บัฟเฟอร์ข้อมูลเพื่อเพิ่มประสิทธิภาพในการเข้าถึงดิสก์ คลาสที่นำมาประยุกต์ใช้หลักๆ ได้แก่ BufferedReader, BufferedWriter, BufferedRandom และ BufferedRWPair
1import io
2
3# Create a buffered binary stream on top of a BytesIO (simulate file)
4base = io.BytesIO()
5buffered = io.BufferedWriter(base)
6buffered.write(b'Python IO buffering')
7buffered.flush()
8base.seek(0)
9print(base.read()) # b'Python IO buffering'- ในตัวอย่างนี้ ข้อมูลที่เขียนผ่าน
BufferedWriterจะเก็บไว้ในบัฟเฟอร์หน่วยความจำชั่วคราว และจะถูกส่งลงไปที่เลเยอร์ล่างก็ต่อเมื่อมีการเรียกflush()
ตัวอย่างของ BufferedReader
BufferedReader เป็นสตรีมบัฟเฟอร์สำหรับอ่านอย่างเดียวที่รองรับการอ่านข้อมูลอย่างมีประสิทธิภาพด้วย peek() และ read()
1import io
2
3stream = io.BytesIO(b"1234567890")
4reader = io.BufferedReader(stream)
5print(reader.peek(5)) # b'12345' (non-destructive)
6print(reader.read(4)) # b'1234'
7print(reader.read(3)) # b'567'peek()เพียงแค่ดูข้อมูลโดยไม่ขยับตัวชี้ตำแหน่งข้อมูล สามารถควบคุมการบัฟเฟอร์ข้อมูลได้อย่างยืดหยุ่นโดยการใช้งานร่วมกับread()
io.TextIOBase: เลเยอร์สำหรับข้อความเท่านั้น
TextIOBase เป็นชั้นนามธรรมสำหรับจัดการสตริง โดยภายในจะทำการถอดรหัสและเข้ารหัสข้อมูล ตัวอย่างคลาสที่พบได้บ่อยคือ TextIOWrapper
1import io
2
3# Wrap a binary stream to handle text encoding
4binary = io.BytesIO()
5text_stream = io.TextIOWrapper(binary, encoding='utf-8')
6text_stream.write("\u3053\u3093\u306B\u3061\u306F")
7text_stream.flush()
8
9# Reset stream position
10binary.seek(0)
11
12# Read bytes once
13data = binary.read()
14
15# Show both raw bytes and decoded text
16print("Raw bytes:", data)
17print("Decoded text:", data.decode('utf-8'))- ในตัวอย่างนี้
TextIOWrapperจะเข้ารหัสสตริงเป็น UTF-8 แล้วเขียนลงในสตรีมไบนารี่ด้านล่าง
ตัวอย่างการอ่านข้อมูลด้วย TextIOWrapper
การแปลงรหัสจะทำงานอัตโนมัติเมื่ออ่านข้อมูล
1import io
2
3binary_data = io.BytesIO("Python I/O".encode('utf-8'))
4text_reader = io.TextIOWrapper(binary_data, encoding='utf-8')
5print(text_reader.read()) # 'Python I/O'TextIOWrapperเป็นคลาสหลักสำหรับ I/O แบบข้อความ และถือเป็นพื้นฐานของการดำเนินการกับไฟล์ในระดับสูงเกือบทั้งหมด
io.StringIO: สตรีมข้อความในหน่วยความจำ
StringIO เป็นคลาสที่ช่วยให้คุณสามารถจัดการกับสตริงในหน่วยความจำราวกับว่าเป็นไฟล์ เหมาะสำหรับใช้ทดสอบ I/O หรือสร้างข้อมูลชั่วคราว
1import io
2
3text_buf = io.StringIO()
4text_buf.write("In-memory text stream")
5text_buf.seek(0)
6print(text_buf.read()) # 'In-memory text stream'StringIOช่วยให้ดำเนินการเหมือนไฟล์ได้โดยไม่ต้องใช้ดิสก์ และนิยมนำไปใช้ในการทดสอบหน่วย (unit testing)
io.BytesIO: สตรีมไบนารี่ในหน่วยความจำ
BytesIO เป็นคลาสไฟล์ในหน่วยความจำสำหรับจัดการลำดับไบต์ (bytes) เหมาะสำหรับกรณีที่ต้องประมวลผลข้อมูลเลขฐานสองหรือบีบอัดข้อมูลโดยไม่ต้องเขียนลงไฟล์
1import io
2
3buf = io.BytesIO()
4buf.write(b'\x01\x02\x03')
5buf.seek(0)
6print(list(buf.read())) # [1, 2, 3]BytesIOมีส่วนติดต่อเช่นเดียวกับBufferedIOBaseและใช้แทนไฟล์ api ได้หลายกรณี
การสร้างสตรีมแบบกำหนดเอง (Custom Stream)
คลาสต่างๆ ในโมดูล io สามารถขยายเพิ่มเติมได้ ทำให้คุณสร้างคลาสสตรีมของคุณเองได้ ด้านล่างนี้คือตัวอย่างการทำซับคลาสของ TextIOBase ที่แปลงข้อความทั้งหมดให้เป็นตัวพิมพ์ใหญ่ขณะเขียน
1import io
2
3class UpperTextIO(io.TextIOBase):
4 def __init__(self):
5 self.buffer = ""
6 def write(self, s):
7 self.buffer += s.upper()
8 return len(s)
9
10u = UpperTextIO()
11u.write("hello io")
12print(u.buffer) # "HELLO IO"- ตราบใดที่คุณปฏิบัติตามข้อกำหนดของ
TextIOBaseคุณก็สามารถกำหนดพฤติกรรมเฉพาะได้ตามต้องการ สามารถขยายการทำงานของสตรีมให้เหมาะกับการใช้งานเฉพาะ เช่น ไฟล์หรือเครือข่ายได้อย่างง่ายดาย
สรุป
โมดูล io จัดระเบียบการประมวลผล I/O เป็นลำดับชั้นของคลาสนามธรรมและคลาสที่นำไปใช้ได้จริง
RawIOBaseคือคลาสสำหรับ I/O ระดับไบต์ในระบบปฏิบัติการBufferedIOBaseคือคลาสที่ให้ชั้นแคชอย่างมีประสิทธิภาพTextIOBaseคือคลาสที่จัดการงานอ่าน/เขียนข้อความStringIOและBytesIOคือคลาสที่ให้สตรีมข้อมูลในหน่วยความจำ
การเข้าใจคลาสเหล่านี้ทำให้คุณสามารถเข้าใจการทำงานของระบบ I/O ในภาษาไพธอนได้อย่างถูกต้อง และนำไปประยุกต์ใช้ในงานกับไฟล์, ติดต่อเครือข่าย และออกแบบสตรีมสำหรับทดสอบได้
คุณสามารถติดตามบทความข้างต้นโดยใช้ Visual Studio Code บนช่อง YouTube ของเรา กรุณาตรวจสอบช่อง YouTube ด้วย