φυβλαςのβλογ
บล็อกของ phyblas



การใช้มอดูล os.path ใน python จัดการพาธและข้อมูลไฟล์
เขียนเมื่อ 2020/03/04 23:39
แก้ไขล่าสุด 2024/02/17 20:29

มอดูล 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() แยกส่วนของชื่อไฟล์และพาธออกจากกัน




อ้างอิง


-----------------------------------------

囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧

ดูสถิติของหน้านี้

หมวดหมู่

-- คอมพิวเตอร์ >> เขียนโปรแกรม >> python

ไม่อนุญาตให้นำเนื้อหาของบทความไปลงที่อื่นโดยไม่ได้ขออนุญาตโดยเด็ดขาด หากต้องการนำบางส่วนไปลงสามารถทำได้โดยต้องไม่ใช่การก๊อปแปะแต่ให้เปลี่ยนคำพูดเป็นของตัวเอง หรือไม่ก็เขียนในลักษณะการยกข้อความอ้างอิง และไม่ว่ากรณีไหนก็ตาม ต้องให้เครดิตพร้อมใส่ลิงก์ของทุกบทความที่มีการใช้เนื้อหาเสมอ

สารบัญ

รวมคำแปลวลีเด็ดจากญี่ปุ่น
มอดูลต่างๆ
-- numpy
-- matplotlib

-- pandas
-- manim
-- opencv
-- pyqt
-- pytorch
การเรียนรู้ของเครื่อง
-- โครงข่าย
     ประสาทเทียม
ภาษา javascript
ภาษา mongol
ภาษาศาสตร์
maya
ความน่าจะเป็น
บันทึกในญี่ปุ่น
บันทึกในจีน
-- บันทึกในปักกิ่ง
-- บันทึกในฮ่องกง
-- บันทึกในมาเก๊า
บันทึกในไต้หวัน
บันทึกในยุโรปเหนือ
บันทึกในประเทศอื่นๆ
qiita
บทความอื่นๆ

บทความแบ่งตามหมวด



ติดตามอัปเดตของบล็อกได้ที่แฟนเพจ

  ค้นหาบทความ

  บทความแนะนำ

ตัวอักษรกรีกและเปรียบเทียบการใช้งานในภาษากรีกโบราณและกรีกสมัยใหม่
ที่มาของอักษรไทยและความเกี่ยวพันกับอักษรอื่นๆในตระกูลอักษรพราหมี
การสร้างแบบจำลองสามมิติเป็นไฟล์ .obj วิธีการอย่างง่ายที่ไม่ว่าใครก็ลองทำได้ทันที
รวมรายชื่อนักร้องเพลงกวางตุ้ง
ภาษาจีนแบ่งเป็นสำเนียงอะไรบ้าง มีความแตกต่างกันมากแค่ไหน
ทำความเข้าใจระบอบประชาธิปไตยจากประวัติศาสตร์ความเป็นมา
เรียนรู้วิธีการใช้ regular expression (regex)
การใช้ unix shell เบื้องต้น ใน linux และ mac
g ในภาษาญี่ปุ่นออกเสียง "ก" หรือ "ง" กันแน่
ทำความรู้จักกับปัญญาประดิษฐ์และการเรียนรู้ของเครื่อง
ค้นพบระบบดาวเคราะห์ ๘ ดวง เบื้องหลังความสำเร็จคือปัญญาประดิษฐ์ (AI)
หอดูดาวโบราณปักกิ่ง ตอนที่ ๑: แท่นสังเกตการณ์และสวนดอกไม้
พิพิธภัณฑ์สถาปัตยกรรมโบราณปักกิ่ง
เที่ยวเมืองตานตง ล่องเรือในน่านน้ำเกาหลีเหนือ
ตระเวนเที่ยวตามรอยฉากของอนิเมะในญี่ปุ่น
เที่ยวชมหอดูดาวที่ฐานสังเกตการณ์ซิงหลง
ทำไมจึงไม่ควรเขียนวรรณยุกต์เวลาทับศัพท์ภาษาต่างประเทศ

บทความแต่ละเดือน

2024年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2023年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2022年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2021年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2020年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

ค้นบทความเก่ากว่านั้น

ไทย

日本語

中文