移動開發(IOS) – Objective-C-07-文件管理
1.沙盒
1.1.iOS 中每個 App 應用程序都有一個單獨封閉的文件夾,這個文件夾稱爲沙盒 ( sandbox )
1.2.沙盒目錄用來存放 App 的本地文件,例如:音頻、視頻、圖片文件 …
1.3.當前 App 應用程序沒權限訪問其他 App 的沙盒。(更安全)
1.4.應用程序包:(Bundle)包含了所有的資源文件和可執行文件。
1.5.沙盒目錄中有如下子目錄:
1.5.1.Documents 存放長期使用的文件。保存應用運行時生成的需要持久化的數據,iTunes同步設備時會備份該目錄。
1.5.2.Library 系統存放文件。Library/Caches, 保存應用運行時生成的需要持久化的數據,iTunes同步設備時不會備份該目錄。一般存儲體積較大、不需要備份的非重要數據。Library/Preference:保存應用的所有偏好設置,iOS的設置應用會在該目錄中查找應用的設置信息。iTunes同步設備時會備份該目錄。
1.5.3.tmp 臨時文件,App 重啓時,該目錄下的文件清空。保存應用運行時所需的臨時數據,使用完畢後再將相應的文件從該目錄刪除。應用沒有運行時,系統也有可能會清除該目錄下的文件。iTunes同步設備時不會備份該目錄。
2.NSString 處理文件路徑
2.1.OC裏的文件路徑通過NSString來描述。
2.2.獲取沙盒路徑:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
 //沙盒的主⺫錄 NSString
*homePath = NSHomeDirectory ();  /***獲取Documents⺫錄***/ //1. // NSUserDomainMask 代表從用戶文件夾下找 // YES 代表展開路徑中的波浪字符“~” NSArray
*documents = NSSearchPathForDirectoriesInDomains ( NSDocumentDirectory ,
NSUserDomainMask ,
YES ); // 只有一個匹配目錄,所以這個集合裏面只有一個元素 NSString
*doc = documents[0]; //2. //使用字符串拼接的方式獲取 //不建議採用字符串拼接的方式獲取目錄,因爲新版本的操作系統可能會修改默認目錄名稱 NSString
*documents = [homePath stringByAppendingPathComponent: @"Documents" ]; /***獲取Cache目錄***/ NSArray
*caches = NSSearchPathForDirectoriesInDomains ( NSCachesDirectory ,
NSUserDomainMask ,
YES ); NSString
*cache = caches[0];  /***獲取Library⺫錄***/ NSString
*library = [homePath stringByAppendingPathComponent: @"Library" ]; /***Preferences目錄***/ //通過NSUserDefaults類存取該目錄下的設置信息 NSUserDefaults
*defaults = [ NSUserDefaults
standardUserDefaults]; [defaults setObject: @"docoder"
forKey: @"userName" ]; [defaults setFloat:18.0f forKey: @"fontSize" ]; [defaults setBool: YES
forKey: @"autoLogin" ]; // 讀取系統偏好 NSUserDefaults
*defaults = [ NSUserDefaults
standardUserDefaults]; NSString
*userName = [defaults objectForKey: @"userName" ]; float
fontSize = [defaults floatForKey: @"fontSize" ]; BOOL
autoLogin = [defaults floatForKey: @"autoLogin" ]; //注意:UserDefaults設置數據時,不是立即寫入,而是根據時間戳定時地把緩存中的數據寫入本地磁盤。所以調用了set方法之後數據有可能還沒有寫入磁盤,應用程序就終止了。 //出現以上問題,可以通過調用synchornize方法強制寫入: [defaults synchronize];  /***獲取tmp⺫錄***/ NSString
*tmpDir = NSTemporaryDirectory (); |
2.3.NSString可以對路徑做一些處理:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
 //演⽰路徑 NSString
*path = @"/Users/username/file.txt" ;  //1.獲取路徑的組成部分 結果: (“/”,”Users”, “username”, “file.txt”) NSArray
*components = [path pathComponents];  //2.路徑的最後一個組成部分 結果: file.txt NSString
*lastName = [path lastPathComponent]; //3.追加⽂件或⺫錄 結果: /Users/username/file.txt/app.txt NSString
*filePath = [path stringByAppendingPathComponent: @"app.txt" ]; //4.刪除最後部分的組成部分 結果: /Users/username NSString
*filePath = [path stringByDeletingLastPathComponent]; //5.取路徑最後部分的擴展名 結果: txt NSString
*extName = [path pathExtension];  //6.追加擴展名 結果: /Users/username/file.txt.jpg NSString
*filePath = [path stringByAppendingPathExtension: @"jpg" ]; |
3.NSFileManager
3.1.NSFileManager 主要對文件進行管理, 具有:創建文件,複製文件,刪除文件,剪切文件的功能。
3.2.NSFileManager 爲單例,不能用 alloc 創建:
1
2
|
//創建 NSFileManager 對象 NSFileManager
*fileManager = [ NSFileManager
defaultManager]; |
3.3.常用方法:
1
2
3
4
5
6
7
8
9
10
11
12
|
 //創建一個⽂件並寫入數據 - ( BOOL )createFileAtPath:( NSString
*)path contents:( NSData
*)data attributes:( NSDictionary
*)attr; //從⼀個文件中讀取數據 - ( NSData
*)contentsAtPath:( NSString
*)path; //srcPath路徑上的⽂件移動到 dstPath 路徑上, 注意這裏的路徑是⽂件路徑⽽不是目錄 - ( BOOL )moveItemAtPath:( NSString
*)srcPath toPath:( NSString
*)dstPath error:( NSError
**)error; //srcPath路徑上的文件複製到 dstPath 路徑上 - ( BOOL )copyItemAtPath:( NSString
*)srcPath toPath:( NSString
*)dstPath error:( NSError
**)error; //文件是否存在 - ( BOOL )fileExistsAtPath:( NSString
*)path; // 移除⽂件 - ( BOOL )removeItemAtPath:( NSString
*)path error:( NSError
**)error; |
3.4.創建文件:
1
2
3
4
5
6
7
8
9
|
//創建 NSFileManager 對象 NSFileManager
*fileManager = [ NSFileManager
defaultManager]; NSString
*homePath = NSHomeDirectory (); NSString
*path = [homePath stringByAppendingPathComponent: @"file.txt" ]; NSString
*text = @"docoder" ; //將字符串轉成NSData類型 NSData
*data = 1; //寫⼊文件 BOOL
success = [fileManager createFileAtPath:path contents:data attributes: nil ]; |
3.5.讀取文件
1
2
3
4
5
6
|
//創建 NSFileManager 對象 NSFileManager
*fileManager = [ NSFileManager
defaultManager]; //根據路徑讀取文件 NSData
*fileData = [fileManager contentsAtPath:filePath]; //將NSData轉NSString NSString
*content = [[ NSString
alloc] initWithData:fileData encoding: NSUTF8StringEncoding ]; |
3.6.剪切、複製
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
 NSString
*homePath = NSHomeDirectory (); //源⽂件路徑 NSString
*srcPath = [homePath stringByAppendingPathComponent: @"file.txt" ]; //目標路徑 NSString
*toPath = [homePath stringByAppendingPathComponent: @"Documents/file.txt" ]; NSError
*error; //剪切(移動)文件  //將srcPath路徑的文件剪切(移動)到toPath路徑 BOOL
isSuccess = [fm moveItemAtPath:srcPath toPath:toPath error:&error]; if (!isSuccess){ NSLog ( @"失敗:%@" ,error); } //複製文件  //將srcPath路徑的⽂件複製到toPath路徑 BOOL
success = [fm copyItemAtPath:srcPath toPath:toPath error: nil ]; |
3.7.刪除文件
1
2
3
4
5
6
7
8
9
|
 //判斷⽂件是否存在 BOOL
isExist = [fm fileExistsAtPath: path]; if
(isExist) { //刪除⽂件 BOOL
success = [fm removeItemAtPath:path error: nil ]; if
(success) { NSLog ( @"remove success" ); } } |
3.8.獲取文件大小
3.8.1.通過讀取文件屬性獲得:
1
2
3
4
5
|
 NSFileManager
*fileManager = [ NSFileManager
defaultManager]; //獲得文件的屬性字典 NSDictionary
*attrDic = [fileManager attributesOfItemAtPath:path error: nil ]; //獲取⽂件⼤小 NSNumber
*fileSize = [attrDic objectForKey: NSFileSize ]; |
3.8.2.計算獲得 (此方法如果讀取大文件會很佔有內存,不建議使用):
1
2
3
|
NSFileManager
*fileManager = [ NSFileManager
defaultManager]; NSData
*data = [fileManager contentsAtPath:path]; NSInteger
len=data.length; |
4.writeToFile 寫文件
4.1.數組、字典、字符串、NSData 都是容納數據的,他們都有一個 writeToFile 方法, 將數據寫入文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
 NSString
*string = @"docoder" ; NSError
*error; //atomically:YES,表示寫成功後(會寫入到臨時文件中)再覆蓋文件,若寫入失敗,則不會覆蓋文件,這樣更安全。 BOOL
isSuccess = [string writeToFile:path atomically: YES
encoding: NSUTF8StringEncoding
error: &error] if (!isSuccess){ NSLog ( @"寫入失敗:%@" ,error); } else { NSLog ( @"寫入成功" ); } NSString
*backString = [ NSString
stringWithContentsOfFile:path encoding:
NSUTF8StringEncoding
error: nil ] NSLog ( @"取回字符串:%@" ,backString); |
4.2.數組寫入文件:
1
2
3
4
5
6
7
8
9
10
|
 NSString
*s1 = @"zhangsan" ; NSString
*s2 = @"lisi" ; NSArray
*array = [ NSArray
arrayWithObjects:s1,s2, nil ]; //將數組中的數據寫⼊文件 [array writeToFile:path atomically: YES ]; //取回寫入的數組(alloc) NSArray
*backArray=[[ NSArray
alloc] initWithContentsOfFile:path]; //取回寫入的數組(類方法) NSArray
*backArray = [ NSArray
arrayWithContentsOfFile:path]; |
4.3.數組只能將如下數據類型寫入文件,如果包含其他對象,將寫入失敗。
NSNumber | NSString | NSData | NSDate | NSArray | NSDictionary |
4.4.數組、字典寫入的文件叫屬性列表 (plist) 文件 (一種XML格式的文件),可以用xcode打開編輯。
4.5.如果所指定保存文件的路徑不存在,寫入文件方法不會報錯,文件也不會被保存。
4.6.其他格式數據的保存:
4.6.1.NSString , 保存時需要自定字符串編碼。
4.6.2.UIImage , 注意UIImage無法寫入文件,需要使用NSData數據類型進行中轉,NSData可以將任何類型的文件,以二進制格式存儲。
1
2
|
// 生成圖像數據 NSData
*data = UIImagePNGRepresentation(image); |
5.NSFileHandle
5.1.NSFileManager 主要對文件進行 (刪除、修改、移動、複製)。NSFileHandle 主要是對文件的內容進行讀取和寫入操作。
5.2.NSFileHandle 不能創建文件,只能對現有文件進行讀寫,並且可以通過文件偏移量來定位讀寫。
5.3.常用方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
 //創建NSFileHandle,並且打開文件準備讀取 + ( id )fileHandleForReadingAtPath:( NSString
*)path; //創建NSFileHandle,並且打開⽂件準備寫入 + ( id )fileHandleForWritingAtPath:( NSString
*)path; //創建NSFileHandle,並且打開文件準備寫入或讀取 + ( id )fileHandleForUpdatingAtPath:( NSString
*)path; //讀取文件全部數據 - ( NSData
*)availableData; //寫⼊數據 - ( void )writeData:( NSData
*)data; // 獲取當前⽂件的偏移量 - (unsigned
long
long )offsetInFile; // 跳到指定⽂件的偏移量 - ( void )seekToFileOffset:(unsigned
long
long )offset; // 使偏移量跳到文件末尾 - (unsigned
long
long )seekToEndOfFile; // 從當前偏移量讀取到文件末尾 - ( NSData
*)readDataToEndOfFile; // 從當前偏移量開始讀取指定的長度數據 - ( NSData
*)readDataOfLength:( NSUInteger )length; |
5.4.向文件追加數據:
1
2
3
4
5
6
7
8
9
10
11
|
 NSString
*sourcePath = [ NSHomeDirectory () stringByAppendingPathComponent: @"file.txt" ]; //創建可讀寫的 NSFileHandle 對象 NSFileHandle
*fileHandle = [ NSFileHandle
fileHandleForUpdatingAtPath:sourcePath]; //將偏移量跳到文件末尾 [fileHandle seekToEndOfFile]; NSString
*str = @"追加的數據" ; NSData
*stringData = [str dataUsingEncoding: NSUTF8StringEncoding ]; //寫⼊數據 [fileHandle writeData:stringData]; //關閉⽂件 [fileHandle closeFile]; |
5.5.定位偏移量讀取:
1
2
3
4
5
6
7
8
9
10
11
|
 NSFileManager
*fileManager = [ NSFileManager
defaultManager]; NSDictionary
*fileAttr = [fileManager attributesOfItemAtPath:filePath error: nil ]; NSNumber
*filesize = [fileAttr objectForKey: NSFileSize ]; long
length = [filesize longValue]; NSFileHandle
*fileHandle = [ NSFileHandle
fileHandleForReadingAtPath:path]; // 將偏移量定位到⽂件⻓度的一半 [fileHandle seekToFileOffset:length/2]; // 從當前偏移量讀到⽂件最後 NSData
*data = [fileHandle readDataToEndOfFile]; // 關閉⽂件 [fileHandle closeFile]; |
5.6.使用NSFileHandle實現複製文件功能:
此方法將全部數據一次讀,一次寫,若文件很大,會很佔內存,可以將其改爲分批讀寫。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
NSFileManager
*fileManager = [ NSFileManager
defaultManager]; NSString
*homePath = NSHomeDirectory (); //源⽂件路徑 NSString
*sourcePath = [homePath stringByAppendingPathComponent: @"srcfile.txt" ]; //輸出⽂件路徑 NSString
*outPath = [homePath stringByAppendingPathComponent: @"outfile.txt" ]; //創建輸出文件 BOOL
success = [fileManager createFileAtPath:outPath contents: nil
attributes: nil ]; if
(!success) { NSLog ( @"創建⽂件失敗" ); }  //創建NSFileHandle,用於讀取源路徑文件 NSFileHandle
*infile = [ NSFileHandle
fileHandleForReadingAtPath:sourcePath]; if
(infile == nil ) { NSLog ( @"打開失敗:路徑:%@" ,sourcePath); } //創建NSFileHandle,⽤於將數據寫入該文件 NSFileHandle
*outfile = [ NSFileHandle
fileHandleForWritingAtPath:outPath]; if
(outfile == nil ) { NSLog ( @"打開失敗:路徑:%@" ,outPath); } //從當前偏移量讀取文件剩下的所有數據 NSData
*buffer = [infile availableData]; //將數據寫⼊輸出文件 [outfile writeData:buffer]; //關閉寫入、輸入⽂件 [infile closeFile]; [outfile closeFile]; |