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



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

มอดูล 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
-- opencv
-- pytorch
การเรียนรู้ของเครื่อง
-- โครงข่าย
     ประสาทเทียม
maya
javascript
ความน่าจะเป็น
บันทึกในญี่ปุ่น
บันทึกในจีน
-- บันทึกในปักกิ่ง
-- บันทึกในฮ่องกง
-- บันทึกในมาเก๊า
บันทึกในไต้หวัน
บันทึกในยุโรปเหนือ
บันทึกในประเทศอื่นๆ
เรียนภาษาจีน
qiita
บทความอื่นๆ

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



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

  ค้นหาบทความ

  บทความแนะนำ

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

ไทย

日本語

中文