How to access file included in app bundle in Swift?
Simply by searching in the app bundle for the resource
var filePath = NSBundle.mainBundle().URLForResource("file", withExtension: "txt")
However you can't write to it because it is in the app resources directory and you have to create it in the document directory to write to it
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)}
now you can access it from fileURL
EDIT - 28 August 2018
This is how to do it in Swift 4.2
var filePath = Bundle.main.url(forResource: "file", withExtension: "txt")
To create it in the document directory
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, based on Karim’s answer.
Reading
You can read files included in an app’s bundle through the bundle’s resource:
let fileURL = Bundle.main.url(forResource:"filename", withExtension: "txt")
Writing
However, you can’t write there. You will need to create a copy, preferably in the Documents directory:
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}
Example usage:
let stuffFileURL = try makeWritableCopy(named: "Stuff.txt", ofResourceFile: "Stuff.txt")try "New contents".write(to: stuffFileURL, atomically: true, encoding: String.Encoding.utf8)
Just a quick update for using this code with Swift 4:
Bundle.main.url(forResource:"YourFile", withExtension: "FileExtension")
And the following has been updated to account for writing the file out:
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) }}
This particular example is not the most flexible, but with a little bit of work you can easily pass in your own file names, extensions and data values.