In my Tests directory in my swift project, I have a directory for test cases and a directory for test files.
+ Tests
+ UnitTest
+ MySwiftTests.swift
+ SourceFiles
+ file1.xml
I need to create a FileManager to load 'file1.xml' in my MySwiftTests. My question is how to specify the SearchPathDirectory and SearchPathDomainMask in the url of the FileManager which is relative the the test cases?
func url(for: FileManager.SearchPathDirectory, in: FileManager.SearchPathDomainMask, appropriateFor: URL?, create: Bool) -> URL
https://developer.apple.com/documentation/foundation/filemanager
let bundle = Bundle(for: type(of: self))
guard let path = bundle.path(forResource: "file1", ofType: "xml") else {
// File not found ... oops
return
}
// Now you can access the file using e.g. String(contentsOfFile:)
let string = try? String(contentsOfFile: path)
// or Data? using the FileManager
let data = FileManager.default.contents(atPath: path)
Make sure to add file1.xml to your Test Target
Related
I'm working with Swift 5.0 and I want to zip 3 files without installing additional dependencies.
Currently I'm able to zip these 3 Files, which all are in the same "root" directory. But if I open the created and exported zip-file (final.zip), than I get the folder (root) in which the 3 files were saved. I don't want this "root" folder. I want to see my data directly inside the final.zip
Below is my code. Can someone help me out?
let fm = FileManager.default
let baseDirectoryUrl = fm.urls(for: .documentDirectory, in: .userDomainMask).first!.appendingPathComponent("root", isDirectory: true)
if !manager.fileExists(atPath: baseDirectoryUrl.relativePath) {
try! manager.createDirectory(
at: baseDirectoryUrl,
withIntermediateDirectories: true,
attributes: nil
)
}
// path of data
let data1_path = baseDirectoryUrl.appendingPathComponent("data1.vec3")
let data2_path = baseDirectoryUrl.appendingPathComponent("data2.vec3")
let data3_path = baseDirectoryUrl.appendingPathComponent("data3.json")
// write wData1 to data1_path
try! wData1.write(to: data1_path)
// write wData2 to data2_path
try! wData2.write(to: data2_path)
// write wData3 to data3_path
try! wData3.write(to: data3_path)
// this will hold the URL of the zip file
var archiveUrl: URL?
// if we encounter an error, store it here
var error: NSError?
let coordinator = NSFileCoordinator()
// zip up the root directory
// this method is synchronous and the block will be executed before it returns
// if the method fails, the block will not be executed though
// if you expect the archiving process to take long, execute it on another queue
coordinator.coordinate(readingItemAt: baseDirectoryUrl, options: [.forUploading], error: &error) { (zipUrl) in
// zipUrl points to the zip file created by the coordinator
// zipUrl is valid only until the end of this block, so we move the file to a temporary folder
let tmpUrl = try! fm.url(
for: .itemReplacementDirectory,
in: .userDomainMask,
appropriateFor: zipUrl,
create: true
).appendingPathComponent("export.zip", isDirectory: false)
try! fm.copyItem(at: zipUrl, to: tmpUrl)
// store the URL so we can use it outside the block
archiveUrl = tmpUrl
}
if let archiveUrl = archiveUrl {
// bring up the share sheet so we can send the archive with AirDrop for example
let avc = UIActivityViewController(activityItems: [archiveUrl], applicationActivities: nil)
avc.popoverPresentationController?.barButtonItem = navigationItem.rightBarButtonItem
present(avc, animated: true)
} else {
print(error)
}
You can use this zip package in your app with shouldKeepParent: false
https://github.com/weichsel/ZIPFoundation#in-memory-archives
I know there are a few questions pertaining to this, but they're in Objective-C.
How can I access a .txt file included in my app using Swift on an actual iPhone? I want to be able to read and write from it. Here are my project files if you want to take a look. I'm happy to add details if necessary.
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.
🎁 Property Wrapper - Fetch and convert to correct data type
This simple wrapper helps you to load any file from any bundle in a cleanest way:
#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)
}
}
Usage:
#BundleFile(name: "avatar", type: "jpg", decoder: { UIImage(data: $0)! } )
var avatar: UIImage
You can define any decoder to match your needs
Get File From Bundle in 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")
Bundles are read only. You can use NSBundle.mainBundle().pathForResource to access the file as read-only, but for read-write access you need to copy your document to Documents folder or tmp folder.
Bundles can be written. You can use Bundle.main.path to overwrite file by adding it into Copy Bundles Resource.
I have to use a file from another bundle. So, following code worked for me. Needful when you work with a frameworks.
let bundle = Bundle(for: ViewController.self)
let fileName = bundle.path(forResource: "fileName", ofType: "json")
download and save file
let destination: DownloadRequest.DownloadFileDestination = { _, _ in
// var fileURL = self.createFolder(folderName: downloadFolderName)
var fileURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
let fileName = URL(string : currentFile.link )
fileURL = fileURL.appendingPathComponent((fileName?.lastPathComponent)!)
return (fileURL, [.removePreviousFile, .createIntermediateDirectories])
}
Alamofire.download(currentDownloadedFile.link , to: destination).response(completionHandler: { (DefaultDownloadResponse) in
print("res ",DefaultDownloadResponse.destinationURL!);
completion(true)
})
but when i wont to check file in this dirrectory i get nil
let filemanager:FileManager = FileManager()
let fileURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
let files = filemanager.enumerator(atPath: fileURL.absoluteString) // = nil
while let file = files?.nextObject() {
print(file)
}
if i save local path to file and after reload app wont to share it -> "share" app cant send file (mb cant found it)
can u pls help me. how it works ? why when i print all files he didnt find it? how to save file who after reboot app it will be saved in same link
You are using the wrong API
For file system URLs use always path, absoluteString returns the full string including the scheme (e. g. file:// or http://)
let files = filemanager.enumerator(atPath: fileURL.path)
How can I find the path of iOS app internal directory in Swift?
Firstly, what is the equivalent name of android app internal directory in iOS app?
Secondly, how can I find the path of the directory?
which api should I use in Swift?
My main purpose is trying to copy Bundle sqlite file to the directory
To get path of document directory you can use this code.
// path to documents directory
let documentDirectoryPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first
if let documentDirectoryPath = documentDirectoryPath {
}
For more information follow these links : File System Basics and Accessing Files and Directories
Try this -
public func getDatabasePath() -> String {
let databaseURL = try? FileManager.default
.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
.appendingPathComponent("YOUR_DB_FILE_NAME.sqlite")
// If DB file not present in file manager copy DB file to user document directory
let fileManager = FileManager.default
if fileManager.fileExists(atPath: (databaseURL?.path)!) {
print("FILE AVAILABLE")
return (databaseURL?.path)!
} else {
print("FILE NOT AVAILABLE ... Copying")
if fileManager.createFile(atPath: (databaseURL?.path)!, contents: Data(), attributes: nil) {
return (databaseURL?.path)!
}
}
return ""
}
In swift how can I get the file path for a test audio File that i have copied into the resources folder in Xcode
The code I have gives file not found. Am I looking in the right Directories with NSSearchPathForDirectoriesInDomains? Any help much appreciated!
let name = "test.wav"
let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as NSString
let filePath = paths.stringByAppendingPathComponent(name)
let checkValidation = NSFileManager.defaultManager()
if (checkValidation.fileExistsAtPath(filePath)) {
print("found .wav")
} else {
print("file not found")
}
i just found this that works.
let name = "test.wav"
let soundPath = (NSBundle.mainBundle().resourcePath! as NSString).stringByAppendingPathComponent(name)
let soundURL = NSURL.fileURLWithPath(soundPath)