Swift 3 : How to get path of file saved in Documents folder - ios

path = Bundle.main.path(forResource: "Owl.jpg", ofType: "jpg")
returns nil, however, using NSHomeDirectory() I'm able to verify that is under Documents/ folder.

First, separate name and extension:
Bundle.main.path(forResource: "Owl", ofType: "jpg")
Second, separate (mentally) your bundle and the Documents folder. They are two completely different things. If this file is the Documents folder, it absolutely is not in your main bundle! You probably want something like this:
let fm = FileManager.default
let docsurl = try! fm.url(for:.documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
let myurl = docsurl.appendingPathComponent("Owl.jpg")
Third, if Owl is an image asset in the asset catalog, then say
let im = UIImage(named:"Owl") // or whatever its name is

Tested on: xCode 8.3.2 & Swift 3.1
First drag your file (JPG, MP3, ZIP) inside your project folder and make sure Copy items if needed is checked and project/app is selected in Add to targets
Inside relevant ViewController
let fileName = "fileName"
let fileType = "fileType"
if let filePath = Bundle.main.path(forResource: fileName, ofType: fileType) {
print(filePath)
}
If you need to get the file URL you can use NSBundle method
if let fileURL = Bundle.main.url(forResource: fileName, withExtension: fileType) {
print(fileURL)
}
Also NSBundle method pathForResource has an initializer that you can specify in which directory your files are located like:
if let filePath = Bundle.main.path(forResource: fileName, ofType: fileType, inDirectory: "filesSubDirectory") {
print(filePath)
}
And for getting file URL:
if let fileURL = Bundle.main.url(forResource: fileName, withExtension: fileType, subdirectory: "filesSubDirectory") {
print(fileURL)
}

enter code here
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let documentsDirectory = paths[0]
print(documentsDirectory)

Related

How to use folders in swift not visible to users?

My app receives a Json file, i need to store this json for reading this and next I've read i need to remove that. How I can storage this file in safety mode? I don't want use a "normal folder" like download, but i want to use a internal folder in my app, is possible ? And if is not possible to use my internal folder, how i can storage my file in safaty mode on ios ?
Well the most popular option to save a file in iOS is saving in document directory of the application.
A document directory is a directory where you can save all possible files and folders what you want, and the files are completely safe from other applications, meaning, iOS doesn't permit any application to write in other's document directory. Moreover, users won't find the directory as like android.
To save a file in the document directory, for example an image file
let fileManager = FileManager.default
do {
let documentDirectory = try fileManager.url(for: .documentDirectory, in: .userDomainMask, appropriateFor:nil, create:false)
let fileURL = documentDirectory.appendingPathComponent(name)
let image = #imageLiteral(resourceName: "Notifications")
if let imageData = image.jpegData(compressionQuality: 0.5) {
try imageData.write(to: fileURL)
return true
}
} catch {
print(error)
}
to remove the file from document directory
let fileManager = FileManager.default
do {
let documentDirectoryURL = try fileManager.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
let fileURLs = try fileManager.contentsOfDirectory(at: documentDirectoryURL, includingPropertiesForKeys: nil, options: .skipsHiddenFiles)
for url in fileURLs {
try fileManager.removeItem(at: url)
}
} catch {
print(error)
}

Path for resource returns nil file path despite file is in Documents directory

When I run this code and add a breakpoint:
var pathFor = Bundle.main.path(forResource: imageName, ofType: "png")
print("breakpoint added here")
I see a nil value for the pathFor variable.
However, if I contextually check the file existence in my app Bundle (using XCode -> Device -> Device Name -> Download Container -> Show package content), I can see it inside the Documents directory:
What am I doing wrong?
UPDATE:
I have modified the code, following the suggestion in the answer.
Unfortunately I am unable to instantiate an image based on the path.
Please see here:
You are looking inside the Bundle ( i.e.: files embed on compilation time ) for a file you put in the Documents Folder. that ain't gonna work.
Your file is here :
if let dir = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.allDomainsMask, true).first {
if let path = NSURL(fileURLWithPath: dir).appendingPathComponent("file.html") {
print(path as Any)
if let imageData = NSData(contentsOf: path!) {
let image = UIImage(data:imageData as Data)
}
}
Another permutation, but I'd personally do:
let fileURL = try! FileManager.default
.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
.appendingPathComponent(imageName)
.appendingPathExtension("png")
let image = UIImage(contentsOfFile: fileURL.path)

Download PDF, saving to document directory and loading it in UIWebView

I am having problem with download pdf, saving to document directory and loading it in web view.
I have no experience with download things, saving things to directories and UIWebView before.
Before I ask this question, I've search multiple StackOverflow question and tried my best but it still doesn't work.
First This is how I download the PDF from url and save it to document directory
let myURL = URL(string: "https://example/example/product.pdf")
let urlRequest = NSURLRequest(url: myURL!)
do {
let theData = try NSURLConnection.sendSynchronousRequest(urlRequest as URLRequest, returning: nil)
var docURL = (FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)).last as? NSURL
docURL = docURL?.appendingPathComponent("my.pdf") as NSURL?
try theData.write(to: docURL as! URL)
print("downloaded")
} catch (let writeError) {
print("error : \(writeError)")
}
The application pauses for a while and prints "downloaded"
This is how I check the list of contacts in my document directory
let docURL = (FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last)
do{
let contents = try (FileManager.default.contentsOfDirectory(at: docURL!, includingPropertiesForKeys: nil, options: FileManager.DirectoryEnumerationOptions.skipsHiddenFiles))
print("There are")
print(contents)
}
catch (let error)
{
print("error contents \(error)")
}
It prints "There are [file:///private/var/mobile/Containers/Data/Application/DF6A310C-EB7E-405E-9B1B-654486B5D03A/Documents/my.pdf]"
This is how I load the pdf into webView
var webView = UIWebView(frame : vc.view.frame)
webView.scalesPageToFit = true
var paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
var documentsDirectory = paths[0]
var filePath = URL(fileURLWithPath: documentsDirectory).appendingPathComponent("my.pdf").absoluteString
var targetURL = URL(fileURLWithPath: filePath)
var request = URLRequest(url: targetURL)
webView.loadRequest(request)
vc.view.addSubview(webView)
The WebView comes up but shows nothing. I'm really confused if my.pdf is really saved with readable PDF format.
I don't know if there are some stuffs like I have to add something in info.plist or enable something in app capabilities. Thank you very much.
I didn't look through all of the code but the following two lines are a problem:
var filePath = URL(fileURLWithPath: documentsDirectory).appendingPathComponent("my.pdf").absoluteString
var targetURL = URL(fileURLWithPath: filePath)
The value of URL absoluteString does not give you a file path so the value of filePath is not a valid value for the URL fileURLWithPath: initializer.
And what's the point of going from URL to String (as a path) and back to a URL? Simply combine those two lines into:
var targetURL = URL(fileURLWithPath: documentsDirectory).appendingPathComponent("my.pdf")
As a side note, use some consistency. In other code you get the Documents folder URL using:
let docURL = (FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last)
and in other code you use:
var paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
var documentsDirectory = paths[0]
var ... = URL(fileURLWithPath: documentsDirectory)...
Pick one approach and use it consistently. Since you need a URL, use the first approach. This means the code I suggested should now be:
let docURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last!
let targetURL = docURL.appendingPathComponent("my.pdf")

URLForResource() returns always nil, swift 2.3, iOS10

I am trying to test something, and need access to the file which is in the same directory as the test class (in fact in sub-directory). I am trying to do it like this:
let fileURL = testBundle.URLForResource("MasterCalendar", withExtension: "ics", subdirectory: "Calendars")
I also tried it like this:
let fileURL = testBundle.URLForResource("MasterCalendar", withExtension: "ics")
My class is called ParserTest. The file I am trying to access is located as shown:
I tried to get the file path:
if let filePath = NSBundle.mainBundle().pathForResource("MasterCalendar", ofType: "ics", inDirectory: "Calendars") {
print("PATH: ", filePath)
}
I tried to remove inDirectory, and put also "CallInTests/Calendar". Nothing worked.
The file itself is added in the Target for tests:
AND for the project:
Regardless of what I do, the fileURL returns always nil.
It is not quite clear to me how your testBundle is defined, but this works for me:
let bundle = Bundle(for: YourClassHere.self)
So in your case that would be:
let bundle = Bundle(for: ParserTest.self)
Which you can then use like so:
if let path = bundle.path(forResource: "MasterCalendar", ofType: "ics") {
//magic goes here
}
Swift 2.3 version
let bundle = NSBundle(forClass: ParserTest.self)
if let path = bundle.pathForResource("MasterCalendar", ofType: "ics") {
//magic still goes here :)
}
Hope that helps you.
try the following way :
let testBundle = NSBundle(forClass: self.dynamicType)
let fileURL = testBundle.URLForResource("MasterCalendar", withExtension: "ics")
XCTAssertNotNil(fileURL)

Rename file in DocumentDirectory

I have a PDF file in my DocumentDirectory.
I want the user to be able to rename this PDF file to something else if they choose to.
I will have a UIButton to start this process. The new name will come from a UITextField.
How do I do this? I'm new to Swift and have only found Objective-C info on this and am having a hard time converting it.
An example of the file location is:
/var/mobile/Containers/Data/Application/39E030E3-6DA1-45FF-BF93-6068B3BDCE89/Documents/Restaurant.pdf
I have this code to see check if the file exists or not:
var name = selectedItem.adjustedName
// Search path for file name specified and assign to variable
let getPDFPath = paths.stringByAppendingPathComponent("\(name).pdf")
let checkValidation = NSFileManager.defaultManager()
// If it exists, delete it, otherwise print error to log
if (checkValidation.fileExistsAtPath(getPDFPath)) {
print("FILE AVAILABLE: \(name).pdf")
} else {
print("FILE NOT AVAILABLE: \(name).pdf")
}
To rename a file you can use NSFileManager's moveItemAtURL.
Moving the file with moveItemAtURL at the same location but with two different file names is the same operation as "renaming".
Simple example:
Swift 2
do {
let path = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0]
let documentDirectory = NSURL(fileURLWithPath: path)
let originPath = documentDirectory.URLByAppendingPathComponent("currentname.pdf")
let destinationPath = documentDirectory.URLByAppendingPathComponent("newname.pdf")
try NSFileManager.defaultManager().moveItemAtURL(originPath, toURL: destinationPath)
} catch let error as NSError {
print(error)
}
Swift 3
do {
let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
let documentDirectory = URL(fileURLWithPath: path)
let originPath = documentDirectory.appendingPathComponent("currentname.pdf")
let destinationPath = documentDirectory.appendingPathComponent("newname.pdf")
try FileManager.default.moveItem(at: originPath, to: destinationPath)
} catch {
print(error)
}
The modern way is (url is the file URL of a file in your sandbox):
var rv = URLResourceValues()
rv.name = newname
try? url.setResourceValues(rv)
There is an easier way to rename item at any given NSURL.
url.setResourceValue(newName, forKey: NSURLNameKey)
Edit - Swift4
url.setTemporaryResourceValue(newName, forKey: .nameKey)

Resources