Data Warehouse

การเขียนข้อมูลลงไฟล์

การเปิดไฟล์สำหรับเขียน

การเขียนไฟล์นั้นก็เช่นเดียวกับการอ่านไฟล์ คือจะต้องเปิดไฟล์ขึ้นมาเสียก่อน เพียงแต่ต้องกำหนดโหมดการใช้งานเป็น w หรือ a แทนที่จะเป็น r แบบตอนอ่าน ที่อาจจะฟังดูแปลกหน่อย ก็คือแม้ว่าไฟล์ที่จะเขียนนั้นยังไม่ได้มีตัวตนอยู่ ก็ตาม แต่ก็ยังต้องใช้คำสั่ง open เพื่อเปิดอะไรที่ว่างเปล่านั้นขึ้น ซึ่งการเปิดในที่นี้นั้นเท่ากับเป็นการสร้างไฟล์ขึ้นมา หาก open ไฟล์ในโหมด w จะพบว่าไฟล์นั้นถูกสร้างขึ้นมาทันทีหากมันไม่ได้มีตัวตนอยู่แต่แรก

f =  open('xxxx.txt','w',encoding='utf-8')  
f.close()

ลองไปดูจะพบว่ามีไฟล์ชื่อ xxxx.txt โผล่มาในโฟลเดอร์เดียวกับไฟล์โปรแกรม และภายในว่างเปล่าไม่มีอะไร โหมด w กับ a นั้นจะต่างกันตรงที่ว่าในกรณีที่ไฟล์เดิมมีตัวตนอยู่แล้วถ้าเป็นโหมด w ไฟล์จะถูกเขียนทับใหม่ทันที แต่ถ้าเป็น a จะเป็นการเขียนต่อจากไฟล์เดิม การเขียนไฟล์ก็ต้องเลือกรูปแบบการเอนโค้ดเช่นกัน ในที่นี้ใช้เป็น utf-8 เช่นเคย

คำสั่งเขียนไฟล์

มี ๒ เมธอดที่ใช้ในการเขียนไฟล์ คือ write กับ writelines ข้อแตกต่างคือ write จะใช้กับสายอักขระอันเดียว แต่ writelines จะใช้กับลิสต์ของสายอักขระ กรณีที่ใช้กับสายอักขระเดียวยาวต่อเนื่อง จะใช้ write หรือ writelines ก็ได้เหมือนกันทั้งคู่

s =  '''เวลาที่เข้าหาผู้อื่น ให้มีหัวใจที่อบอุ่นดั่งฤดูใบไม้ผลิ  
เวลาที่ทำงาน ให้มีหัวใจที่เร่าร้อนดั่งฤดูร้อน  
เวลาที่คิดอะไร ให้มีหัวใจที่แจ่มใสดั่งฤดูใบไม้ร่วง  
เวลาที่เผชิญหน้ากับตัวเอง ให้มีหัวใจที่เข้มงวดดั่งฤดูหนาว'''  
f =  open('samejima.txt','w',encoding='utf-8')  
f.write(s)  
#หรือ f.writelines(s)  
f.close()

(ที่มาของข้อความ)

แต่ถ้ามีสายอักขระหลายๆอันแยกกันอยู่จะใช้ได้แต่ writelines เช่น

s = ['เวลาที่เข้าหาผู้อื่น ให้มีหัวใจที่อบอุ่นดั่งฤดูใบไม้ผลิ',  'เวลาที่ทำงาน ให้มีหัวใจที่เร่าร้อนดั่งฤดูร้อน',  'เวลาที่คิดอะไร ให้มีหัวใจที่แจ่มใสดั่งฤดูใบไม้ร่วง',  'เวลาที่เผชิญหน้ากับตัวเอง ให้มีหัวใจที่เข้มงวดดั่งฤดูหนาว']  
f =  open('samejima.txt','w',encoding='utf-8')  
f.writelines(s)  
f.close()

เพียงแต่ว่าจะไม่มีการเว้นบรรทัดให้ระหว่างสายอักขระแต่ละท่อน ถ้าต้องการก็ต้องเพิ่มเอาเอง ถ้าจะใช้ write ก็อาจใช้เป็น f.write('\n’.join(s)) คือใช้เมธอด join เพื่อรวมสายอักขระเข้าด้วยกันโดยมีการขึ้นบรรทัดใหม่เป็นตัวแบ่ง หรืออาจจะเขียนต่อๆกันไปเลยก็ได้ การใช้คำสั่ง write หลายครั้งจะเป็นการเขียนต่อไปเรื่อยๆ โดยจะไม่มีการขึ้นบรรทัดใหม่ให้ดังนั้นต้องเติม ‘\n’ ไปด้วย

for  a  in  s:  
f.write(a+'\n')

สิ่งที่จะเขียนได้นั้นต้องเป็นสายอักขระเท่านั้น หากไม่ใช่สายอักขระก็ต้องแปลงก่อน
ตัวอย่าง โปรแกรมเขียนเลข 1 ถึง 10000 ลงไฟล์

f =  open('10000.txt','w',encoding='utf-8')  
for  i  in  range(1,10001):  
f.write('|%d|'%i)  
if(i%100==0): f.write('\n')  # ขึ้นบรรทัดใหม่ถ้านับถึง 100  
f.close()

แค่พิมพ์โค้ดสั้นๆแค่นี้ก็มีเลขโผล่ขึ้นมาถึงหมื่นภายในพริบตา ขนาดไฟล์หลายสิบกิโลไบต์ ลองคิดดูว่าถ้าเปลี่ยนจากหมื่นเป็นพันล้านจะเป็นอย่างไร เท่านี้ก็สามารถไปประยุกต์สร้างไวรัสอย่างง่ายๆได้แล้ว ลองเขียนโปรแกรมทำนองนี้แล้วส่งให้ไปรันในเครื่องคนอื่นก็จะเกิดไฟล์ขนาดใหญ่ขึ้นอย่างรวดเร็ว แค่คิดก็น่ากลัวแล้ว ตัวอย่างทั้งหมดนี้ใช้โหมด r คือพอเปิดไฟล์มาก็จะถูกลบทิ้งแล้วเริ่มเขียนใหม่ทันที ถ้าอยากให้ไฟล์เขียนต่อก็แค่เปลี่ยน r เป็น a เท่านั้น ลองทำดูกันได้

การคัดลอกไฟล์

เมื่อสามารถเปิดอ่านและสามารถเขียนไฟล์ได้แล้ว ต่อไปสิ่งที่จะทำได้ตามมาอย่างไม่ยากก็คือการนำข้อมูลจากไฟล์หนึ่งคัดลอกไปลงในอีกไฟล์ ซึ่งก็คือการอ่านไฟล์หนึ่ง ดึงข้อมูลมา แล้วก็นำไปเขียนในอีกไฟล์ ลองดูตัวอย่าง

f1 =  open('nishikaze.txt','r',encoding='utf-8')  # เปิดไฟล์ต้นฉบับ  
f2 =  open('nishikaze2.txt','w',encoding='utf-8')  # กำหนดไฟล์ใหม่ที่จะเขียน  
a = f1.read()  # นำข้อมูลจากไฟล์ต้นฉบับมาเก็บในตัวแปร  
f2.write(a)  # นำข้อมูลจากตัวแปรมาเขียนลงในไฟล์ใหม่  
f1.close()  # ปิดไฟล์ต้นฉบับ  
f2.close()  # ปิดไฟล์ที่เขียนเสร็จ

เท่านี้ก็จะได้ไฟล์ใหมที่เหมือนกับไฟล์ต้นฉบับทุกประการ แต่ความจริงแล้วนอกจากนี้ยังมีอีกวิธีที่ง่ายกว่านั้น นั่นคือใช้ฟังก์ชัน copyfile ในมอดูล shutil

import  shutil  
shutil.copyfile('nishikaze.txt',  'nishikaze2.txt')

นอกจากนี้ยังมีฟังก์ชัน move เอาไว้ย้ายไฟล์

import  shutil  
shutil.move('nishikaze2.txt',  'nishikaze3.txt')

เท่านี้ข้อมูลจากไฟล์เดิมก็ย้ายไปอยู่ในไฟล์ชื่อใหม่ แค่การคัดลอกมาทั้งหมดอาจดูง่ายไปไม่ค่อยมีอะไร เราลองมาทำอะไรที่ต้องออกแรงมากกว่านั้นสักหน่อย ต่อไปเป็นการนำข้อความจากไฟล์ต้นฉบับมาแตกออกเป็นไฟล์ย่อยแบ่งทีละบรรทัด

f =  open('nishikaze.txt','r',encoding='utf-8')  # เปิดไฟล์ต้นฉบับ  
i = 1  
for  r  in  f:  # วนซ้ำเพื่อแยกวิเคราะห์ทีละบรรทัด  
if(r=='\n'): continue  # หากบรรทัดไหนว่างเปล่าก็ข้ามไปเลย ไม่ต้องสร้างไฟล์ บรรทัดที่ว่างคือบรรทัดที่มีแต่ \n คือคำสั่งขึ้นบรรทัดใหม่  
fw =  open('n%02d.txt'%i,'w',encoding='utf-8')  # สร้างไฟล์ใหม่ ตั้งชื่อเป็น n ตามด้วยหมายเลข  
fw.writelines(r)  # เขียนข้อมูลที่อ่านได้ในบรรทัดนั้นลงไฟล์  
fw.close()  # ปิดไฟล์ที่เขียน  
i += 1  
f.close()  # ปิดไฟล์ต้นฉบับ

การจัดเก็บข้อมูลเพื่อใช้งาน

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

rahat =  input('ป้อนรหัสผู้สอบ: ')  
physics =  input('คะแนนฟิสิกส์: ')  
chemi =  input('คะแนนเคมี: ')  
chiwa =  input('คะแนนชีวะ: ')  
f =  open('khanaen.txt','a',encoding='utf-8')  
f.write('%s %s %s %s\n'%(rahat,physics,chemi,chiwa))  
f.close()

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

590001 90 76 84  
590003 99 90 88  
590007 80 92 100

ข้อมูลแบบนี้นำมาใช้งานได้ง่าย หากต้องการดึงข้อมูลคะแนนทั้งหมดมาวิเคราะห์ก็เปิดไฟล์ขึ้นมาอ่านแล้ว read แล้ว split แยกเอาแต่ละส่วน เช่นเอาข้อมูลที่ได้นี้มาหาค่าต่ำสุด สูงสุด และค่าเฉลี่ย

f =  open('khanaen.txt','r',encoding='utf-8')  
physics = []  
chemi = []  
chiwa = []  
for  s  in  f:  
a = s.split()  
physics += [int(a[1])]  
chemi += [int(a[2])]  
chiwa += [int(a[3])]  
f.close()  
print('คะแนนฟิสิกส์ ต่ำสุด=%d, สูงสุด=%d, เฉลี่ย=%.2f'%(min(physics),max(physics),sum(physics)/len(physics)))  
print('คะแนนเคมี ต่ำสุด=%d, สูงสุด=%d, เฉลี่ย=%.2f'%(min(chemi),max(chemi),sum(chemi)/len(chemi)))  
print('คะแนนชีววิทยา ต่ำสุด=%d, สูงสุด=%d, เฉลี่ย=%.2f'%(min(chiwa),max(chiwa),sum(chiwa)/len(chiwa)))

บางครั้งตัวกั้นข้อมูลก็อาจใช้แท็บ \t หรือในกรณีไฟล์ชนิด .csv จะกั้นด้วยจุลภาค , จะใช้เป็นอะไรก็ได้ แต่เวลาเปิดอ่านข้อมูลก็ต้องรู้และระบุตัวแยกให้ถูกต้อง

สรุปเนื้อหา

  • การเขียนไฟล์ก็คล้ายกับการอ่านไฟล์ ต้องเปิดไฟล์ขึ้นมาก่อน โดยต้องเลือกโหมดเป็น w หรือ a
  • w กับ a ต่างกันตรงที่ w เป็นการเขียนทับ ส่วน a เป็นการเขียนต่อ
  • เมธอดที่ใช้เขียนคือ write และ writelines
  • write ใช้กับสายอักขระ ส่วน writelines ใช้กับลิสต์ของสายอักขระ
  • การคัดลอกไฟล์ทำได้โดยเปิดไฟล์ขึ้นมาอ่านแล้วเขียนใส่อีกไฟล์ หรือใช้ shutil.copyfile ก็ได้
  • สามารถใช้การอ่านและเขียนไฟล์เพื่อจัดการกับข้อมูลอย่างเป็นระบบได้

อ้างอิง
http://docs.python.jp/3/library/functions.html
http://diveintopython3-ja.rdy.jp/files.html
http://www.ops.dti.ne.jp/ironpython.beginner/textfile.html
http://www.yukun.info/blog/2008/09/python-file-write-writelines.html

Reference : https://phyblas.hinaboshi.com/tsuchinoko18