Objective-C Programming Chapter 11 (Part1)

File , Folder and data

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

File System Layout

เราควรจะทำความเข้าใจเบื้องต้นเกี่ยวกับโครงสร้างการจัดการไฟล์ก่อนที่จะไปใช้คลาสต่างๆที่เกี่ยวไฟล์ ในระบบ Mac OS X นั้น โครงสร้างของระบบไฟล์จะใช้ระบบการเช่นเดียวกันกับระบบปฎิบัติการที่มีพื้นฐานมาจาก Unix เช่น Free BSD หรือ Linux นั่นคือ มีลักษณะเหมือนรากของต้นไม้

ch11_1

โดยแบ่งออกเป็น 2 ส่วนใหญ่ๆด้วยกัน ส่วนแรก System Files คือไฟล์ของระบบปฎิบัติการ ในส่วนนี้ผู้ใช้งานทั่วๆไปไม่สามารถเข้าไปแก้ไขจัดการได้ ส่วนที่สองคือ User Files ซึ่งเป็นส่วนที่อนุญาติให้ผู้ใช้แต่ละคนสามารถจัดการไฟล์ต่างๆได้ด้วยตัวเอง ระบบปฎิบัติการจะแยกไฟล์ของผู้ใช้แต่ละคนออกจากกัน ซึ่งผู้ใช้แต่ละคนจะมี Home Directory เป็นของตัวเอง

Pathname
คือชื่อที่ใช้ในการอ้างอิงที่อยู่ของไฟล์ แบ่งออกเป็น 2 แบบด้วยกัน แบบแรกคือ absolute path เป็นการบอกที่อยู่ของไฟล์หรือโฟลเดอร์โดยมีจุดเริ่มต้นที่ root ซึ่งแทนด้วยเครื่องหมาย / และอยู่ตำแหน่งหน้าสุดของ path เสมอ ส่วนเครื่องหมาย / ต่อมาจะหมายถึง sub folder ยกตัวอย่างเช่นไฟล์ chapter_1.pdf ในรูปมี path คือ /User/Ter/Download/chapter_1.pdf
แบบที่สองคือ relative path จะเป็นการอ้างอิงกับตำแหน่งของโฟลเดอร์ที่กำลังทำงานในขณะนั้น เช่น สมมติว่ากำลังทำงานอยู่ที่ home directory เมื่อต้องการจะอ้างถึงไฟล์ chapter_1.pdf ก็จะได้ว่า Download/chapter_1.pdf
นอกจากเครื่องหมาย / จะใช้แทน root แล้วยังมีสัญลักษณ์พิเศษอีก 3 อย่างด้วยกัน อย่างแรกคือ ~ ที่ใช้แทน home directory เช่น สมมติว่าตอนนี้ผู้ใช้คือ Ter เราสามารถเขียน path ของไฟล์ chapter_1.pdf โดยใช้ ~ ได้ดังนี้ ~/Download/chapter_1.pdf อย่างที่สองคือ . (จุด) หมายถึงโฟลเดอร์ที่ใช้งานขณะนั้น และสุดท้ายคือ .. ( จุด จุด ) หมายถึงโฟลเดอร์ชั้นหน้า (parent folder) ของโฟลเดอร์ที่ใช้งานปัจจุบัน

NSFileManager

คลาสเกี่ยวกับไฟล์คลาสแรกที่ Foundation Framework ได้เตรียมไว้ก็คือ NSFileManger คลาสนี้มีเมธอดพื้นฐานอยู่หลายเมธอดด้วยกัน อาทิเช่น การสร้างไฟล์ คัดลอกไฟล์ การย้ายไฟล์หรือไดเรกทอรี รวมไปถึงการขอข้อมูลเบี้องต้นของไฟล์และโฟลเดอร์เช่น ขนาดของไฟล์ วันที่เปลี่ยนแปลงล่าสุด คลาสนี้ยังมีเมธอดเกี่ยวกับการจัดการไฟล์ในระบบเคลือข่ายแบบกลุ่มเมฆ1 อีกด้วย แต่สามารถใช้ได้กับระบบปฎิบัติการ Mac OS X 10.7 และ iOS 5.0 ขึ้นไป การใช้งานโดยส่วนใหญ่สามารถทำผ่านออบเจ็กต์ที่เรียกว่า shared object ซึ่งเป็นออบเจ็กต์ที่มีคุณลักษณะพิเศษคือออบเจ็กต์นี้มีเพียงแค่ออบเจ็กต์เดียวและใช้ร่วมกันทั้งโปรแกรม หรือเรียกว่า Singleton อีกทั้งยังรองรับการทำงานร่วมกันหลาย thread (thread safe) อย่างไรก็ตามเรายังสามารถที่จะสร้างออบเจ็กต์ของคลาสนี้ได้ตามปกติ

Program 11.1
Main.m

Program 11.1 Output

Test Text 123
File type NSFileTypeRegular
File size 13

โปรแกรมที่ 11.1 นี้เป็นโปรแกรมตัวอย่างสาธิตการใช้งานเมธอดต่างๆของคลาส NSFileManager โปรแกรมจะเริ่มด้วยการสร้าง shared object ของ NSFileManager ด้วยเมธอด defaultManager จากนั้นบรรทัดที่ 13 ใช้ฟังก์ชั่น NSHomeDirectory ขอที่อยู่ home directory ของผู้ใช้งานคนปัจจุบัน เพื่อจะนำมาใช้ในการสร้าง path ของไฟล์ test.txt ที่อยู่ในโฟลเดอร์ Desktop ต่ออีกทีหนึ่ง เพื่อให้แน่ใจว่ามีไฟล์นี้อยู่จริง เราเรียกเมธอด fileExistsAtPath: เพื่อทำการตรวจสอบ เมื่อตรวจสอบเรียบร้อยโปรแกรมก็จะแสดงข้อมูลในไฟล์ ต่อมาบรรทัดที่ 32 โปรแกรมจะคัดลอกไฟล์

สิ่งที่น่าสนใจของคำสั่งนี้คือพารามิเตอร์สุดท้ายนั้นรับ address of pointer ของ NSError ดังนั้นเราจึงต้องประกาศพอยน์เตอร์ และส่ง adress ของพอยน์เตอร์นั้น ด้วยการใส่เครื่องหมาย & นำหน้า เมื่อเกิดข้อผิดพลาดขึ้นมาเมธอดนี้จะส่งค่ากลับมายังพอยน์เตอร์ของเราพร้อมรายละเอียดต่างๆ เช่น error code เป็นต้น ในกรณีที่ไม่เกิดข้อผิดพลาด error ก็จะเป็น nil และค่า copyResult จะเป็น YES จากนั้นโปรแกรมจะทำการเปรียบเทียบไฟล์ที่คัดลอกกับไฟล์ต้นฉบับ จากนั้นบรรทัดที่ 42 ก็จะเปลี่ยนชื่อไฟล์ และเราเรียกเมธอด attributeOfItemAtPath เพื่อขอรายละเอียดของไฟล์ เมื่อเราเปิดดู API Document2 จะเห็นว่าเมธอดนี้จะให้ NSDirctionary กลับมา
ch11_2

ดิกชันนารีที่ได้กลับมานี้จะมี key ต่างๆซึ่งจะอธิบายในส่วนของ File Attribute Keys และเมื่อเราเปิดไปดูที่ File Attribute Keys ก็จะเห็นว่ามีคีย์หลายอย่างมาก เช่น NSFileSize เพื่อหาขนาดของไฟล์ เป็นต้น และสุดท้ายก็ลบไฟล์ที่ที่เราได้คัดลอกจากต้นฉบับ

ch11_3

โปรแกรมที่เราได้เขียนไปเป็นเพียงแค่การสาธิตการใช้งานในส่วนของเมธอดที่เกี่ยวกับไฟล์เท่านั้น  คลาส NSFileManager ยังมีเมธอดที่เกี่ยวกับ Directory หรือ Folder

Program 11.2
Main.m

โปรแกรมที่ 11.2 เริ่มจากการแสดงโฟลเดอร์ที่กำลังทำงานอยู่ หลังจากนั้นก็เปลี่ยนมาที่ Desktop ของผู้ใช้ และบรรทัดที่ 20

เมธอดนี้รับพารามิเตอร์ถึง 4 ค่าด้วยกัน ค่าแรกคือชื่อของโฟลเดอร์ที่ต้องการ เมธอดนี้รองรับ path ทั้งแบบ absolute path และ relative path ในตัวอย่างเราใช้ relative path ดังนั้นแล้วโฟลเดอร์ก็จะถูกสร้างที่ Desktop ของผู้ใช้ ส่วนค่าที่สองหากระบุให้เป็น YES ในกรณีที่ไม่มี parent folder ที่กำหนด โปรแกรมจะสร้างโฟลเดอร์ให้ใหม่รวมถึง parent folder ด้วย เช่น สมมติว่าโปรแกรมทำงานที่ Desktop และถ้าเรากำหนด path เป็น Test/Demo แต่ยังไม่มีโฟลเดอร์ Test โปรแกรมก็จะสร้างทั้งสองโฟรเดอร์คือ Test และ Demo ต่อมาเป็นพารามิเตอร์ที่สามเป็นการกำหนดค่า attribute ให้กับโฟลเดอร์ แต่เราไม่ต้องการกำหนดอะไรเป็นพิเศษจึงใส่ค่า nil และพารามิเตอร์สุดท้ายคือค่า error (ใส่เป็น nil ก็ได้) เมื่อเราสร้างโฟลเดอร์เรียบร้อยแล้ว แต่ไปก็เปลี่ยนชื่อของโฟลเดอร์ เมื่อโปรแกรมทำงานจบลง ที่ Desktop ก็จะมีโฟลเดอร์ที่เราได้สร้างขึ้นนั่นเอง

Program 11.2 Output

Current directory path is /Users/Ter/Library/Developer/Xcode/DerivedData/Program_11.2-exeytenwzmypuzeedbcamrujncfg/Build/Products/Debug

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

Program 11.3
Main.m

Program 11.3 Output

Chapter_7.pdf
Chapter_9.pdf
untitled folder
untitled folder/Chapter_10.pdf
——-
Chapter_7.pdf
Chapter_9.pdf
untitled folder

โปรแกรมที่ 11.3 จะแสดงไฟล์และโฟลเดอร์ตาม path ที่เราได้กำหนดไว้ ซึ่งมีด้วยกันสองวิธีคือ แบบแรกใช้เมธอด enumeratorAtPaht: ส่วนวิธีที่สองใช้เมธอด contentsOfDirectoryAtPath: เมธอดทั้งสองนี้สามารถแสดงไฟล์และโฟลเดอร์ได้เหมือนกัน แต่ผลลัพธ์แตกต่างกัน โดยแบบแรกนั้นจะแสดงโฟรเดอร์ย่อยด้านใน รวมถึงไฟล์ที่อยู่ในโฟลเดอร์ย่อยอีกด้วย เช่นตัวอย่าง output จะเห็นว่าแบบแรกได้แสดงโฟลเดอร์ untitled folder และไฟล์ Chapter_10.pdf ด้วย ส่วนเมธอดที่สองนั้นจะแสดงแค่ชื่อของโฟลเดอร์ untitled folder เท่านั้น ไม่ได้แสดงรายการภายใน
อย่างไรก็ตาม เราสามารถที่จะทำให้เมธอดแรกนั้นแสดงผลลัพธ์เหมือนอย่างวิธีที่สองได้เช่นกัน โดยการเพิ่มเติมโค้ดในการตรวจสอบว่าถ้าหาก path นั้นเป็นโฟลเดอร์ก็เรียกเมธอด skipDescendants เพื่อให้ข้ามการทำงาน ดังเช่นตัวอย่าง

เมธอด fileExistsAtPath:isDirectory นั้นจะส่งค่ากลับมาเป็น YES ในกรณีที่ path นั้นมีอยู่จริง ส่วนค่า flag จะได้กลับมาเป็น YES ในกรณี path นั้นเป็นโฟลเดอร์

Leave a Reply