說這個之前,我們先了解一個工具锦募,以便我們更好的去操作摆屯。
在appstore上搜索下載,以便我們更好的查看app的沙盒文件糠亩。同時在項目中導(dǎo)入它:
pod 'WoodPeckeriOS'
虐骑,這樣項目運(yùn)行的時候就可以直觀的看到app的沙盒文件准验。當(dāng)然不用這種軟件也可以查看運(yùn)行app的沙盒文件。
Xcode -> Window -> Devices and Simulators ->選擇你要查看的應(yīng)用 -> Download Container...
下載即可廷没。
然后查看下載內(nèi)容糊饱,顯示包內(nèi)容,就可以看到:
一颠黎、iOS沙盒機(jī)制簡介
iOS中的沙盒機(jī)制(SandBox)是一種安全體系另锋,它規(guī)定了應(yīng)用程序只能在為該應(yīng)用創(chuàng)建的文件夾內(nèi)讀取文件,不可以訪問其他地方的內(nèi)容盏缤。所有的非代碼文件都保存在這個地方砰蠢,比如圖片、聲音唉铜、屬性列表和文本文件等台舱。總體來說沙盒就是一種獨(dú)立潭流、安全竞惋、封閉的空間。
1.特點(diǎn):
- 每個應(yīng)用程序的活動范圍都限定在自己的沙盒里灰嫉。
- 不能隨意跨越自己的沙盒去訪問別的應(yīng)用程序(iOS 8已經(jīng)部分開放訪問extension拆宛。
- 在訪問別人沙盒內(nèi)的數(shù)據(jù)時需要訪問權(quán)限羹铅。
2.沙盒目錄
- Documnets目錄: 保存應(yīng)用運(yùn)行時生成的需要持久化的數(shù)據(jù)护桦,iTunes備份和恢復(fù)的時候會包括此目錄,所以蘋果建議將程序中建立的或在程序中瀏覽到的文件數(shù)據(jù)保存在該目錄下蹄咖。
- Library/Caches: 存放緩存文件根盒,iTunes不會備份此目錄钳幅,此目錄下文件不會在應(yīng)用退出后刪除 。一般存放體積比較大炎滞,不是特別重要的資源敢艰。
- Library/Preferences: 保存應(yīng)用程序的所有偏好設(shè)置iOS的Settings(設(shè)置),我們不應(yīng)該直接在這里創(chuàng)建文件册赛,而是需要通過UserDefault這個類來訪問應(yīng)用程序的偏好設(shè)置钠导。iTunes會自動備份該文件目錄下的內(nèi)容。
- SystemData目錄:暫無信息森瘪。
- tmp目錄:用于存放臨時文件牡属,保存應(yīng)用程序再次啟動過程中不需要的信息,重啟后清空扼睬。
二逮栅、獲取文件路徑
常用獲取文件路徑方法主要有兩種:
- NSHomeDirectory() + "/../../"
- NSSearchPathForDirectoriesInDomains方法
1. Documnets
let documnetPaths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let documnetPath = documnetPaths.first
or
let documnetPath = NSHomeDirectory() + "/Documents"
2.Library/Caches
let cachePaths = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true)
let cachePath = cachePaths.first
or
let cachePath = NSHomeDirectory() + "/Library/Caches
3.Library/Preferences
let preferencPath = NSHomeDirectory() + "/Library/Preferences
4.tmp
let timDir = NSTemporaryDirectory()
or
let timDir = NSHomeDirectory() + "/tmp"
三、文件常規(guī)操作
iOS開發(fā)經(jīng)常會遇到讀文件,寫文件等证芭,對文件和文件夾的操作,這時就可以使用FileManager担映,F(xiàn)ileHandle等類來實現(xiàn)废士。
這個時候結(jié)合woodpecker效果會更好
1.創(chuàng)建文件
方法1:
let myDirectory = NSHomeDirectory() + "/Documents/myFolder"
let fileManager = FileManager.default
// 為ture表示路徑中間如果有不存在的文件夾都會創(chuàng)建
try! fileManager.createDirectory(atPath: myDirectory, withIntermediateDirectories: true, attributes: nil)
方法2
let manager = FileManager.default
let urlForDocument = manager.urls(for: .documentDirectory, in: .userDomainMask)
let url = urlForDocument.first!
let folder = url.appendingPathComponent("myFolder", isDirectory: true)
let exist = manager.fileExists(atPath: folder.path)
if !exist {
try! manager.createDirectory(at: folder, withIntermediateDirectories: true, attributes: nil)
}
結(jié)果可以看出,我們在Documents目錄下成功創(chuàng)建一個myFolder文件夾:(↓:是創(chuàng)建出來的意思 蝇完,↑:是刪除的意思)
2.將對象寫入文件
這里的對象包含String官硝,NSString,UIImage短蜕,NSArray氢架,NSDictionary,通過write(to:)方法即可朋魔。
2.1 string
let filePath = NSHomeDirectory() + "/Documents/wh.txt"
let info = "test write 'hello word' to wh.txt"
try? info.write(toFile: filePath, atomically: true, encoding: String.Encoding.utf8)
2.2 image
let filePath = NSHomeDirectory() + "/Documents/wh.png"
let image = UIImage.init(named: "WechatIMG9320")
let data: Data = UIImagePNGRepresentation(image!)!
try? data.write(to: URL.init(fileURLWithPath: filePath))
2.3 NSArray
let array = NSArray.init(array: ["a", "b", "c", "d"])
let filePath = NSHomeDirectory() + "/Documents/array.plist"
array.write(toFile: filePath, atomically: true)
2.4 NSDictionary
let dictionary = NSDictionary.init(dictionary: ["name": "wh",
"age": 16,
"sex": "man"])
let filePath = NSHomeDirectory() + "/Documents/Dic.plist"
dictionary.write(toFile: filePath, atomically: true)
3.創(chuàng)建文件
let manager = FileManager.default
let urlForDocument = manager.urls(for: .documentDirectory, in: .userDomainMask)
let url = urlForDocument.first!
let file = url.appendingPathComponent("test.txt")
let exist = manager.fileExists(atPath: file.path)
if !exist {
let data = Data.init(base64Encoded: "aGVsbG8gd29ybGQ=", options: .ignoreUnknownCharacters)
let creatSuccess = manager.createFile(atPath: file.path, contents: data, attributes: nil)
print("文件創(chuàng)建結(jié)果:\(creatSuccess)")
}
4.復(fù)制文件
let fileManager = FileManager.default
let sourcePath = NSHomeDirectory() + "/Documents/wh.txt"
let toPath = NSHomeDirectory() + "/Documents/copy.txt"
try? fileManager.copyItem(atPath: sourcePath, toPath: toPath)
or
let manager = FileManager.default
let urlForDocument = manager.urls(for: .documentDirectory, in: .userDomainMask)
let url = urlForDocument.first!
let sourceURL = url.appendingPathComponent("wh.txt")
let toUrl = url.appendingPathComponent("copy.txt")
try? manager.copyItem(at: sourceURL, to: toUrl)
5.移動文件
let fileManager = FileManager.default
let sourceUrl = NSHomeDirectory() + "/Documents/test.txt"
let toUrl = NSHomeDirectory() + "/Documents/myFolder/test.txt"
try? fileManager.moveItem(atPath: sourceUrl, toPath: toUrl)
or
let fileManager = FileManager.default
let urlForDocument = fileManager.urls(for: .documentDirectory, in: .userDomainMask)
let url = urlForDocument.first!
let sourceUrl = url.appendingPathComponent("wh.txt")
let toUrl = url.appendingPathComponent("/myFolder/move.txt")
try! fileManager.moveItem(at: sourceUrl, to: toUrl)
6.刪除目錄下所有文件
let fileManager = FileManager.default
let myDirectory = NSHomeDirectory() + "/Documents/myFolder"
let fileArray = fileManager.subpaths(atPath: myDirectory)
for fn in fileArray!{
try! fileManager.removeItem(atPath: myDirectory + "/\(fn)")
}
7.遍歷一個目錄下的所有文件
let manager = FileManager.default
let urlForDocument = manager.urls(for: .documentDirectory, in: .userDomainMask)
let url = urlForDocument.first
// 對指定路徑執(zhí)行淺搜索岖研,返回指定目錄路徑下的文件、子目錄及符號鏈接的列表
let contentsOfPath = try? manager.contentsOfDirectory(atPath: url!.path)
print("contentsOfPath:\(contentsOfPath!)")
let contentsOfUrl = try? manager.contentsOfDirectory(at: url!, includingPropertiesForKeys: nil, options: .skipsHiddenFiles)
print("contentsOfUrl:\(contentsOfUrl!)")
// 深度遍歷警检,會遞歸遍歷子文件夾(但不會遞歸符號鏈接)
let enumeratorAtPath = manager.enumerator(atPath: url!.path)
print("enumeratorAtPath:\(enumeratorAtPath!.allObjects)")
let enumeratorAtUrl = manager.enumerator(at: url!, includingPropertiesForKeys: nil, options: .skipsHiddenFiles, errorHandler: nil)
print("enumeratorAtUrl:\(enumeratorAtUrl!.allObjects)")
// 深度遍歷孙援,會遞歸遍歷子文件夾(包括符號鏈接,所以要求性能的話用enumeratorAtPath)
let subPaths = manager.subpaths(atPath: url!.path)
print("subPaths:\(subPaths!)")
運(yùn)行結(jié)果:
contentsOfPath:["wh.png", "Dic.plist", "myFolder", "array.plist", "copy.txt"]
contentsOfUrl:[file:///private/var/mobile/Containers/Data/Application/C0142560-B8D9-4620-A1A2-ACFBE26296AE/Documents/wh.png, file:///private/var/mobile/Containers/Data/Application/C0142560-B8D9-4620-A1A2-ACFBE26296AE/Documents/Dic.plist, file:///private/var/mobile/Containers/Data/Application/C0142560-B8D9-4620-A1A2-ACFBE26296AE/Documents/myFolder/, file:///private/var/mobile/Containers/Data/Application/C0142560-B8D9-4620-A1A2-ACFBE26296AE/Documents/array.plist, file:///private/var/mobile/Containers/Data/Application/C0142560-B8D9-4620-A1A2-ACFBE26296AE/Documents/copy.txt]
enumeratorAtPath:[wh.png, Dic.plist, myFolder, array.plist, copy.txt]
enumeratorAtUrl:[file:///private/var/mobile/Containers/Data/Application/C0142560-B8D9-4620-A1A2-ACFBE26296AE/Documents/wh.png, file:///private/var/mobile/Containers/Data/Application/C0142560-B8D9-4620-A1A2-ACFBE26296AE/Documents/Dic.plist, file:///private/var/mobile/Containers/Data/Application/C0142560-B8D9-4620-A1A2-ACFBE26296AE/Documents/myFolder/, file:///private/var/mobile/Containers/Data/Application/C0142560-B8D9-4620-A1A2-ACFBE26296AE/Documents/array.plist, file:///private/var/mobile/Containers/Data/Application/C0142560-B8D9-4620-A1A2-ACFBE26296AE/Documents/copy.txt]
subPaths:["wh.png", "Dic.plist", "myFolder", "array.plist", "copy.txt"]
8.判斷文件或文件夾是否存在
let fileManager = FileManager.default
let filePath = NSHomeDirectory() + "/Documents/Folder"
let exist = fileManager.fileExists(atPath: filePath)
print("exist:\(exist)")
運(yùn)行結(jié)果:
exist:false
如果文件夾名稱是是myFolder
扇雕,運(yùn)行結(jié)果即為:exist:true
9.讀取文件內(nèi)容
let fileManager = FileManager.default
let urlForDocument = fileManager.urls(for: .documentDirectory, in: .userDomainMask)
let docPath = urlForDocument.first!
let file = docPath.appendingPathComponent("copy.txt")
//方法1
let readHandler = try! FileHandle.init(forReadingFrom: file)
let data = readHandler.readDataToEndOfFile()
let string = String.init(data: data, encoding: .utf8)
print("文件內(nèi)容:\(string!)")
//方法2
let data2 = fileManager.contents(atPath: file.path)
let string2 = String.init(data: data2!, encoding: .utf8)
print("文件內(nèi)容:\(string2!)")
運(yùn)行結(jié)果:
文件內(nèi)容:test write 'hello word' to wh.txt
10.寫入數(shù)據(jù)
let fileManager = FileManager.default
let urlForDocument = fileManager.urls(for: .documentDirectory, in: .userDomainMask)
let docPath = urlForDocument.first!
let file = docPath.appendingPathComponent("copy.txt")
let string = "ending..."
let data = string.data(using: .utf8, allowLossyConversion: true)
let handler = try? FileHandle.init(forWritingTo: file)
// handler?.seek(toFileOffset: <#T##UInt64#>)
handler?.seekToEndOfFile()
handler?.write(data!)
11.文件屬性
let fileManager = FileManager.default
let urlForDocument = fileManager.urls(for: .documentDirectory, in: .userDomainMask)
let docPath = urlForDocument.first!
let file = docPath.appendingPathComponent("copy.txt")
let attributes = try? fileManager.attributesOfItem(atPath: file.path)
// print("attributes:\(attributes)")
print("創(chuàng)建時間:\(attributes![FileAttributeKey.creationDate]!)")
print("修改時間:\(attributes![FileAttributeKey.modificationDate]!)")
print("文件大小:\(attributes![FileAttributeKey.size]!)")
運(yùn)行結(jié)果:
創(chuàng)建時時\351\227間:2018-11-23 03:22:35 +0000
修改\346\227時\346\227時\351\346\227時\351\351\227間:2018-11-23 04:02:12 +0000
文件大小:42
12.文件權(quán)限
let fileManager = FileManager.default
let urlForDocument = fileManager.urls(for: .documentDirectory, in: .userDomainMask)
let docPath = urlForDocument.first!
let file = docPath.appendingPathComponent("copy.txt")
let readable = fileManager.isReadableFile(atPath: file.path)
let writeable = fileManager.isWritableFile(atPath: file.path)
let executable = fileManager.isExecutableFile(atPath: file.path)
let deleteable = fileManager.isDeletableFile(atPath: file.path)
print("可讀:\(readable) \n可寫:\(writeable) \n可執(zhí)行:\(executable) \n可刪除:\(deleteable)")
運(yùn)行結(jié)果:
可讀:true
可寫:true
可執(zhí)行:false
可刪除:true
13.文件比較
let fileManager = FileManager.default
let urlForDocument = fileManager.urls(for: .documentDirectory, in: .userDomainMask)
let docPath = urlForDocument.first!
let contents = try! fileManager.contentsOfDirectory(atPath: docPath.path)
//下面比較用戶文檔中前面兩個文件是否內(nèi)容相同(該方法也可以用來比較目錄)
let count = contents.count
if count > 1 {
let path1 = docPath.path + "/" + contents[0]
let path2 = docPath.path + "/" + contents[1]
let equal = fileManager.contentsEqual(atPath: path1, andPath: path2)
print("path1:\(path1)")
print("path2:\(path2)")
print("比較結(jié)果:\(equal)")
}
運(yùn)行結(jié)果:
path1:/var/mobile/Containers/Data/Application/A1F0DBBF-1BDC-4527-957A-B205A580926B/Documents/wh.png
path2:/var/mobile/Containers/Data/Application/A1F0DBBF-1BDC-4527-957A-B205A580926B/Documents/Dic.plist
比較結(jié)果:false
以上就是沙盒文件的一些常規(guī)操作拓售。