φυβλαςのβλογ
phyblas的博客



การจัดการไฟล์ด้วย python โดยใช้มอดูล os และ shutil
เขียนเมื่อ 2020/03/19 17:43
แก้ไขล่าสุด 2024/02/22 10:36


ไพธอนมีฟังก์ชันมากมายที่เกี่ยวกับการจัดการไฟล์ ส่วนใหญ่จะอยู่ในมอดูลชื่อ os ซึ่งเป็นมอดูลที่มีการใช้งานที่หลากหลาย และมีบางส่วนที่อยู่ในมอดูล shutil

ทั้ง ๒​ มอดูลนี้ต่างก็มีอยู่แล้วในไพธอนโดยไม่ต้องติดตั้งเพิ่ม

เนื่องจากคำสั่งภายใน ๒ มอดูลนี้มีความเกี่ยวข้องกันมาก จึงขอสรุปเกี่ยวกับพวกฟังก์ชันต่างๆที่ใช้จัดการไฟล์จาก ๒ มอดูลนี้ลงในบทความนี้ทีเดียวเลย

อย่างไรก็ตาม มอดูล os นั้นแบ่งเป็นหลายส่วน คำสั่งถูกใช้งานได้ในหลายด้าน เช่นมีมอดูลย่อย os.path ซึ่งใช้ในการจัดการเรื่องพาธและข้อมูลไฟล์ ซึ่งได้เขียนถึงไปใน https://phyblas.hinaboshi.com/20200304

shutil เองก็ยังมีอีกหลายฟังก์ชันซึ่งไม่ได้เกี่ยวกับการจัดการไฟล์ ในที่นี้ก็จะไม่ได้พูดถึง

คำสั่งส่วนใหญ่นั้นจริงๆแล้วมีความใกล้เคียงกับคำสั่งที่สั่งในคอมมานด์ไลน์ ซึ่งถ้าใช้มอดูล subprocess (ดูใน https://phyblas.hinaboshi.com/20200306) เพื่อสั่งคอมมานด์ไลน์ก็สามารถทำได้

แต่ถ้าคำสั่งไหนใช้ฟังก์ชันที่มีอยู่แล้วในไพธอนได้ก็ย่อมสะดวกกว่า หากไม่ใช่งานที่ระดับสูงมากนักแค่ใช้ฟังก์ชันต่างๆที่มีอยู่ในมอดูล os และ shutil ก็จัดการได้โดยง่าย

ขอแบ่งอธิบายเป็นกลุ่มๆ ตามการใช้งาน ดูชื่อฟังก์ชันทั้งหมดได้ที่สารบัญข้างบน




การสร้างโฟลเดอร์ (os.mkdir, os.makedirs)

คำสั่งสำหรับสร้างโฟลเดอร์ขึ้นมาใหม่มีอยู่ ๒ ตัวคือ os.mkdir() และ os.makedirs() วิธีการใช้คล้ายกัน คือใส่ชื่อโฟลเดอร์ที่ต้องการสร้าง เช่น
import os

os.mkdir('aki') # สร้างโฟลเดอร์ชื่อ aki
os.makedirs('aya') # สร้างโฟลเดอร์ชื่อ aya

ในกรณีแบบนี้จะใช้อันไหนก็ไม่ต่างกัน แต่ข้อแตกต่างจะเกิดขึ้นในกรณีที่สร้างโฟลเดอร์ซ้อนภายในโฟลเดอร์ที่ไม่มีมาก่อน ถ้าเป็น os.mkdir() จะเกิดข้อผิดพลาดขึ้น แต่ os.makedirs() จะสร้างได้
os.mkdir('ama/saki') # FileNotFoundError: [Errno 2] No such file or directory: 'ama/saki'
os.makedirs('ama/saki') # สร้างโฟลเดอร์ชื่อ ama แล้วจึงสร้างโฟลเดอร์ชื่อ saki ในนั้น

ถ้าหากโฟลเดอร์ที่สร้างมีตัวตนอยู่แล้ว จะเกิดข้อผิดพลาดขึ้น ไม่ว่าจะใช้คำสั่งไหน
os.mkdir('aki') # ได้ FileExistsError: [Errno 17] File exists: 'aki'
os.makedirs('aya') # ได้ FileExistsError: [Errno 17] File exists: 'aya'

แต่สำหรับ os.makedirs สามารถใส่ exist_ok=True เพื่อให้ไม่เกิดอะไรขึ้นเมื่อโฟลเดอร์มีอยู่แล้วได้
os.makedirs('aya',exist_ok=True) # ไม่เกิดอะไรขึ้น




การย้ายหรือเปลี่ยนชื่อไฟล์ (os.rename, os.renames, os.replace, shutil.move)

การย้ายไฟล์หรือเปลี่ยนชื่อไฟล์นั้นที่จริงแล้วก็เป็นเรื่องเดียวกัน มีหลายคำสั่งที่ใช้ในการเปลี่ยนชื่อหรือย้าย ได้แก่ os.rename(), os.renames(), os.replace() และ shutil.move()

ถ้าใช้กับไฟล์หรือโฟลเดอร์ที่มีอยู่แล้ว ไม่ว่าจะใช้อันไหนก็ให้ผลไม่ต่างกัน เป็นการเปลี่ยนชื่อไฟล์หรือโฟลเดอร์นั้น
import os,shutil

os.rename('aki','aka') # เปลี่ยนชื่อ aki เป็น aka
os.renames('ama','ami') # เปลี่ยนชื่อ ama เป็น ami
os.replace('aya','maya') # เปลี่ยนชื่อ aya เป็น maya
shutil.move('maya','saya') # เปลี่ยนชื่อ maya เป็น saya

แต่ในกรณีที่ปลายทางเป็นโฟลเดอร์ที่มีอยู่แล้วและเป็นโฟลเดอร์ที่ไม่ว่างเปล่า แบบนี้ os.rename(), os.renames(), os.replace() จะเกิดข้อผิดพลาดขึ้น ในขณะที่ shutil.move() จะเป็นการย้ายเข้าโฟลเดอร์นั้น
os.rename('aka','ami') # OSError: [Errno 66] Directory not empty: 'aka' -> 'ami'
os.renames('aka','ami') # OSError: [Errno 66] Directory not empty: 'aka' -> 'ami'
os.replace('aka','ami') # OSError: [Errno 66] Directory not empty: 'aka' -> 'ami'
shutil.move('aka','ami') # ย้าย aka ไปไว้ใน ami

เพียงแต่หากไฟล์ที่ต้องการย้ายนั้นเป็นโฟลเดอร์ และย้ายไปโฟลเดอร์ปลายทางซึ่งพอดีเป็นโฟลเดอร์เปล่า แบบนี้ os.rename(), os.renames(), os.replace() จะกลายเป็นการย้ายโฟลเดอร์ต้นทางไปทับโฟลเดอร์นั้นแทน

กรณีที่ปลายทางอยู่ในโฟลเดอร์ที่ไม่มีตัวตนอยู่ os.rename() กับ os.replace() จะเกิดข้อผิดพลาด ส่วน os.renames() กับ shutil.move() จะสร้างโฟลเดอร์ใหม่ขึ้นมาตามเส้นทาง
os.rename('aka','hana/saka') # FileNotFoundError: [Errno 2] No such file or directory: 'aka' -> 'hana/saka'
os.replace('aka','hana/saka') # FileNotFoundError: [Errno 2] No such file or directory: 'aka' -> 'hana/saka'
os.renames('aka','hana/saka') # aka ย้ายไปอยู่ใน hana และเปลี่ยนชื่อเป็น saka
# shutil.move('aka','hana/saka') ก็ให้ผลเหมือน os.renames()

กรณีที่ย้ายไฟล์ออกจากโฟลเดอร์แล้วโฟลเดอร์นั้นไม่เหลือไฟล์อื่น หากใช้ os.renames() จะทำการลบโฟลเดอร์นั้นทิ้งโดยอัตโนมัติ ส่วนตัวอื่นจะแค่ย้ายไปที่ใหม่
os.renames('hana/saka','saya/suki')
# saka ย้ายไปอยู่ใน saya และเปลี่ยนชื่อเป็น suki ส่วน โฟลเดอร์ hana ถูกลบทิ้ง




การคัดลอกไฟล์ (shutil.copy, shutil.copy2, shutil.copyfile, shutil.copytree, shutil.copystat)

ฟังก์ชันสำหรับทำการคัดลอกอยู่ในมอดูล shutil ทั้งหมด

shutil.copy(), shutil.copy2(), shutil.copyfile() ใช้คัดลอกไฟล์ธรรมดาที่ไม่ใช่โฟลเดอร์ ถ้าใช้กับโฟลเดอร์จะเกิดข้อผิดพลาด

ข้อแตกต่างคือ shutil.copy() กับ shutil.copyfile() จะแค่คัดลอกเนื้อหาจากไฟล์เดิมไปสร้างไฟล์ให้มีเนื้อหาเหมือนเดิม แต่พวกข้อมูลสถานะเช่นพวกเวลาสร้าง เวลาแก้ไข จะไม่ได้คัดลอกมาด้วย แต่จะเหมือนสร้างใหม่

ตัวอย่างเช่น มีไฟล์นึงชื่อ sasori.txt ลองคัดลอกไปเป็นไฟล์อีกชื่อ
shutil.copy('sasori.txt','sasuru.txt') # คัดลอกแค่เนื้อหาไฟล์
shutil.copy2('sasori.txt','sosoru.txt') # คัดลอกทั้งเนื้อหาไฟล์และสถานะ
shutil.copyfile('sasori.txt','susuri.txt') # คัดลอกแค่เนื้อหาไฟล์

ส่วน shutil.copytree() จะใช้คัดลอกโฟลเดอร์ พร้อมทั้งเนื้อหาที่อยู่ในโฟลเดอร์ทั้งหมด ถ้าปลายทางอยู่ในโฟลเดอร์ที่ยังไม่มีตัวตนอยู่ก็จะถูกสร้างใหม่
shutil.copytree('ami','hama') # ตัดลอกโฟลเดอร์และเนื้อใน ami ไปยัง hama
shutil.copytree('ami','asa/nagi') # โฟลเดอร์ asa จะถูกสร้างขึ้นถ้าไม่มีอยู่ แล้วจึงคัดลอกข้อมูลจาก ami ไป nagi ใน asa

ปกติแล้วการคัดลอกจะให้ผลเหมือยน shutil.copy2() คือคัดลอกทั้งเนื้อหาไฟล์และข้อมูลประกอบไฟล์ แต่หากต้องการทำให้คัดลอกแบบ shutil.copy ก็ทำได้โดยใส่ copy_function=shutil.copy
shutil.copytree('ami','nami',copy_function=shutil.copy)

ถ้าโฟลเดอร์ปลายทางมีอยู่แล้วก็จะเกิดข้อผิดพลาดขึ้น แต่ในไพธอน 3.8 สามารถใส่ dirs_exist_ok=True เพื่อจะทำให้สามารถคัดลอกได้แม้จะมีโฟลเดอร์เดิมอยู่ โดยเนื้อหาจากต้นฉบับจะถูกคัดลอกเข้าไปยังโฟลเดอร์ปลายทางนั้น ส่วนเนื้อหาในโฟลเดอร์ปลายทางที่มีอยู่เดิมก็ไม่ได้หายไปไหน
shutil.copytree('ami','nami',dirs_exist_ok=True)

ส่วน shutil.copystat() มีไว้คัดลอกสถานะของไฟล์หนึ่งไปยังอีกไฟล์ที่มีอยู่แล้ว โดยไม่ได้เปลี่ยนเนื้อหาข้างใน
shutil.copystat('sasori.txt','sasuru.txt')




สร้างลิงก์หรือชอร์ตคัต (os.link, os.symlink)

ฟังก์ชัน os.link() มีไว้สร้างฮาร์ดลิงก์ ส่วน os.symlink() ไว้ใช้สร้างซิมโบลิกลิงก์
os.link('sasori.txt','sasoru.txt') # สร้างฮาร์ดลิงก์ของ sasori.txt ชื่อ sasoru.txt
os.symlink('sasori.txt','sasara.txt') # สร้างซิมโบลิกลิงก์ของ sasori.txt ชื่อ sasara.txt

เกี่ยวกับความแตกต่างระหว่างฮาร์ดลิงก์กับซิมโบลิกลิงก์ได้เขียนถึงไว้ใน https://phyblas.hinaboshi.com/20200303




การลบไฟล์หรือโฟลเดอร์ (os.remove, os.unlink, os.rmdir, os.removedirs, shutil.rmtree)

ฟังก์ชันที่ใช้ในการลบไฟล์คือ os.remove() และ os.unlink() ใช้อันไหนก็เหมือนกัน
os.remove('sasara.txt') # ลบ sasara.txt

os.rmdir() กับ os.removedirs() มีไว้ใช้ลบโฟลเดอร์เปล่า แต่ถ้าใช้กับโฟลเดอร์ที่มีอะไรอยู่จะเกิดข้อผิดพลาด
os.rmdir('hama/saki') # ลบโฟลเดอร์ saka ในโฟลเดอร์ hama แต่ถ้าใน saka ไม่ได้ว่างเปล่าจะเกิดข้อผิดพลาด

หากต้องการลบโฟลเดอร์ที่มีอะไรอยู่พร้อมกับไฟล์ในนั้นทั้งหมดให้ใช้ shutil.rmtree
shutil.rmtree('asa') # ลบโฟลเดอร์ asa และไฟล์ที่อยู่ข้างในทั้งหมด




โฟลเดอร์ที่ทำงาน (os.chdir, os.getcwd)

os.getcwd() ใช้หาพาธของโฟลเดอร์ที่ทำงานอยู่ปัจจุบัน และหากต้องการย้ายโฟลเดอร์ก็ใช้ os.chdir()

ตัวอย่าง
os.chdir('/') # ย้ายโฟลเดอร์ทำงานไปที่ /
os.getcwd() # ได้ /




ดูสถานะไฟล์ (os.stat, os.lstat)

os.stat ใช้สำหรับดูข้อมูลสถานะของไฟล์
stat = os.stat('sasori.txt')
print(stat) # ได้ os.stat_result(st_mode=33188, st_ino=14819342, st_dev=16777223, st_nlink=3, st_uid=501, st_gid=20, st_size=5, st_atime=1584553332, st_mtime=1584549830, st_ctime=1584553331)
print(stat.st_mode) # ได้ 33188

st_atime, st_ctime และ st_mtime เป็นข้อมูลเวลา ถูกแสดงในรูปตัวเลขวินาที timestamp อาจใช้ datetime.datetime.fromtimestamp() เพื่อเปลี่ยนเป็นวันที่ที่อ่านได้ (รายละเอียดการใช้ดูได้ใน https://phyblas.hinaboshi.com/20160621)
import datetime

print(datetime.datetime.fromtimestamp(stat.st_atime)) # ได้ 2020-03-19 01:42:12.758729
print(datetime.datetime.fromtimestamp(stat.st_ctime)) # ได้ 2020-03-19 01:42:11.705659
print(datetime.datetime.fromtimestamp(stat.st_mtime)) # ได้ 2020-03-19 00:43:50.621884

os.lstat() จะเหมือนกับ os.stat() แต่ต่างกันตรงที่ถ้าหากใช้กับไฟล์ที่เป็นซิมโบลิกลิงก์ จะตามไปหาข้อมูลไฟล์ต้นทางแทน

เช่นสมมุติว่า sasara.txt เป็นซิมโบลิกลิงก์ของไฟล์ sasori.txt เมื่อครู่นี้ ก็จะได้ว่าผลของ os.stat() กับ os.fstat() ต่างกัน
stat = os.stat('sasara.txt')
lstat = os.lstat('sasara.txt')
print(stat==lstat) # ได้ T False
print(stat) # ได้ os.stat_result(st_mode=33279, st_ino=14819342, st_dev=16777223, st_nlink=3, st_uid=501, st_gid=20, st_size=5, st_atime=1584595520, st_mtime=1584549830, st_ctime=1584595595)
print(lstat) # ได้ os.stat_result(st_mode=41453, st_ino=14851181, st_dev=16777223, st_nlink=1, st_uid=501, st_gid=20, st_size=10, st_atime=1584594424, st_mtime=1584594424, st_ctime=1584594424)
print(os.stat('sasori.txt')==os.lstat('sasori.txt')) # ได้ True




จัดการสิทธิไฟล์ (os.chmod, os.chown, os.chflags, os.lchmod, os.lchown, os.lchflags)

os.chmod(), os.chown(), os.chflags() มีไว้สำหรับเปลี่ยนพวกสิทธิหรือสถานะต่างๆใน unix เทียบเท่ากับการใช้คำสั่ง chmod, chown, chflags ในเชลยูนิกซ์ ในที่นี้จะไม่อธิบายละเอียด แต่มีเขียนถึงไว้ใน https://phyblas.hinaboshi.com/20190126

ตัวอย่างการใช้
os.chflags('sasori.txt',0)
os.chmod('sasori.txt',0o777)
os.chown('sasori.txt',501,20)

ส่วน os.lchmod(), os.lchown(), os.lchflags() จะคล้ายกัน แค่ต่างตรงที่ว่าถ้าเจอซิมโบลิกลิงก์จะไปจัดการที่ตัวต้นทางแทน




ดูไฟล์ที่มีอยู่ในโฟลเดอร์ (os.listdir, os.scandir)

ฟังก์ชัน os.listdir() จะแสดงลิสต์ของชื่อไฟล์ทั้งหมดในโฟลเดอร์ที่ระบุ แต่ถ้าหากไม่ระบุโฟลเดอร์ก็จะแสดงไฟล์ของโฟลเดอร์ที่ทำงานอยู่ปัจจุบัน

ตัวอย่าง
os.listdir('kami') # ได้ ['nari.txt', 'washinda']

นอกจากนี้ยังมี os.scandir() จะดูไฟล์ต่างๆในโฟลเดอร์ทั้งหมด คล้ายกับ os.listdir() แต่จะให้ผลออกมาเป็นอิเทอเรเตอร์ซึ่งสามารถนำมาดูข้อมูลของไฟล์ได้หลายอย่าง

วิธีการใช้มักใช้คู่กับ for เพื่อวนดูไฟล์ทีละตัว และใช้เสร็จก็ให้ใช้ .close() เพื่อปิดด้วย หรือจะใช้กับ with เพื่อจะได้ไม่ต้องมาปิดตอนท้ายก็ได้
fol = os.scandir('kami')
for f in fol:
    print('=='+f.name+'==') # แสดงชื่อไฟล์
    print('path: %s'%f.path) # แสดงพาธไฟล์
    print('inode: %s'%f.inode()) # แสดงไอโหนด
    print('file?: %s'%f.is_file()) # เป็นไฟล์ธรรมดาหรือเปล่า?
    print('dir?: %s'%f.is_dir()) #  เป็นโฟลเดอร์หรือเปล่า?
    print('symlink?: %s'%f.is_symlink()) # เป็นซิมโบลิกลิงก์หรือเปล่า?
    print('stat: %s'%(f.stat(),)) # แสดงข้อมูลสถานะ
fol.close()

ได้
==nari.txt==
path: kami/nari.txt
inode: 14849154
file?: True
dir?: False
symlink?: False
stat: os.stat_result(st_mode=33188, st_ino=14849154, st_dev=16777223, st_nlink=1, st_uid=501, st_gid=20, st_size=5, st_atime=1584592839, st_mtime=1584549830, st_ctime=1584592838)
==washinda==
path: kami/washinda
inode: 14849149
file?: False
dir?: True
symlink?: False
stat: os.stat_result(st_mode=16877, st_ino=14849149, st_dev=16777223, st_nlink=2, st_uid=501, st_gid=20, st_size=64, st_atime=1584592813, st_mtime=1584592813, st_ctime=1584592821)




ไล่จัดการโฟลเดอร์ไปทีละชั้น (os.walk)

os.walk() เป็นฟังก์ชันที่สะดวกเมื่อต้องการจะไล่จัดการกับไฟล์ที่อยู่ในโฟลเดอร์ที่ซ้อนอยู่ในโฟลเดอร์ย่อยเป็นชั้นๆ

ฟังก์ชันนี้เมื่อใช้ไปจะคืนค่าเป็นเจเนอเรเตอร์ที่มีข้อมูลของโฟลเดอร์ โดยจะให้ ๓ อย่างมาพร้อมกัน คือ
- [พาธโฟลเดอร์นั้น, ลิสต์ของโฟลเดอร์ข้างใน, ลิสต์ของไฟล์ข้างใน]

จากนั้นหากในนั้นมีโฟลเดอร์อยู่ ในรอบต่อๆไปของ for ก็จะไปวนดูโฟลเดอร์ด้านในนั้น และให้ค่า ๓ อย่างเหมือนเดิม เป็นอย่างนี้ซ้ำไปเรื่อยๆจนหมดทุกโฟลเดอร์ย่อยด้านใน

ตัวอย่างการใช้ เช่น สมมุติมีโฟลเดอร์ที่ข้างในมีโฟลเดอร์ย่อยและไฟล์แบบนี้



เมื่อลองใช้ os.walk() เพื่อให้ไล่ดูไฟล์และโฟลเดอร์ข้างในไปทีละชั้น
import os

i = 0
for path,lis_fol,lis_fai in os.walk('sa'):
    i += 1
    print('%d. ในโฟลเดอร์ '%i+path)
    print('มีโฟลเดอร์ %d โฟลเดอร์'%len(lis_fol))
    for fol in lis_fol:
        print('- '+os.path.join(path,fol))
    print('มีไฟล์ %d ไฟล์'%len(lis_fai))
    for fai in lis_fai:
        print('- '+os.path.join(path,fai))

ก็จะไล่ออกมาได้ผลแบบนี้
1. ในโฟลเดอร์ sa
มีโฟลเดอร์ 2 โฟลเดอร์
- sa/ga
- sa/ka
มีไฟล์ 0 ไฟล์
2. ในโฟลเดอร์ sa/ga
มีโฟลเดอร์ 1 โฟลเดอร์
- sa/ga/shi
มีไฟล์ 2 ไฟล์
- sa/ga/mi
- sa/ga/su
3. ในโฟลเดอร์ sa/ga/shi
มีโฟลเดอร์ 2 โฟลเดอร์
- sa/ga/shi/ma
- sa/ga/shi/te
มีไฟล์ 1 ไฟล์
- sa/ga/shi/ta
4. ในโฟลเดอร์ sa/ga/shi/ma
มีโฟลเดอร์ 1 โฟลเดอร์
- sa/ga/shi/ma/su
มีไฟล์ 0 ไฟล์
5. ในโฟลเดอร์ sa/ga/shi/ma/su
มีโฟลเดอร์ 0 โฟลเดอร์
มีไฟล์ 0 ไฟล์
6. ในโฟลเดอร์ sa/ga/shi/te
มีโฟลเดอร์ 0 โฟลเดอร์
มีไฟล์ 0 ไฟล์
7. ในโฟลเดอร์ sa/ka
มีโฟลเดอร์ 1 โฟลเดอร์
- sa/ka/mi
มีไฟล์ 1 ไฟล์
- sa/ka/na
8. ในโฟลเดอร์ sa/ka/mi
มีโฟลเดอร์ 0 โฟลเดอร์
มีไฟล์ 1 ไฟล์
- sa/ka/mi/chi

เนื่องจากมีทั้งหมด ๘ โฟลเดอร์ (รวมตัวโฟลเดอร์ที่เริ่มต้นด้วย) ดังนั้นจึงมีการวน ๘ ครั้ง แต่ละครั้งจะบอกเนื้อหาว่าข้างในมีโฟลเดอร์อะไรอยู่บ้าง โดยไล่จากนอกสุดเข้ามา




อ้างอิง


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

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

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

หมวดหมู่

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

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

目录

从日本来的名言
模块
-- numpy
-- matplotlib

-- pandas
-- manim
-- opencv
-- pyqt
-- pytorch
机器学习
-- 神经网络
javascript
蒙古语
语言学
maya
概率论
与日本相关的日记
与中国相关的日记
-- 与北京相关的日记
-- 与香港相关的日记
-- 与澳门相关的日记
与台湾相关的日记
与北欧相关的日记
与其他国家相关的日记
qiita
其他日志

按类别分日志



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

  查看日志

  推荐日志

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