iOS 沙盒探究

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

woodpecker.png

在appstore上搜索下載,以便我們更好的查看app的沙盒文件。同時在項(xiàng)目中導(dǎo)入它:pod 'WoodPeckeriOS',這樣項(xiàng)目運(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)容。所有的非代碼文件都保存在這個地方,比如圖片、聲音、屬性列表和文本文件等??傮w來說沙盒就是一種獨(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等類來實(shí)現(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)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容