簡體   English   中英

如何訪問 Swift 中應用程序包中包含的文件?

[英]How to access file included in app bundle in Swift?

我知道有幾個問題與此有關,但它們在 Objective-C 中。

如何在實際 iPhone 上使用 Swift 訪問我的應用程序中包含的.txt文件? 我希望能夠從中讀取和寫入。 如果您想看一下,是我的項目文件。 如有必要,我很樂意添加詳細信息。

只需在應用程序包中搜索資源

var filePath = NSBundle.mainBundle().URLForResource("file", withExtension: "txt")

但是你不能寫入它,因為它在應用程序資源目錄中,你必須在文檔目錄中創建它才能寫入它

var documentsDirectory: NSURL?
var fileURL: NSURL?

documentsDirectory = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).last!
fileURL = documentsDirectory!.URLByAppendingPathComponent("file.txt")

if (fileURL!.checkResourceIsReachableAndReturnError(nil)) {
    print("file exist")
}else{
    print("file doesnt exist")
    NSData().writeToURL(fileURL!,atomically:true)
}

現在您可以從fileURL訪問它

編輯 - 2018 年 8 月 28 日

這是在Swift 4.2 中的方法

var filePath = Bundle.main.url(forResource: "file", withExtension: "txt")

在文檔目錄中創建它

if let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last {
   let fileURL = documentsDirectory.appendingPathComponent("file.txt")
   do {
       if try fileURL.checkResourceIsReachable() {
           print("file exist")
       } else {
           print("file doesnt exist")
           do {
            try Data().write(to: fileURL)
           } catch {
               print("an error happened while creating the file")
           }
       }
   } catch {
       print("an error happened while checking for the file")
   }
}

Swift 3 ,基於Karim 的回答

您可以通過捆綁包的資源讀取應用程序捆綁包中包含的文件:

let fileURL = Bundle.main.url(forResource:"filename", withExtension: "txt")

寫作

但是,你不能在那里寫。 您需要創建一個副本,最好在 Documents 目錄中:

func makeWritableCopy(named destFileName: String, ofResourceFile originalFileName: String) throws -> URL {
    // Get Documents directory in app bundle
    guard let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last else {
        fatalError("No document directory found in application bundle.")
    }

    // Get URL for dest file (in Documents directory)
    let writableFileURL = documentsDirectory.appendingPathComponent(destFileName)

    // If dest file doesn’t exist yet
    if (try? writableFileURL.checkResourceIsReachable()) == nil {
        // Get original (unwritable) file’s URL
        guard let originalFileURL = Bundle.main.url(forResource: originalFileName, withExtension: nil) else {
            fatalError("Cannot find original file “\(originalFileName)” in application bundle’s resources.")
        }

        // Get original file’s contents
        let originalContents = try Data(contentsOf: originalFileURL)

        // Write original file’s contents to dest file
        try originalContents.write(to: writableFileURL, options: .atomic)
        print("Made a writable copy of file “\(originalFileName)” in “\(documentsDirectory)\\\(destFileName)”.")

    } else { // Dest file already exists
        // Print dest file contents
        let contents = try String(contentsOf: writableFileURL, encoding: String.Encoding.utf8)
        print("File “\(destFileName)” already exists in “\(documentsDirectory)”.\nContents:\n\(contents)")
    }

    // Return dest file URL
    return writableFileURL
}

用法示例:

let stuffFileURL = try makeWritableCopy(named: "Stuff.txt", ofResourceFile: "Stuff.txt")
try "New contents".write(to: stuffFileURL, atomically: true, encoding: String.Encoding.utf8)

只是在 Swift 4 中使用此代碼的快速更新:

Bundle.main.url(forResource:"YourFile", withExtension: "FileExtension")

並且以下已更新以說明寫出文件:

var myData: Data!

func checkFile() {
    if let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last {
        let fileURL = documentsDirectory.appendingPathComponent("YourFile.extension")
        do {
            let fileExists = try fileURL.checkResourceIsReachable()
            if fileExists {
                print("File exists")
            } else {
                print("File does not exist, create it")
                writeFile(fileURL: fileURL)
            }
        } catch {
            print(error.localizedDescription)
        }
    }
}

func writeFile(fileURL: URL) {
    do {
        try myData.write(to: fileURL)
    } catch {
        print(error.localizedDescription)
    }
}

這個特定的例子並不是最靈活的,但是通過一些工作,您可以輕松地傳遞您自己的文件名、擴展名和數據值。

捆綁包是只讀的。 您可以使用NSBundle.mainBundle().pathForResource以只讀方式訪問文件,但對於讀寫訪問,您需要將文檔復制到 Documents 文件夾或 tmp 文件夾。

在 Swift 5.1 中從包中獲取文件

//For Video File
let stringPath = Bundle.main.path(forResource: "(Your video file name)", ofType: "mov")

let urlVideo = Bundle.main.url(forResource: "Your video file name", withExtension: "mov")

🎁 屬性包裝器 - 獲取並轉換為正確的數據類型

這個簡單的包裝器可以幫助您以最干凈的方式從任何包中加載任何文件:

@propertyWrapper struct BundleFile<DataType> {
    let name: String
    let type: String
    let fileManager: FileManager = .default
    let bundle: Bundle = .main
    let decoder: (Data) -> DataType

    var wrappedValue: DataType {
        guard let path = bundle.path(forResource: name, ofType: type) else { fatalError("Resource not found: \(name).\(type)") }
        guard let data = fileManager.contents(atPath: path) else { fatalError("Can not load file at: \(path)") }
        return decoder(data)
    }
}

用法:

@BundleFile(name: "avatar", type: "jpg", decoder: { UIImage(data: $0)! } )
var avatar: UIImage

您可以定義任何解碼器來滿足您的需求

可以寫包。 您可以使用Bundle.main.path通過將文件添加到Copy Bundles Resource來覆蓋文件。

項目 -> 目標 -> 構建階段 -> 復制捆綁資源

我必須使用另一個包中的文件。 因此,以下代碼對我有用。 當你使用框架時是必需的。

let bundle = Bundle(for: ViewController.self)
let fileName = bundle.path(forResource: "fileName", ofType: "json")

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM