iOS 沙盒探究

說這個之前,我們先了解一個工具锦募,以便我們更好的去操作摆屯。

woodpecker.png

在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)用程序再次啟動過程中不需要的信息,重啟后清空扼睬。

二逮栅、獲取文件路徑

常用獲取文件路徑方法主要有兩種:

  1. NSHomeDirectory() + "/../../"
  2. 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)")
}

屏幕快照 2018-11-22 下午4.28.20.png

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ī)操作拓售。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市镶奉,隨后出現(xiàn)的幾起案子础淤,更是在濱河造成了極大的恐慌,老刑警劉巖哨苛,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鸽凶,死亡現(xiàn)場離奇詭異,居然都是意外死亡移国,警方通過查閱死者的電腦和手機(jī)吱瘩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來迹缀,“玉大人使碾,你說我怎么就攤上這事∽6” “怎么了票摇?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長砚蓬。 經(jīng)常有香客問我矢门,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任祟剔,我火速辦了婚禮隔躲,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘物延。我一直安慰自己宣旱,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布叛薯。 她就那樣靜靜地躺著浑吟,像睡著了一般。 火紅的嫁衣襯著肌膚如雪耗溜。 梳的紋絲不亂的頭發(fā)上组力,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天,我揣著相機(jī)與錄音抖拴,去河邊找鬼燎字。 笑死,一個胖子當(dāng)著我的面吹牛阿宅,可吹牛的內(nèi)容都是我干的轩触。 我是一名探鬼主播,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼家夺,長吁一口氣:“原來是場噩夢啊……” “哼脱柱!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起拉馋,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤榨为,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后煌茴,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體随闺,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年蔓腐,在試婚紗的時候發(fā)現(xiàn)自己被綠了矩乐。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡回论,死狀恐怖散罕,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情傀蓉,我是刑警寧澤欧漱,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站葬燎,受9級特大地震影響误甚,放射性物質(zhì)發(fā)生泄漏缚甩。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一窑邦、第九天 我趴在偏房一處隱蔽的房頂上張望擅威。 院中可真熱鬧,春花似錦冈钦、人聲如沸裕寨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至捻艳,卻和暖如春驾窟,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背认轨。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工绅络, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人嘁字。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓恩急,卻偏偏與公主長得像,于是被迫代替她去往敵國和親纪蜒。 傳聞我的和親對象是個殘疾皇子衷恭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評論 2 361

推薦閱讀更多精彩內(nèi)容