檔案輸入與輸出 - 碁峰資訊epaper.gotop.com.tw/pdfsample/acl041500.pdf ·...

13
檔案輸入與輸出 檔案的輸入與輸出(File I/O) 不同於標準的輸入與輸出,前者所有輸入與輸出的動作 都是針對檔案,而後者的輸入動作是從鍵盤讀取資料,而輸出則是從螢幕顯示結 果。當然,檔案的 I/O 之好處為,若輸入的資料很多時,可以先將其建檔,待要使 用時再開啟。這可防止鍵入資料有誤時的修改,並可以重複使用此資料,也可以將 輸出結果的檔案做為下次輸入的資料。 由於 Mac OS X UNIX 的作業系統,有關使用 UNIX 的路徑規則,我們列出下面 幾個簡單的觀念供讀者參考: 系統的根目錄(root directory) 是以 / 開始,以資料夾的方式為所有的檔案分 類。 系統使用者的家目錄(home directory) ,通常以 “~使用者名稱表示,例如, ~Bright 表示使用者 Bright 的家目錄。若直接以~則代表目前使用者的家目 錄。 若使用 ./ 加上路徑名稱,則是指當下所在的目錄開始算起。例如:假設 test.m 所在絕對路徑為 “/Users/Bright/test/test.m”,而目前路徑位於 Bright 的家目錄 下,若要查看檔案 test.m ,則指定的路徑為 ./test/test.m ,此路徑也表示為 ~Bright/test/test.m 若使用 ../ 加上路徑名稱,則代表上一層目錄內的檔案。例如:若現在依然位 Bright 的家目錄下,若要進入使用者 Jerry 底下的 exam 目錄,則移動的目 錄路徑為 ../Jerry/exam ,可表示為 ~Jerry/exam ,或完整檔案路徑 : “/Users/Jerry/exam”以下我們將以檔案的類別來加以討論之。

Upload: others

Post on 03-Jun-2020

5 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: 檔案輸入與輸出 - 碁峰資訊epaper.gotop.com.tw/PDFSample/ACL041500.pdf · 檔案的輸入與輸出(File I/O)不同於標準的輸入與輸出,前者所有輸入與輸出的動作

檔案輸入與輸出

檔案的輸入與輸出(File I/O)不同於標準的輸入與輸出,前者所有輸入與輸出的動作

都是針對檔案,而後者的輸入動作是從鍵盤讀取資料,而輸出則是從螢幕顯示結

果。當然,檔案的 I/O 之好處為,若輸入的資料很多時,可以先將其建檔,待要使

用時再開啟。這可防止鍵入資料有誤時的修改,並可以重複使用此資料,也可以將

輸出結果的檔案做為下次輸入的資料。

由於 Mac OS X是 UNIX的作業系統,有關使用 UNIX的路徑規則,我們列出下面

幾個簡單的觀念供讀者參考:

系統的根目錄(root directory)是以 / 開始,以資料夾的方式為所有的檔案分

類。

系統使用者的家目錄(home directory),通常以 “~使用者名稱” 表示,例如,

~Bright 表示使用者 Bright 的家目錄。若直接以~,則代表目前使用者的家目

錄。

若使用 ./ 加上路徑名稱,則是指當下所在的目錄開始算起。例如:假設 test.m

所在絕對路徑為 “/Users/Bright/test/test.m”,而目前路徑位於 Bright 的家目錄

下,若要查看檔案 test.m,則指定的路徑為 ./test/test.m,此路徑也表示為

~Bright/test/test.m。

若使用 ../ 加上路徑名稱,則代表上一層目錄內的檔案。例如:若現在依然位

於 Bright 的家目錄下,若要進入使用者 Jerry 底下的 exam 目錄,則移動的目

錄 路 徑 為 ../Jerry/exam , 可 表 示 為 ~Jerry/exam , 或 完 整 檔 案 路 徑 :

“/Users/Jerry/exam”。

以下我們將以檔案的類別來加以討論之。

Page 2: 檔案輸入與輸出 - 碁峰資訊epaper.gotop.com.tw/PDFSample/ACL041500.pdf · 檔案的輸入與輸出(File I/O)不同於標準的輸入與輸出,前者所有輸入與輸出的動作

20-2

學會 Objective-C 的 24 堂課

20.1 NSFileManager 類別的方法 您可使用 NSFileManager 物件執行一些有關目錄與檔案的操作,舉凡目錄與檔案的

建立、擷取檔案的內容(當作是 NSData物件),刪除目錄或檔案,複製、移動檔案或

目錄,查閱或設定檔案的屬性等等,都可以此類別完成之。若需具有執行緒安全,

請務必以 alloc 手動建立,並初始化 NSFileManager,勿以 +defaultManager 類別方

法建立之。NSFileManager常見的方法,如表 20-1與表 20-2所示:

表 20-1 NSFileManager 用於檔案操作的方法

方法 說明

- (BOOL)createFileAtPath:(NSString *)path

contents:(NSData *)contents

attributes:(NSDictionary *)attributes

建 立 具 有 contents 的 內 容 , 以 及attributes 屬性的檔案。若建立成功則回傳 YES,否則回傳 NO

- (NSDictionary *)attributesOfItemAtPath:

(NSString *)path error:(NSError **)error

回傳 path指定的檔案或目錄屬性,若過程有發生任何錯誤,則將錯誤訊息記錄

於 error物件

- (BOOL)removeItemAtPath:(NSString *)path

error:(NSError **)error

若成功刪除 path指定的檔案、連結、目錄,則回傳 YES,否則將錯誤訊息記錄

於 error 物件,並回傳 NO。(此方法將

刪除所有子目錄中的內容)

- (BOOL)moveItemAtPath:(NSString *)srcPath

toPath:(NSString *)dstPath error:(NSError

**)error

將 srcPath 的檔案或目錄移至 dstPath。若移動成功,則回傳 YES,否則回傳

NO。(僅最後一層名稱不同,代表更改

名稱)

- (BOOL)fileExistsAtPath:

(NSString *)path

若 path指定的檔案存在,則回傳 YES,

否則回傳 NO

表 20-2 NSFileManager 用於目錄操作的方法

方法 說明

- (BOOL)createDirectoryAtPath: (NSString *)

path attributes:(NSDictionary *)attributes

error:(NSError **)error

建立 path 指定的目錄,且此目錄具有attributes 的屬性。若成功建立目錄,則回

傳 YES,否則回傳 NO

- (BOOL)changeCurrentDirectoryPath:

(NSString *)path

改變目前的目錄為 path

- (NSString *)currentDirectoryPath 回傳目前程式所在之路徑

- (NSArray *)directoryContentsAtPath:path 列出目錄為 path的內容

- (NSDirectoryEnumerator *)

enumeratorAtPath:(NSString *)path

回傳 path 指定路徑的內容,內容包含檔案與目錄

Page 3: 檔案輸入與輸出 - 碁峰資訊epaper.gotop.com.tw/PDFSample/ACL041500.pdf · 檔案的輸入與輸出(File I/O)不同於標準的輸入與輸出,前者所有輸入與輸出的動作

20-3

Chapter 20 檔案輸入與輸出

方法 說明

- (BOOL)fileExistsAtPath:

(NSString *)path

若 path 指定的檔案存在,則回傳 YES,

否則回傳 NO

以下示範如何利用 NSFileManager 建立檔案,查看檔案屬性與刪除檔案,請參閱範

例程式 ns_file_manager。

範例程式 ns_file_manager

// ns_file_manager #import <Foundation/Foundation.h> int main(int argc, const char * argv[]) { @autoreleasepool { // 建立 NSFileManager 類別 NSFileManager *fmanager = [[NSFileManager alloc] init]; // 儲存系統暫存目錄的路徑 NSString *dirPath = NSTemporaryDirectory(); NSLog(@"暫存檔路徑: %@", dirPath); // 新檔案建立的路徑與名稱 NSString *newFile = [dirPath stringByAppendingPathComponent: @"testFile"]; // 若 testFile檔案不存在,建立此檔案 if ([fmanager fileExistsAtPath: newFile] == YES) NSLog(@"檔案 testFile 已存在!!"); else [fmanager createFileAtPath: newFile contents: nil attributes: nil]; // 取得並列出 testFile 的屬性 NSDictionary *attr = [fmanager attributesOfItemAtPath: newFile error: NULL]; NSLog(@"\n 印出 testFile的屬性"); for(NSString *tempAttr in attr) NSLog(@"%@ - %@", tempAttr, [attr objectForKey: tempAttr]); // 移除 testFile檔案 NSLog(@"\n 移除 testFile檔案..."); [fmanager removeItemAtPath: newFile error: NULL]; } return 0; }

Page 4: 檔案輸入與輸出 - 碁峰資訊epaper.gotop.com.tw/PDFSample/ACL041500.pdf · 檔案的輸入與輸出(File I/O)不同於標準的輸入與輸出,前者所有輸入與輸出的動作

20-4

學會 Objective-C 的 24 堂課

輸出結果

暫存檔路徑: /var/folders/j8/j8E45ELUEtCWp3g9w2y2DE+++TI/-Tmp-/ 印出 testFile 的屬性 NSFileOwnerAccountID - 501 NSFileHFSTypeCode - 0 NSFileSystemFileNumber - 1575309 NSFileExtensionHidden - 0 NSFileSystemNumber - 234881026 NSFileSize - 0 NSFileGroupOwnerAccountID - 20 NSFileHFSCreatorCode - 0 NSFileOwnerAccountName - bright NSFilePosixPermissions - 420 NSFileCreationDate - 2010-07-15 15:11:27 +0800 NSFileType - NSFileTypeRegular NSFileGroupOwnerAccountName - staff NSFileReferenceCount - 1 NSFileModificationDate - 2010-07-15 15:11:27 +0800 移除 testFile 檔案...

程式利用 NSTemporaryDirectory() 函式,找出使用者暫存目錄的路徑,這是系統給

定的,然後將它指定給路徑 dirPath,接著以 NSString 的 stringByAppending

PathComponent: 方法,將檔案路徑 dirPath加上檔案名稱 testFile。

接下來使用 fmanager 建立檔案時,需先確定是否有同樣的暫存檔,因為 fmanager

會蓋過原始的檔案。此處 contents 為 nil,代表建立無內容的檔案。attributes 若為

nil,則以預設的檔案屬性建立。

接下來列舉檔案的各種屬性,最後使用 removeItemAtPath:方法刪除此暫存檔,

NULL表示不需儲存錯誤資訊。

小提示

nil是透過巨集定義的 NULL,此位於 MacTypes.h標頭檔,定義式如下:

#define nil NULL

此程式使用的 NSTemporaryDirectory() 是 Foundation framework的基本函式,功能

為建立一暫時目錄。stringByAppendingPathComponent:是 NSString對於檔案路徑的

方法,支援檔案系統的路徑操作。

在 NSString類別下用於路徑操作的方法,如表 20-3所示:

Page 5: 檔案輸入與輸出 - 碁峰資訊epaper.gotop.com.tw/PDFSample/ACL041500.pdf · 檔案的輸入與輸出(File I/O)不同於標準的輸入與輸出,前者所有輸入與輸出的動作

20-5

Chapter 20 檔案輸入與輸出

表 20-3 NSString 類別下路徑的操作方法

函式 說明

NSString * NSFullUserName (void) 回傳目前使用者的完整名稱

NSString * NSHomeDirectory (void) 回傳目前使用者家目錄的路徑

NSString * NSHomeDirectoryForUser

(NSString *userName)

回傳使用者 userName 家目錄的路

NSString * NSTemporaryDirectory (void) 回傳目前使用者暫存目錄的路徑

方法 說明

+ (NSString *)pathWithComponents:

(NSArray *)components

以 components陣列為初始數值,初始為檔案路徑格式

- (NSArray *)pathComponents 回傳依字串路徑切分的字串陣列

- (NSString *)lastPathComponent 取得字串路徑最後一個檔案或目錄

名稱

- (NSString *)pathExtension 取得字串路徑的延伸檔名

- (NSString *)stringByAppendingPathComponent:

(NSString *) aString 在字串尾端附加檔案或目錄名稱

- (NSString *)stringByAppendingPathExtension:

(NSString *) ext 在字串尾端附加檔案的延伸檔名

- (NSString *)stringByDeletingLastPathComponent 刪除字串路徑最後一個檔案或目錄

的名稱

- (NSString *)stringByDeletingPathExtension 刪除字串路徑的延伸檔名

- (NSString *)stringByExpandingTildeInPath

將字串路徑中的 ~ (目前使用者家

目錄)與 ~user(指定使用者家目錄)

展開為完整路徑

- (NSString *)stringByStandardizingPath 將字串路徑標準化,展開 ~、

~user,去除 //、./、/、..

以下我們將使用 NSFileManager 示範目錄的新增、更名、刪除、查看目錄內容等功

能,請參閱範例程式 ns_file_manager_directory。

範例程式 ns_file_manager_directory

// ns_file_manager_directory #import <Foundation/Foundation.h> int main(int argc, const char * argv[]) { @autoreleasepool { NSFileManager *fmanager = [[NSFileManager alloc] init]; NSString *dirPath = [fmanager currentDirectoryPath]; NSString *createPath = [dirPath stringByAppendingPathComponent:

Page 6: 檔案輸入與輸出 - 碁峰資訊epaper.gotop.com.tw/PDFSample/ACL041500.pdf · 檔案的輸入與輸出(File I/O)不同於標準的輸入與輸出,前者所有輸入與輸出的動作

20-6

學會 Objective-C 的 24 堂課

@"testDirectory"]; NSString *movePath = [dirPath stringByAppendingPathComponent: @"moveDirectory"]; // 建立指定目錄 [fmanager createDirectoryAtPath: createPath withIntermediateDirectories: YES attributes: nil error: NULL]; // 更改指定目錄名稱 [fmanager moveItemAtPath: createPath toPath: movePath error: NULL]; // 列出目錄下的檔案 NSLog(@"印出路徑: %@ 中的所有內容", dirPath); NSString *path; BOOL isDir; NSDirectoryEnumerator *dirEnum = [fmanager enumeratorAtPath: dirPath]; while ((path = [dirEnum nextObject]) != nil) { [fmanager fileExistsAtPath:path isDirectory: &isDir]; NSLog(@"%@名稱為%@", (isDir == YES)? @"目錄": @"檔案" , path); } // 刪除指定目錄 [fmanager removeItemAtPath: movePath error: NULL]; } return 0; }

輸出結果

印出路徑: /Users/jerry/Documents/ns_file_manager_directory/build/Debug 中的所有內容 目錄名稱為 moveDirectory 檔案名稱為 ns_file_manager_directory

需特別注意:

[fmanager createDirectoryAtPath: createPath withIntermediateDirectories: YES attributes: nil error: NULL];

此敘述建立 createPath 指定的目錄,其中在 withIntermediateDirectories:之後的參

數,表示路徑之間有名稱不存在時,若指定為 YES,則自動建立,若指定為 NO,

則不自動建立。後面的 nil 和 NULL,分別代表屬性為預設值,且錯誤訊息可被忽

略。下一敘述:

[fmanager moveItemAtPath: createPath toPath: movePath error: NULL];

將 createPath的目錄移至 movePath的目錄。注意 movePath 不能是一個已存在的目

錄。最後程式以 enumeratorAtPath:方法取得 dirPath 目錄下的檔案列舉,以下程式

列出目錄中的內容,並識別是否為檔案或目錄。

Page 7: 檔案輸入與輸出 - 碁峰資訊epaper.gotop.com.tw/PDFSample/ACL041500.pdf · 檔案的輸入與輸出(File I/O)不同於標準的輸入與輸出,前者所有輸入與輸出的動作

20-7

Chapter 20 檔案輸入與輸出

while ((path = [dirEnum nextObject]) != nil) { [fmanager fileExistsAtPath: path isDirectory: &isDir]; NSLog(@"%@名稱為%@", (isDir == YES)? @"目錄": @"檔案" , path); }

dirEnum是 NSDirectoryEnumerator型態,它是 NSEnumerator的子類別,因此能以

nextObject 方法取得下一個物件,若回傳的物件為 nil,則代表已經讀完所有資料。

fileExistsAtPath:isDirectory:方法能判斷是否為目錄,請注意,因為 isDir 前面有加

上 &,因此 isDir 變數是以位址的方式傳入,這與其他方法中需傳入 NSError 相

同。接著再以三元運算子判斷確定與否。最後的 removeItemAtPath:方法,用以刪除

指定路徑的檔案、連結或目錄。請注意 movePath不能是 . 或 ..。

20.2 NSString 類別的運作 文字 I/O 是將位元串流透過文字編碼的轉換,再將內容呈現於程式中,所以

NSString 在檔案的操作上,最重要的是編碼的問題。請參閱範例程式

ns_string_io。

範例程式 ns_string_io

// ns_string_io #import <Foundation/Foundation.h> int main(int argc, const char * argv[]) { @autoreleasepool { // 建立檔案路徑以及預寫入的字串 NSString *path = [NSHomeDirectory() stringByAppendingPathComponent: @"Documents/testFile"]; NSLog(@"完整路徑為: %@", path); NSString *wContent = @"Hello world!!"; // 將字串寫入檔案 [wContent writeToFile: path atomically: YES encoding: NSUTF8StringEncoding error: NULL]; // 查看寫入的檔案內容 NSString *rContent = [NSString stringWithContentsOfFile: path encoding: NSUTF8StringEncoding error: NULL]; NSLog(@"content: \n%@", rContent); } return 0; }

Page 8: 檔案輸入與輸出 - 碁峰資訊epaper.gotop.com.tw/PDFSample/ACL041500.pdf · 檔案的輸入與輸出(File I/O)不同於標準的輸入與輸出,前者所有輸入與輸出的動作

20-8

學會 Objective-C 的 24 堂課

輸出結果

完整路徑為: /Users/jerry/Documents/testFile content: Hello world!!

需特別注意:

[wContent writeToFile: path atomically: YES encoding: NSUTF8StringEncoding error: NULL];

這裡 atomically:的 YES是指,先將內容存於輔助的檔案名稱,當成功儲存後,再將

它更名為指定的檔案名稱;若為 NO,則直接以指定的檔案名稱進行儲存,若進行

寫入的過程被中斷,將會造成檔案損毀。

編碼的關鍵字 NSUTF8StringEncoding 是列舉型態,定義於檔頭檔 NSString.h,此

標頭檔以列舉型態定義一些有關編碼的符號常數,如表 20-4所示:

表 20-4 有關編碼的符號常數

符號常數名稱 說明

NSASCIIStringEncoding 8-bit 中,有 7-bit 是 ASCII 編碼,值域為 0 到

127

NSUTF8StringEncoding Unicode 字元的 8-bit 表達法,以 ASCII 為基礎

的系統,用此進行傳輸或儲存

NSISOLatin1StringEncoding 8-bit的 ISO Latin 1編碼

NSISOLatin2StringEncoding 8-bit的 ISO Latin 2編碼

NSUnicodeStringEncoding 符合規範的字串物件編碼,採用 16-bit

NSWindowsCP1250StringEncoding Microsoft Windows 的 1250 編碼,相當於

WinLatin2

NSWindowsCP1252StringEncoding Microsoft Windows 的 1252 編碼,相當於

WinLatin1

NSUTF16StringEncoding NSUnicodeStringEncoding的別名

NSUTF32StringEncoding 32-bit的 UTF編碼

因此,若以選定的編碼進行,也得以相同的編碼執行解碼。

Page 9: 檔案輸入與輸出 - 碁峰資訊epaper.gotop.com.tw/PDFSample/ACL041500.pdf · 檔案的輸入與輸出(File I/O)不同於標準的輸入與輸出,前者所有輸入與輸出的動作

20-9

Chapter 20 檔案輸入與輸出

20.3 NSData 類別的運作 NSData 將檔案讀回程式,因此它的內容是以位元組方式呈現。一般而言,檔案輸

出入會建立位元緩衝區(byte buffer)。我們能將檔案以一定的大小分次讀入緩衝區,

接著再讓程式利用。這樣的好處在於硬體層能減少重複操作次數,而不是多次的間

斷寫入與讀取,I/O 效率會比沒有緩衝區更高。NSData 若用於 32 位元的應用程

式,儲存容量的最大限制是 2GB;若是 64 位元的應用程式,則上限會提升至

8EB(Exabyte,1018)。範例程式 ns_data_io使用 NSData,進行檔案的複製。

範例程式 ns_data_io

// ns_data_io #import <Foundation/Foundation.h> int main(int argc, const char * argv[]) { @autoreleasepool { // 建立檔案路徑以及預寫入的字串 NSString *path = [NSHomeDirectory() stringByAppendingPathComponent: @"test.mp3"]; NSString *newPath = [NSHomeDirectory() stringByAppendingPathComponent:@"newTest.mp3"]; // 將檔案的內容讀出 NSLog(@"讀取檔案\"%@\"...", path); NSData *data = [NSData dataWithContentsOfFile: path]; if (data == nil) { NSLog(@"無此檔案名稱"); return 1; } // 寫入檔案 NSLog(@"寫入檔案\"%@\"...", newPath); BOOL isTrue = [data writeToFile: newPath atomically: TRUE]; if (!isTrue) { NSLog(@"無此檔案名稱"); return 2; } NSLog(@"檔案複製完成..."); } return 0; }

輸出結果

讀取檔案"/Users/jerry/test.mp3"... 寫入檔案"/Users/jerry/newTest.mp3"... 檔案複製完成...

Page 10: 檔案輸入與輸出 - 碁峰資訊epaper.gotop.com.tw/PDFSample/ACL041500.pdf · 檔案的輸入與輸出(File I/O)不同於標準的輸入與輸出,前者所有輸入與輸出的動作

20-10

學會 Objective-C 的 24 堂課

為了進行示範,這裡挑選一首 mp3 格式的歌曲,將它讀入 NSData,再將它寫入另

一個指定檔案。這裡用到程式的 return 技巧,若程式遇見 return 敘述,則剩下的程

式都不會再執行。一般而言,return 0 是指正常結束,其他則代表異常結束,不同

的數字代表不同的問題,這端視程式設計師如何定義,哪一個數字該對應哪一個發

生的問題。本程式中 1表示讀取的檔案不存在,2代表寫入檔案錯誤。

20.4 NSFileHandle 類別的運作 NSFileHandle 對檔案具有基本的讀、寫、更新等模式。為什麼上述兩種類別

NSString與 NSData具有檔案讀寫的功能,卻還需要 NSFileHandle呢?原因是它具

有更進階的功能,以下列出三個重點:

1. 除了一般的讀寫外,NSFileHandle 另外提供 seek 移動檔案指標的功能,以及

truncate對檔案長度進行增減的功能。

2. NSFileHandle 除了對檔案的處理外,還包含許多通訊頻道 (communication

channel),例如以此概念實作的 socket、pipe及裝置等。

3. NSFileHandle能達到非同步的背景執行通訊。

表 20-5列出一些常用的 NSFileHandle方法。

表 20-5 常用的 NSFileHandle 方法

方法 說明

+ (id)fileHandleForReadingAtPath:

(NSString *)path 建立一個能讀取 path的 NSFileHandle物件

+ (id)fileHandleForWritingAtPath:

(NSString *)path 建立一個能寫入 path的 NSFileHandle物件

+ (id)fileHandleForUpdatingAtPath:

(NSString *)path

建立一個能讀取與寫入 path 的 NSFileHandle

物件

- (unsigned long long) seekToEndOfFile 將檔案指標移至檔案結尾,並回傳最後的檔案

指標位置

- (void)seekToFileOffset: (unsigned long

long)offset 將檔案指標移至偏移量為 offset的位置

- (void)writeData: (NSData *)data 寫入 data的內容

- (NSData *)readDataToEndOfFile 讀取內容,直到檔案結束或達到位元組的最大

數量,最後回傳讀取的內容

Page 11: 檔案輸入與輸出 - 碁峰資訊epaper.gotop.com.tw/PDFSample/ACL041500.pdf · 檔案的輸入與輸出(File I/O)不同於標準的輸入與輸出,前者所有輸入與輸出的動作

20-11

Chapter 20 檔案輸入與輸出

方法 說明

- (NSData *)readDataOfLength:

(NSUInteger)length 讀取 length個位元組

- (void)closeFile 關閉檔案

以下將示範 NSFileHandle的檔案寫入與讀取操作,請參閱範例程式 ns_file_handle_

write與 ns_file_handle_read。

範例程式 ns_file_handle_write

// ns_file_handle_write #import <Foundation/Foundation.h> int main(int argc, const char * argv[]) { @autoreleasepool { // 建立檔案路徑以及預寫入的字串 NSString *path = [NSHomeDirectory() stringByAppendingPathComponent: @"testFile"]; NSLog(@"完整路徑為: %@", path); NSString *content1 = @"*iPod** MacBook Pro"; // 建立一個具有 Apple內容的檔案 NSData *data = [@"Apple" dataUsingEncoding: NSUTF8StringEncoding]; [[NSFileManager defaultManager] createFileAtPath:path contents:data attributes:nil]; // 開啟檔案 NSFileHandle *out = [NSFileHandle fileHandleForWritingAtPath: path]; // 移到檔案結尾,並寫入字串 [out seekToEndOfFile]; [out writeData: [content1 dataUsingEncoding: NSUTF8StringEncoding]]; // offset 為 5,表示將檔案指標指到第六個元素的地方 NSString *content2 = @"$iPhone"; [out seekToFileOffset: 5]; [out writeData: [content2 dataUsingEncoding: NSUTF8StringEncoding]]; NSLog(@"檔案寫入完畢..."); // 關閉檔案 [out closeFile]; } return 0; }

Page 12: 檔案輸入與輸出 - 碁峰資訊epaper.gotop.com.tw/PDFSample/ACL041500.pdf · 檔案的輸入與輸出(File I/O)不同於標準的輸入與輸出,前者所有輸入與輸出的動作

20-12

學會 Objective-C 的 24 堂課

輸出結果

完整路徑為: /Users/jerry/testFile 檔案寫入完畢...

首先以 NSFileManager建立具有 @"Apple" 內容的檔案。out物件以寫入的形式取得

NSFileHandle,接著將檔案指標移到檔案結尾,然後寫入 content1 字串,

@"*iPod** MacBook Pro"。接著再將檔案指標移至字串的第六個元素的位置(因為

offset 為 5),寫入 content2 字串,@"$iPhone"。以下範例程式將剛才寫入的檔案讀

取之。

範例程式 ns_file_handle_read

// ns_file_handle_read #import <Foundation/Foundation.h> int main(int argc, const char * argv[]) { @autoreleasepool { // 建立檔案路徑以及預寫入的字串 NSString *path = [NSHomeDirectory() stringByAppendingPathComponent: @"testFile"]; NSLog(@"完整路徑為: %@", path); // 讀取檔案內容並印出 NSFileHandle *in = [NSFileHandle fileHandleForReadingAtPath: path]; NSString *inContent = [[NSString alloc] initWithData: [in readDataToEndOfFile] encoding: NSUTF8StringEncoding]; NSLog(@"content:\n %@", inContent); [in closeFile]; } return 0; }

輸出結果

完整路徑為: /Users/jerry/testFile content: Apple$iPhone MacBook Pro

由輸出結果得知,範例程式 ns_file_handle_write,寫入 content1 的內容,也就是寫

入*iPod** MacBook Pro字串,因此寫入 content1後 out的內容呈現如下:

Page 13: 檔案輸入與輸出 - 碁峰資訊epaper.gotop.com.tw/PDFSample/ACL041500.pdf · 檔案的輸入與輸出(File I/O)不同於標準的輸入與輸出,前者所有輸入與輸出的動作

20-13

Chapter 20 檔案輸入與輸出

Apple*iPod** MacBook Pro

從上一字的第六個位置(亦即*字元),寫入 content2 字串:"$Apple"。content2 的內

容寫入後,out內容呈現如下:

Apple$iPhone MacBook Pro

因為在第二次寫入後,$iPhone蓋掉原來 Apple之後的*iPod**。

NSFileHandle 也可使用 +(id)fileHandleForUpdatingAtPath: 的方式來建立並初始

化,此模式綜合以上的兩種讀寫功能。

20.5 習題 1. 利用 NSFileManager 類別所提供的方法,查看您的家目錄有哪些目錄,及查

閱某一目錄下有哪些檔案。

2. 利用 NSFileHandle 類別,建立一麻吉的通訊錄,每位麻吉包括姓名、出生年

月日、手機號碼及地址。再將剛建立好的檔案讀出,驗證寫入檔案的資料是

否正確。