มอดูล os เป็นมอดูลอันหนึ่งที่มีติดตัวอยู่ในไพธอนตั้งแต่แรกโดยไม่ต้องติดตั้งเพิ่ม และมีโอกาสใช้งานบ่อย
ภายในนี้มีพวกฟังก์ชันต่างๆที่เกี่ยวกับงานที่ขึ้นกับระบบปฏิบัติการ
(operating system, ย่อว่า OS)
ภายในมอดูล os มีมอดูลย่อย os.path ซึ่งบรรจุพวกฟังก์ชันที่เอาไว้จัดการกับพาธของไฟล์
ในบทนี้จะอธิบายและยกตัวอย่างการใช้ฟังก์ชันต่างๆในมอดูล os.path
ความแตกต่างระหว่างพาธในวินโดวส์ และ mac กับ linux
เนื่องจากพาธของไฟล์นั้นมีความต่างไปในแต่ละระบบปฏิบัติการ โดยหลักๆแล้วจะแบ่ง ๒ แบบคือวินโดวส์ จะต่างกับ mac และ
linux
พาธในวินโดวส์จะใช้เครื่องหมายแบ็กสแลช \ ในการกั้น ในขณะที่ mac และ linux จะใช้เครื่องหมายทับ /
ตัวอย่างพาธไฟล์ในวินโดวส์เช่น
C:\phyblas\maki.py
ตัวอย่างพาธใน mac หรือ linux เช่น
/home/phyblas/maki.py
คำสั่งต่างๆใน os.path ก็จะทำงานต่างกันออกไปโดยพิจารณาแยกแยะว่าเป็นระบบปฏิบัติการไหน
เช่น os.path.join มีไว้เชื่อมชื่อไฟล์ จะใส่ \ เป็นตัวเชื่อมถ้าเป็นในวินโดวส์ แต่จะใช้ / เป็นตัวเชื่อมใน mac และ
linux
หรืออย่าง os.path.split ซึ่งเอาไว้แยกชื่อไฟล์กับพาธไฟล์ ก็จะมอง \ เป็นตัวแยก ถ้าเป็นในวินโดวส์ และมอง / เป็นตัวแยกใน
mac และ linux เป็นต้น
ดังนั้นการใช้ฟังก์ชันต่างๆใน os.path ทำให้สามารถเขียนโปรแกรมที่สามารถใช้งานได้เหมือนกันทั้งในวินโดวส์และ mac กับ linux โดยไม่ต้องมาคอยเขียนแยกกรณี
ในตัวอย่างที่จะยกให้ดูต่อไปนี้จะยกของฝั่ง mac และ linux เป็นหลัก แต่ถ้าใครใช้วินโดวส์ สิ่งที่ต่างกันก็มีแต่เปลี่ยน /
เป็น \ เท่านั้น
การเชื่อมพาธของไฟล์ (.join)
หากมีชื่อไฟล์และโฟลเดอร์แล้วต้องการนำมาเชื่อมกัน สามารถใช้ฟังก์ชัน os.path.join แล้วใส่ชื่อโฟลเดอร์ไล่ไปตามลำดับ
ตัวอย่างเช่น
import os
print(os.path.join('phyblas','umi','kaki.txt')) # ได้ phyblas/umi/kaki.txt
# ถ้าเป็นวินโดวส์จะได้ phyblas\umi\kaki.txt
ผลที่ได้คือจะมี / หรือ \ มากั้น ผลที่ได้อาจคล้ายกับการใช้ '/'.join() หรือ '\\'.join()
แต่ว่าข้อดีก็คือไม่ต้องมาคอยเขียนแยกกรณีเอาเองว่าจะใช้ / หรือ \ แต่จะถูกตัดสินเองจากระบบปฏิบัติการที่ใช้
อนึ่ง กรณีที่ชื่อโฟลเดอร์บรรจุอยู่ภายในลิสต์อาจนำลิสต์นั้นมาใช้ได้โดยเติม *
เพื่อให้ข้อมูลในลิสต์กระจายไปเป็นอาร์กิวเมนต์ตามลำดับ
flis = ['phyblas','umi','kaki.txt']
print(os.path.join(*flis)) # ได้ phyblas/umi/kaki.txt
การแยกส่วนประกอบต่างๆของชื่อไฟล์ (.split, .dirname, .basename)
ในมอดูล os.path มีคำสั่งต่างๆที่ใช้ในการวิเคราะห์แยกส่วนประกอบต่างๆในชื่อไฟล์ได้
สมมุติว่ามีไฟล์หนึ่งใน mac หรือ linux ชื่อและพาธรวมแล้วเป็น
/home/phyblas/umi/ebi.py
หากต้องการแยกส่วนพาธกับตัวชื่อไฟล์ออกจากกันสามารถใช้ฟังก์ชัน os.path.split
ebi = '/home/phyblas/umi/ebi.py'
print(os.path.split(ebi)) # ได้ ('/home/phyblas/umi', 'ebi.py')
หรือสามารถเอาเฉพาะส่วนที่เป็นชื่อตัวไฟล์ออกมาได้โดยใช้ฟังก์ชัน os.path.basename
ในขณะที่ส่วนของพาธที่เหลือจะเอาได้ด้วยฟังก์ชัน os.path.dirname
print(os.path.dirname(ebi)) # ได้ /home/phyblas/umi
print(os.path.basename(ebi)) # ได้ ebi.py
ถ้าต้องการแยกส่วนของสกุลไฟล์ออกจากส่วนอื่นใช้ os.path.splitext
print(os.path.splitext(ebi)) # ได้ ('/home/phyblas/umi/ebi', '.py')
print(os.path.splitext('ika.py')) # ได้ ('ika', '.py')
การจัดการกับพาธสัมบูรณ์และสัมพัทธ์ (.abspath, .relpath, .isabs)
ถ้ามีชื่อและพาธไฟล์ที่เขียนด้วยพาธสัมพัทธ์และต้องการเปลี่ยนเป็นพาธสัมบูรณ์อาจใช้ os.path.abspath
จะมีการเติมพาธที่อยู่ปัจจุบันลงไปให้กลายเป็นพาธสัมบูรณ์
abp = os.path.abspath('ebi.py')
print(abp) # ได้ /home/phyblas/umi/ebi.py
ในทางกลับกันถ้าจะแปลงพาธสัมบูรณ์เป็นพาธสัมพัทธ์โดยเทียบจากตำแหน่งที่เราอยู่ก็ใช้ os.path.relpath
print(os.path.relpath('/home/phyblas/umi/ebi.py')) # ได้ ebi.py
print(os.path.relpath('/home/phyblas/umi')) # ได้ .
print(os.path.relpath('/home/phyblas')) # ได้ ..
print(os.path.relpath('/di')) # ได้ ../../../di
บางครั้งเราอาจต้องการดูว่าพาธที่ใส่ไปเป็นพาธสัมบูรณ์หรือสัมพัทธ์ สามารถใช้ os.path.isabs ตรวจสอบได้ ถ้าเป็นภาพสัมบูรณ์
(ปกติจะขึ้นต้นด้วย /) จะได้ True ถ้าเป็นพาธสัมพัทธ์จะได้ False
print(os.path.isabs('ari')) # ได้ False
print(os.path.isabs('/ari')) # ได้ True
การหาพาธร่วมกันระหว่างไฟล์ (.commonpath .commonprefix)
os.path.commonpath ใช้หาว่าในกลุ่มไฟล์ที่มีชื่ออยู่ในลิสต์นั้นมีพาธร่วมกันนอกสุดที่ตรงไหน
จะใส่เป็นพาธสัมบูรณ์หรือสัมพัทธ์ก็ได้ แต่จะใส่ปนกันไม่ได้
flis = ['/home/phyblas/umi/ebi.py','/home/phyblas/umi/ika/miso.py']
print(os.path.commonpath(flis)) # ได้ /home/phyblas/umi/
flis = ['umi/ebi.py','umi/ika/miso.py','umi']
print(os.path.commonpath(flis)) # ได้ umi
นอกจากนี้ยังมีฟังก์ชันที่คล้ายกันคือ os.path.commonprefix
แต่อันนี้แค่จะไปหาว่าอักษรตัวหน้าสุดของสายอักขระแต่ละตัวนั้นซ้ำกันถึงแค่ตัวไหนเท่านั้น
ลองดูตัวอย่างเทียบความแตกต่าง
flis = ['/home/phyblas/umi/','/home/phyblas/umi/ebi.py']
print(os.path.commonprefix(flis)) # ได้ /home/phyblas/umi/
print(os.path.commonpath(flis)) # ได้ /home/phyblas/umi
flis = ['/home/phyblas/umi/ebi.py','/home/phyblas/umo']
print(os.path.commonprefix(flis)) # ได้ /home/phyblas/um
print(os.path.commonpath(flis)) # ได้ /home/phyblas
การเสริมชื่อโฟลเดอร์บ้านและตัวแปรสภาพแวดล้อม (.expanduser, .expandvars)
ปกติถ้าใช้งานคอมมานด์ไลน์ เครื่องหมาย ~ จะใช้แทนโฟลเดอร์บ้าน แต่ว่าฟังก์ชันต่างๆในไพธอนปกติจะไม่ได้ตีความแบบนั้นให้เลยโดยอัตโนมัติ
เพื่อที่จะแปลง ~/ ที่อยู่ทางซ้ายสุดให้เป็นพาธของโฟลเดอร์บ้าน อาจใช้ฟังก์ชัน os.path.expanduser
print(os.path.expanduser('~/abura/~')) # ได้ /home/phyblas/abura/~
os.path.expanduser จะไปถึงเอาค่าตัวแปรสภาพแวดล้อมที่เก็บค่าที่บอกว่าโฟลเดอร์บ้านของเราขณะนี้คืออะไร แล้วเอามาแทนใส่ ~/
ที่อยู่ซ้ายสุด
สำหรับ mac และ linux แล้ว ชื่อโฟลเดอร์บ้านจะเก็บอยู่ในตัวแปรสภาพแวดล้อมชื่อ $HOME
นอกจากชื่อโฟลเดอร์บ้านแล้ว เรายังสามารถดึงตัวแปรสภาพแวดล้อมตัวอื่นๆมาใช้ได้ โดยใช้ os.path.expandvars
จะทำการแปลงส่วนที่เป็น $ชื่อตัวแปร ให้เป็นค่าตามที่มี
print(os.path.expandvars('$HOME/aaa')) # ได้ /home/phyblas/aaa
print(os.path.expandvars('$USER-a')) # ได้ phyblas-a
การตรวจสอบตัวตนของไฟล์ (.exists, .isfile, .isdir)
หากต้องการตรวจว่าไฟล์ชื่อนั้นที่กำลังค้นอยู่นี้มีตัวตนอยู่หรือเปล่า อาจใช้ os.path.exists
ถ้ามีอยู่จริงไม่ว่าจะเป็นไฟล์หรือเป็นโฟลเดอร์ก็จะได้ True
print(os.path.exists('/home/phyblas/umi/ebi.py')) # ได้ True
print(os.path.exists('/home/phyblas/umi')) # ได้ True
ถ้าต้องการให้เป็น True เมื่อเป็นไฟล์ธรรมดาไม่ใช่โฟลเดอร์เท่านั้นใช้ os.path.isfile หรือในทางกลับกัน ถ้าต้องการให้เป็น True แค่ที่เป็นโฟลเดอร์ใช้
os.path.isdir
print(os.path.isfile('/home/phyblas/umi')) # ได้ False
print(os.path.isfile('/home/phyblas/umi/ebi.py')) # ได้ True
print(os.path.isdir('/home/phyblas/umi')) # ได้ True
print(os.path.isdir('/home/phyblas/umi/ebi.py')) # ได้ False
การดูข้อมูลพื้นฐานของในไฟล์ (.getatime, .getctime, .getmtime, .getsize)
ค่าเวลาที่ทำการแก้ไขหรือเข้าถึงไฟล์นั้นเป็นข้อมูลที่ถูกบันทึกไว้กับตัวไฟล์ เป็นค่าที่สามารถดูได้
ใน os.path มีฟังก์ชันที่ใช้สำหรับดูเวลาเหล่านี้ได้ เพียงแต่ว่าค่าที่ได้ออกมาจะอยู่ในรูปตัวเลขวินาที timestamp
หากต้องการแปลงเป็นเวลาที่เราสามารถเข้าใจได้ก็อาจใช้ datetime.datetime.fromtimestamp (รายละเอียดการใช้ดูได้ใน
https://phyblas.hinaboshi.com/20160621)
สามารถดูเวลาที่แก้ไฟล์ล่าสุดได้โดย os.path.getmtime
import os,datetime
ebi = '/home/phyblas/umi/ebi.py'
m = os.path.getmtime(ebi)
print(m) # ได้ 1583280922.7442703
print(datetime.datetime.fromtimestamp(m)) # ได้ 2020-03-04 08:15:22.744270
ดูเวลาที่มีการเข้าถึงไฟล์ครั้งล่าสุดได้โดย os.path.getatime
a = os.path.getatime(ebi)
print(a) # ได้ 1583327063.902019
print(datetime.datetime.fromtimestamp(a)) # ได้ 2020-03-04 21:04:23.902019
ดูเวลาที่ไฟล์นั้นถูกสร้างขึ้นโดย os.path.getctime
c = os.path.getctime(ebi)
print(c) # ได้ 1583327063.8955612
print(datetime.datetime.fromtimestamp(c)) # ได้ 2020-03-04 21:04:23.895561
ขนาดของไฟล์ (ในหน่วยไบต์) สามารถหาได้โดย os.path.getsize
s = os.path.getsize(ebi)
print(s) # ได้ 292
การจัดการกับซิมโบลิกลิงก์หรือชอร์ตคัต (.realpath, .islink, .samefile)
os.path.realpath สามารถใช้กับไฟล์ที่เป็นซิมโบลิกลิงก์ (ใน mac หรือ linux) หรือชอร์ตคัต (ในวินโดวส์)
เพื่อดูว่าเป็นตัวที่โยงไปที่ไหน โดยจะแสดงเป็นพาธสัมบูรณ์
เช่นสมมุติว่าสร้างไฟล์ hailao.py ขึ้นมาเป็นซิมโบลิกลิงก์ของ ebi.py
print(os.path.realpath('hailao.py')) # ได้ /home/phyblas/umi/ebi.py
หรือถ้าใช้กับไฟล์ที่อยู่ในโฟลเดอร์ที่เป็นซิมโบลิกลิงก์ก็จะแสดงพาธจริงเช่นกัน
เช่นสมมุติว่าโฟลเดอร์ hai เป็นซิมโบลิกลิงก์ของโฟลเดอร์ umi
print(os.path.realpath('/home/phyblas/hai/ebi.py')) # ได้ /home/phyblas/umi/ebi.py
os.path.islink ใช้ตรวจดูว่าไฟล์ไหนเป็นซิมโบลิกลิงก์หรือเปล่า
print(os.path.islink('hailao.py')) # ได้ True
การจะดูว่าไฟล์ ๒ ไฟล์เป็นไฟล์เดียวกันหรือเปล่าอาจใช้ os.path.samefile ฟังก์ชันนี้จะให้ค่า True ถ้าเป็นไฟล์เดียวกัน
หรือเป็นซิมโบลิกลิงก์ที่โยงไปที่เดียวกัน
print(os.path.samefile('ebi.py','/home/phyblas/umi/ebi.py')) # ได้ True
print(os.path.samefile('ebi.py','hailao.py')) # ได้ True
สรุปฟังก์ชันทั้งหมด
os.path.abspath() |
แปลงพาธสัมพัทธ์เป็นพาธสัมบูรณ์ |
os.path.basename() |
แยกเอาชื่อไฟล์ ตัดพาธทิ้ง |
os.path.commonpath() |
หาพาธร่วมระหว่างชื่อไฟล์หลายไฟล์ |
os.path.commonprefix() |
หาคำนำหน้าร่วมระหว่างชื่อไฟล์หลายไฟล์ |
os.path.dirname() |
แยกเอาพาธ ตัดชื่อไฟล์ |
os.path.exists() |
ดูว่าไฟล์นี้มีอยู่จริงหรือไม่ |
os.path.expanduser() |
เพิ่มส่วนของโฟลเดอร์บ้านของผู้ใช้ไปแทน ~/ |
os.path.expandvars() |
แทนค่าจากตัวแปรสภาพแวดล้อม (ซึ่งขึ้นต้นด้วย $) |
os.path.getatime() |
ดูเวลาที่เปิดไฟล์ครั้งล่าสุด |
os.path.getctime() |
ดูเวลาที่ไฟล์ถูกสร้างขึ้น |
os.path.getmtime() |
ดูเวลาที่มีการแก้ไขไฟล์ครั้งล่าสุด |
os.path.getsize() |
ดูขนาดของไฟล์ |
os.path.isabs() |
ดูว่าพาธไฟล์นี้เป็นพาธสัมบูรณ์ (True) หรือสัมพัทธ์ (False) |
os.path.isdir() |
ดูว่าพาธไฟล์นี้มีอยู่จริง และเป็นโฟลเดอร์หรือไม่ |
os.path.isfile() |
ดูว่าพาธไฟล์นี้มีอยู่จริง และเป็นไฟล์ทั่วไปที่ไม่ใช่โฟลเดอร์หรือไม่ |
os.path.islink() |
ดูว่าไฟล์นี้เป็นซิมโบลิกลิงก์หรือชอร์ตคัตหรือไม่ |
os.path.join() |
เชื่อมชื่อไฟล์และโฟลเดอร์โดยคั่นด้วย / ใน mac หรือ linux หรือด้วย \ ในวินโดวส์ |
os.path.realpath() |
หาพาธไฟล์ที่แท้จริงของไฟล์ที่มีพาธผ่านซิมโบลิกลิงก์หรือชอร์ตคัต |
os.path.relpath() |
แปลงพาธสัมบูรณ์เป็นพาธสัมพัทธ์ |
os.path.samefile() |
ดูว่าไฟล์ ๒ ไฟล์นั้นโยงไปที่ไฟล์เดียวกันหรือไม่ |
os.path.split() |
แยกส่วนของชื่อไฟล์และพาธออกจากกัน |
อ้างอิง