I am developing an application which can list the phone files, such as a .pdf. But so far I could only read the files within the application directory.
The following code:
let pathURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
let path = pathURL.URLByAppendingPathComponent("file.pdf")
let pathStr = path.path
return pathStr
The above code works, but only for directories within the application directory and I need to read all directories and grab all the .pdf files.
How to get access to all phone directories? For example, read and catch all the .pdf files you have on your phone. If not, please indicate the link where the restriction list.
Due to Apple's sandboxing, you can only read documents in your own app's directory.
From the documentation:
An iOS app’s interactions with the file system are limited mostly to the directories inside the app’s sandbox.
Related
I enabled UIFilesharingEnabled option in my app set to true but this was exposes my documents file and my sqlite.db file also.
Then how can restrict on to display/access my database files to user or other apps?
You should take a look at the Library Directory section Apple File System Basics. There you can find all information regarding where to write your app files:
Library
This is the top-level directory for any files that are not user data
files. You typically put files in one of several standard
subdirectories. iOS apps commonly use the Application Support and
Caches subdirectories; however, you can create custom subdirectories.
Use the Library subdirectories for any files you don’t want exposed to
the user. Your app should not use these directories for user data
files. The contents of the Library directory (with the exception of
the Caches subdirectory) are backed up by iTunes and iCloud. For
additional information about the Library directory and its commonly
used subdirectories, see The Library Directory Stores App-Specific
Files.
You can check this post how to access the Library directory in your App Bundle
It could be achieved by using libraryDirectory.
private static var __once: NSString = {
let documentFolderPath = NSSearchPathForDirectoriesInDomains(
.libraryDirectory,
.userDomainMask,
true)[0] as String
let databaseFile = "DATABASE_FILE_NAME"
return "\(documentFolderPath)\(databaseFile)" as NSString
}()
We plan to store the following user files
SQLite file
Image files
Audio files
We also provide an option for users, to upload and download the above files, to a 3rd party cloud storage.
I was wondering, should we use
FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
or
FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)
for the above file storage purpose?
Historically we used the “Documents” folder, but nowadays the “Application Support” directory is the best place for files like this.
The File System Programming Guide says
Put user data in Documents/. User data generally includes any files you might want to expose to the user—anything you might want the user to create, import, delete or edit. For a drawing app, user data includes any graphic files the user might create. For a text editor, it includes the text files. Video and audio apps may even include files that the user has downloaded to watch or listen to later.
Put app-created support files in the Library/Application support/ directory. In general, this directory includes files that the app uses to run but that should remain hidden from the user. This directory can also include data files, configuration files, templates and modified versions of resources loaded from the app bundle.
Remember that files in Documents/ and Application Support/ are backed up by default. You can exclude files from the backup by calling -[NSURL setResourceValue:forKey:error:] using the NSURLIsExcludedFromBackupKey key. Any file that can be re-created or downloaded must be excluded from the backup. This is particularly important for large media files. If your application downloads video or audio files, make sure they are not included in the backup.
Put temporary data in the tmp/ directory. Temporary data comprises any data that you do not need to persist for an extended period of time. Remember to delete those files when you are done with them so that they do not continue to consume space on the user’s device. The system will periodically purge these files when your app is not running; therefore, you cannot rely on these files persisting after your app terminates.
Put data cache files in the Library/Caches/ directory. Cache data can be used for any data that needs to persist longer than temporary data, but not as long as a support file. Generally speaking, the application does not require cache data to operate properly, but it can use cache data to improve performance. Examples of cache data include (but are not limited to) database cache files and transient, downloadable content. Note that the system may delete the Caches/ directory to free up disk space, so your app must be able to re-create or download these files as needed.
Also see the iOS Storage Best Practices video.
If using the .applicationSupportDirectory, I’d suggest you use url(for:in:appropriateFor:create:) with create set to true:
let folderURL = try! FileManager.default
.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
It doesn't make much difference which you choose. The chief difference is in case you want to use a file browser or the Files app; they can look in your documents directory but not in your application support directory.
Also if you pick one and release the app and later change your mind, it's easy to migrate and change where the app stores its information.
My iOS app is writing to local files to:
/var/mobile/Containers/Data/Application/A.../Library/a.txt
When my app updates, it gets a new application container ID and folder:
/var/mobile/Containers/Data/Application/B...
What happens to all the files I wrote to container ID A?
Is there an "update hook" that will allow me to copy all the "A" container files to path "B"?
Can the new version of the app (B) read the old versions files (A)?
Is there any documentation around what happens to the filesystem during updates?
Is it possible to recover files from container A after B has been installed?
When you update an app, by changing its version number in the .plist file, iOS creates a new directory for that app with a different hexadecimal name and it copies all the files to the new directories. Now if you are using the absolute paths to get the details of files from the directories then those paths would be incorrect and you won't get the file details.
I just tried this in simulator. I created a function as below which will return the document directory path url
func getDocumentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let documentsDirectory = paths[0]
return documentsDirectory
}
I called this function from didFinishLaunchingWithOptions in app delegate when version number was 1.0 and it returned the below path :
file:///Users/BhargavRathod/Library/Developer/CoreSimulator/Devices/3082611F-BCCA-4D17-B390-E0EF4CA454DA/data/Containers/Data/Application/72759097-38F3-4292-825E-1D2343219973/Documents/
When I updated the version number to 1.1 it returned me the new path as :
file:///Users/BhargavRathod/Library/Developer/CoreSimulator/Devices/3082611F-BCCA-4D17-B390-E0EF4CA454DA/data/Containers/Data/Application/72DC31E9-C32F-42CC-8449-F1946ADB1018/Documents/
So if you are using a absolute path to access any file from document directory then it is not good practice. You can just save the file name(or relative path after the document directory) and whenever the access to that file name is required then get the file name and append it after the document directory path and access the file.
I hope this will be of some help to you.
My iOS app is writing to local files to: /var/mobile/Containers/Data/Application/A.../Library/a.txt
Okay, stop right there. This is wrong.
Your app has its own sandbox. This sandbox persists forever, thru updates, as long as your app keeps its Bundle ID, and as long as the user does not delete the app.
You thus have no business knowing or thinking about the full absolute path to where your file is. All you know, and all you need to know, is that it is in your app’s sandbox in the Library directory. You can, at any time, obtain the URL of the Library directory by means of its search path:
https://developer.apple.com/documentation/foundation/filemanager/searchpathdirectory/librarydirectory
And that is where the file will always be. As long as you ask the FileManager for your Library directory and for the a.txt file within it, you will find the same file, regardless of any updates, as long as the user doesn’t actually delete your app (because that deletes the sandbox).
Can explain what happens to the files
Nothing. They stay where they are within the sandbox. The absolute URL of the sandbox may change, but your files are unaffected.
how to keep the files written by the previous version of the app
They are kept automatically. You don’t have to do anything.
(Having said all that, keep in mind that if you submit an app with a different bundle id, that is not a new version of your app. It is a totally different app. In that case you would have a very different problem to solve. This would be no different from any other problem of communicating files from one app to another. You’d need to put the files in a common location, make them available thru the Document Browser, make them exportable by the user, or whatever.)
I have developed an iOS app that has been downloading files and storing data in the Documents directory. I am storing document’s directory path (where downloaded files get store) in sqlite database. Now if App version get changes then path for database file and document’s directory get changes. If I have manually delete the app and install it again then downloaded files get removed from document’s directory and user has to download files again. Is there any way to get my database file with previously downloaded document’s directory path so that no need to download files again Or any other solution for this?
Understand this concept for document directory
If you update the newer version of the App, Data in the document directory will not getting erased. It will be there. Just the path to reach the document directory get's updated.
So, to overcome the path changing problem. Don't store the entire path to your database file. Just store the ending path or name of the downloaded content to the document directory. Now, if you wants to get some file, lets say example.jpg from the document directory, then you should first get the path to document directory and then append the path of your file.
PATH_TO_DOCUMENT_DIRECTORY/example.jpg this is the complete path for your image. and same is applies for your database.sqlite file.
You can use this handy functions:
func documentsDirPath() -> String {
var paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true) as [String]
return paths[0]
}
And can call it in this way:
let pathToDocumentDirectory = documentsDirPath()
let fileName = "example.jpg" // This you can get from the database.
let filePath = pathToDocumentDirectory + "/\(fileName)"
print(pathToDocumentDirectory)
And for the app that get's deleted, there is no option to recover the contents of the document directory, unless you code and save the data to iCloud and on newer installation of the app, in applicationDidFinishLaunching check if there is some files, present on iCloud with name database.sqlite and other, then you can fetch it and put it to document directory and later you can use.
Hope it helps
I'm basically doing variations on this:
let dir = fileManager.url(forUbiquityContainerIdentifier: nil)?
let files = try fileManager.contentsOfDirectory(at: dir)
trying to get to the root (i.e., the "/") of iCloud Drive, where I have some files that aren't in any folder.
However, dir is (expectedly, I guess) my app's folder.
Is it even possible to access the root of iCloud Drive? I mean, users can obviously drop files here, but can I get to that directory? (Note that for the moment I'm trying to avoid using a DocumentPickerViewController.)
It is not possible to access directly files outside of your app's iCloud container. I you want to allow users to give your app access to files that are potentially stored somewhere else, you need to UIDocumentPickerViewController.
More information on iCloud documents can be found here:
https://developer.apple.com/library/content/documentation/General/Conceptual/iCloudDesignGuide/Chapters/DesigningForDocumentsIniCloud.html#//apple_ref/doc/uid/TP40012094-CH2-SW1