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)
}
Related
This question already has answers here:
How to write a file to a folder located at Apple's Files App in Swift
(2 answers)
Closed 3 years ago.
I am doing a scanner app that scans a picture and converts it into a PDF. I want to be able to save it to "On My IPhone" but I do not know that path URL. Here is what I have so far:
let data = pdfDocument.dataRepresentation()
let documentsDirectoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let currentTimeStamp = String(Int(NSDate().timeIntervalSince1970))
let docURL = documentsDirectoryURL.appendingPathComponent("Scan\(currentTimeStamp).pdf")
do{
try data?.write(to: docURL)
}catch(let error)
{
print("error is \(error.localizedDescription)")
}
However, the I cannot find my file on my phone because I do not know what "Directory" URL is. How can I get my PDF to save to my iPhone Storage? What is the URL to my "On My IPhone" folder?
Thanks in advance.
In order to retrieve the urls of the files contained in documents directory, you can use the following code snippet.
guard let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
do {
let directoryContents = try FileManager.default.contentsOfDirectory(at: documentsDirectory, includingPropertiesForKeys: nil, options: [])
// Print the urls of the files contained in the documents directory
print(directoryContents)
} catch {
print("Could not search for urls of files in documents directory: \(error)")
}
My Scenario, I am trying to delete all files from particular document directory by using document folder path. Here, every time I am saving file within my application document directory folder, by using below code I can’t able to delete files
let urlString: String = myurl.absoluteString
print("FILEURL:\(urlString)")
do {
try fm.removeItem(atPath: "\(myurl)")
} catch let error as NSError {
print(error.debugDescription)
}
You are mixing up URL and String path
Either use the String related API
try fm.removeItem(atPath: myurl.path) // NEVER use .absoluteString for a file system path
or use the URL related API (recommended)
try fm.removeItem(at: myurl)
To remove all files get the file URLs in the enclosing directory with contentsOfDirectory(at:includingPropertiesForKeys:options:) and remove one by one
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)
}
For delete specific file or folder using Url
let filePathString = "file:///Users/mac-01/Library/Developer/CoreSimulator/Devices/092D2386-5B43-4D98-8DCF-F21E08CCD400/data/Containers/Data/Application/C6D910A2-67D9-48A4-8221-5C81C722D508/Documents/Products"
guard let fileUrl = URL(string: "\(filePathString)") else { return }
do {
try FileManager.default.removeItem(at: fileUrl)
print("Remove successfully")
}
catch let error as NSError {
print("An error took place: \(error)")
}
removeItem method is accept url of document directory file or folder.Please try with it.
For Delete Document directory folder use
let fileManager = FileManager.default
let myDocuments = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first!
do {
try fileManager.removeItem(at: myDocuments)
} catch {
return
}
Just like browsing UIIMage using UIImagePickerViewController. Is there any way to browse Another files in Swift / objective code?
if let fileURL = NSBundle.mainBundle().URLForResource("MyImage", withExtension: "jpg") {
// Instantiate the interaction controller
self.docController = UIDocumentInteractionController(URL: fileURL)
}
else {
shareButton.enabled = false
print("File missing! Button has been disabled")
}
You can only access files in document folder. To access All the files
let fileManager = FileManager.default
let documentsURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0]
do {
let fileURLs = try fileManager.contentsOfDirectory(at: documentsURL, includingPropertiesForKeys: nil)
// process files
} catch {
print("Error while enumerating files \(documentsURL.path): \(error.localizedDescription)")
}
and if you want to single file look following code:
// Get the document directory url
let documentsUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
do {
// Get the directory contents urls (including subfolders urls)
let directoryContents = try FileManager.default.contentsOfDirectory(at: documentsUrl, includingPropertiesForKeys: nil, options: [])
print(directoryContents)
// if you want to filter the directory contents you can do like this:
let mp3Files = directoryContents.filter{ $0.pathExtension == "mp3" }
print("mp3 urls:",mp3Files)
let mp3FileNames = mp3Files.map{ $0.deletingPathExtension().lastPathComponent }
print("mp3 list:", mp3FileNames)
} catch {
print(error.localizedDescription)
}
If you want to view PDF files within your app there are two ways.
PDFView - available iOS 11.0
let pdfDocument = PDFDocument(url: url)
pdfView.document = pdfDocument
WKWebView - available iOS 8.0
webView.loadRequest(URLRequest.init(url: url))
You could also use UIWebview to get the same result, But it has been deprecated.
Alternatively, use a file explorer library that you can customize to what you need done. Something like this
https://developer.apple.com/documentation/pdfkit/pdfview
https://developer.apple.com/documentation/webkit/wkwebview
Below is my code -
I have tried to get the document directory path and with standard FileManager singleton tried to create a file, but I am not able to create the file, as the error -
Unable to store data: Error Domain=NSCocoaErrorDomain Code=4 "The file “CrashLog.txt” doesn’t exist."
UserInfo={NSFilePath=file:///Users/ABC/Library/Developer/CoreSimulator/Devices/87317777-63E7-422B-A55F-878E3267AFB8/data/Containers/Data/Application/4B41AA87-E4B9-4EE4-A67F-AC3B018913CC/Documents/CrashLog,
NSUnderlyingError=0x600000244ec0 {Error Domain=NSPOSIXErrorDomain
Code=2 "No such file or directory"}}
Code in development -
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
if (paths.count > 0) {
let documentsDirectory = paths[0]
let logFilePath = URL(fileURLWithPath: documentsDirectory).appendingPathComponent("CrashLog.txt").absoluteString
let _string = "Hello"
//Create file at given path
let data = _string.data(using: .utf8)
//let attributes = FileManager.default.attributesOfItem(atPath: logFilePath)
let fileExists : Bool = FileManager.default.fileExists(atPath: logFilePath)
print(fileExists)
let isFileCreated = FileManager.default.createFile(atPath: logFilePath, contents: data, attributes: nil)
print("ifFileCreated", isFileCreated)
}
Here's my take on what you've done. Adopt the URL-based means of working with files. The best way to write data (for this example, at least), is to use Data's ability (not FileManager) to write to a file, again, using a URL. In most cases, you don't need to worry whether the file exists or not; just do it, and handle any error that arises.
if var url = try? FileManager.default.url(for: .documentDirectory,
in: .userDomainMask,
appropriateFor: nil,
create: false) {
url = url.appendingPathComponent("CrashLog").appendingPathExtension("txt")
let _string = "Hello"
if let data = _string.data(using: .utf8) {
do {
try data.write(to: url)
print("successful")
} catch {
print("unsuccessful")
}
}
}
The appendingPathComponent method if the receiver (e.g. parameter) does not end with a trailing slash, then it may read file metadata to determine whether the resulting path is a directory. That means it may produce the error you are seeing, so better use the appendingPathComponent(_:isDirectory:) instead.
For example:
let logFilePath = URL(fileURLWithPath: documentsDirectory).appendingPathComponent("CrashLog.txt", isDirectory: false).absoluteString
The API absoluteString is wrong. The correct API is path
absoluteString returns the entire URL string representation including the scheme file://. On the other hand the path API of FileManager expects file system paths, the string without the scheme.
You are encouraged to use the URL related API anyway and you can write Data directly to disk without explicitly creating a file.
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let logFileURL = documentsURL.appendingPathComponent("CrashLog.txt")
let string = "Hello"
let data = Data(string.utf8)
let fileExists = FileManager.default.fileExists(atPath: logFileURL.path)
print(fileExists)
do {
try data.write(to: logFileURL)
print("data written")
} catch { print(error) }
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)