【问题标题】:How to access file included in app bundle in Swift?如何在 Swift 中访问应用程序包中包含的文件?
【发布时间】:2016-06-01 22:48:28
【问题描述】:

我知道有一些与此相关的问题,但它们在 Objective-C 中。

我如何在实际的 iPhone 上使用 Swift 访问我的应用程序中包含的 .txt 文件?我希望能够从中读取和写入。 Here 是我的项目文件,如果你想看看的话。如有必要,我很乐意添加详细信息。

【问题讨论】:

  • “我希望能够从中读写。”你不能。当安装在设备上时,应用程序包是只读的。您可以读取应用程序包中的文件,但不能写入。

标签: ios swift file read-write


【解决方案1】:

只需在 app bundle 中搜索资源

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")
   }
}

【讨论】:

  • “它”是指复制到文档目录的可写文件?
  • "现在你可以从 fileURL 访问它" 我的意思是创建的文件不是包含的和可写的
  • 文件没有被复制成一个新的空文件
  • 您能否更具体地说明如何在文档目录中创建目录?目录的名称是什么?是文件还是文件?谢谢
  • 如何更具体?答案是关于如何访问文件而不是如何创建目录。
【解决方案2】:

Swift 3,基于 Karim’s answer

阅读

您可以通过包的资源读取应用包中包含的文件:

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)

【讨论】:

    【解决方案3】:

    在 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)
        }
    }
    

    这个特定的例子不是最灵活的,但是通过一些工作你可以很容易地传入你自己的文件名、扩展名和数据值。

    【讨论】:

      【解决方案4】:

      ? 属性包装器 - 获取并转换为正确的数据类型

      这个简单的包装器可以帮助您以最干净的方式从任何包中加载任何文件:

      @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
      

      您可以定义任何解码器来满足您的需求

      【讨论】:

        【解决方案5】:

        在 Swift 5.1 中从 Bundle 中获取文件

        //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")
        

        【讨论】:

          【解决方案6】:

          捆绑包是只读的。您可以使用NSBundle.mainBundle().pathForResource 以只读方式访问文件,但要进行读写访问,您需要将文档复制到 Documents 文件夹或 tmp 文件夹。

          【讨论】:

            【解决方案7】:

            可以编写捆绑包。您可以使用Bundle.main.path 将文件添加到Copy Bundles Resource 来覆盖文件。

            【讨论】:

              猜你喜欢
              • 2016-12-06
              • 2017-11-07
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2013-02-04
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多