I have file in my App bundle on iOS. How can I move it to be in Document folder?
Can this be done through some configuration or I need to make custom code for it?
By custom code I mean:
check is this first run of app:
if so, move files to the Document folder.
Please check out NSFileManager which allows you to copy files within the file system as required. You should be aware that Apple will reject your App if the copied file is not flagged to NOT backup to iCloud.
I use the following methods to copy a sqlite database from the bundle to a folder; it should work for your purpose with minor modification.
+ (void)copyBundleFileToStoresDirectory:(NSString *)filename
{
NSError *error;
NSURL *fileURL = [NSURL fileURLWithPath: [[NSBundle mainBundle] pathForResource:filename ofType:nil]];
NSURL *pathURL = [SVOFileSystemMethods documentsSubdirectory:#"Stores" skipBackup:YES];
if (fileURL)
{
if([[NSFileManager defaultManager] copyItemAtURL:fileURL toURL:pathURL error:&error])
{
// NSLog(#"File successfully copied");
}
else
{
[[[UIAlertView alloc]initWithTitle:NSLocalizedString(#"error", nil) message: NSLocalizedString(#"Failed to copy database from bundle.", nil)
delegate:nil cancelButtonTitle:NSLocalizedString(#"OK", nil) otherButtonTitles:nil] show];
NSLog(#"Error description-%# \n", [error localizedDescription]);
NSLog(#"Error reason-%#", [error localizedFailureReason]);
}
}
}
+ (NSURL *) documentsSubdirectory:(NSString *)subdirectoryName skipBackup:(BOOL) skipBackup
{
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0]; // Get documents folder
NSString *dataPath = [documentsDirectory stringByAppendingPathComponent:subdirectoryName]; //untested change here -- was literal #"/Stores"
if (![[NSFileManager defaultManager] fileExistsAtPath:dataPath])
{
[[NSFileManager defaultManager] createDirectoryAtPath:dataPath withIntermediateDirectories:YES attributes:nil error:&error]; //Create folder
NSURL *finalURL = [NSURL fileURLWithPath:dataPath];
if (skipBackup)
[SVOFileSystemMethods addSkipBackupAttributeToItemAtURL:finalURL]; // flag to exclude from backups.
return finalURL;
}
else
return [NSURL fileURLWithPath:dataPath]; // already existed
}
//
// flags URL to exclude from backup
//
+ (BOOL) addSkipBackupAttributeToItemAtURL:(NSURL *)URL
{
NSError *error = nil;
BOOL success = [URL setResourceValue: [NSNumber numberWithBool: YES]
forKey: NSURLIsExcludedFromBackupKey error: &error];
if(!success)
{
NSLog(#"Error excluding %# from backup %#", [URL lastPathComponent], error);
}
return success;
}
From what I understand, you can't "move" files from the app bundle to the app directory, since that requires deleting them from the bundle. You'll get an access denied, assuming your code is set up right.
You can "copy" files however, since that it simply a read.
In my case, I had a whole bunch of files that I wanted to move to the app's Library directory but was unable. Additionally, the copy operation was far too costly because of the quantity of files.
In this case, I changed the app logic to check for "fresh" information first (that I would save to the Library folder), & if it wasn't there then fall back to the App bundle to look for an old/original copy of the file.
Related
I want to export my whole database from my app via email and on other device when i download that database file, it can be open directly in app and replace my existing database file with that database file.
I have exported my database file(.sqlite) via mail and i want to import that file from mail into my app. I have also implement the functionality which the file from mail can directly open in my app. But i want to import that database file directly from mail. So how can i do that?
Or Can i replace that file with my app database?
I think you are looking for below method,
- (BOOL)replaceItemAtURL:(NSURL *)originalItemURL withItemAtURL:(NSURL *)newItemURL backupItemName:(nullable NSString *)backupItemName options:(NSFileManagerItemReplacementOptions)options resultingItemURL:(NSURL * _Nullable * _Nullable)resultingURL error:(NSError **)error NS_AVAILABLE(10_6, 4_0);
you can call this method with NSFileManager's instance or object. You can pass source and destination path as fileUrl ([NSURL fileURLWithPath:#"path string"];) and it will replace data at destination path!
Couldn't understand your problem completely but here is a code that can give any clue how to replace your existing file in documents directory:
//Reference the path to the documents directory.
NSString *documentDir =[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
//Get the path of old file.
NSString *filePath = [documentDir stringByAppendingPathComponent:#"File.sqlite"];
if([[NSFileManager defaultManager] fileExistsAtPath: filePath])
{
[fileManager removeItemAtPath:filePath error:&error] //Delete old file
}
//Copy New File.sqlite from Resource Bundle.
NSString *resourcePath = [[NSBundle mainBundle] pathForResource:#"File" ofType:#"sqlite"];
[fileManager copyItemAtPath:resourcePath toPath:filePath error:&error];
This link is helps to all your questions in SQLITE,
Like Copy Sqlite File in to Docs directory,
and also Select queries, Insert, Delete, Update varius types of recotds etc.. etc...
Checkout + (NSString*) copyDBFile method in this link for ur requirement
SQLite Programing : Initial Steps - By iOSCodeGUIDE
//Commen method for DAtaBase Copy
+ (NSString*) copyDBFile
{
NSString *docsDirectoryPath;
NSArray *dirPaths;
NSString *databasePath;
NSFileManager *fileManager = [NSFileManager defaultManager];
// Get the documents directory
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDirectoryPath = [dirPaths objectAtIndex:0];
// Build the path to the database file
databasePath = [[NSString alloc] initWithString: [docsDirectoryPath stringByAppendingPathComponent: #"SqliteTable.db"]];
BOOL isSuccess = [fileManager fileExistsAtPath: databasePath ];
if (!isSuccess)
{
NSError *error;
NSString *defaultDBPath=[[NSBundle mainBundle]pathForResource:#"SqliteTable" ofType:#"db"];
// NSLog(#"path :%#", defaultDBPath);
isSuccess = [fileManager copyItemAtPath:defaultDBPath toPath:databasePath error:&error];
if (! isSuccess)
NSAssert1(0, #"Failed to create writable database file with message '%#'.", [error localizedDescription]);
}
NSLog(#"%#",databasePath);
return databasePath;
}
You should use iOS share extensions to first import the database file from mail app. Here is a tutorial that you can refer to.
// Returns the persistent store coordinator for the application.
// If the coordinator doesn't already exist, it is created and the application's store added to it.
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (_persistentStoreCoordinator != nil)
{
return _persistentStoreCoordinator;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"yourSqlite.sqlite"];
NSString *sourcePath = [[NSBundle mainBundle] pathForResource:#"yourSqlite.sqlite" ofType:nil];
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSError *error = nil;
if (![[NSFileManager defaultManager] fileExistsAtPath:[documentsDirectory stringByAppendingPathComponent:#"yourSqlite.sqlite"] ]) {
if([[NSFileManager defaultManager] copyItemAtPath:sourcePath toPath:[documentsDirectory stringByAppendingPathComponent:#"yourSqlite.sqlite"] error:&error]){
NSLog(#"Default file successfully copied over.");
} else {
NSLog(#"Error description-%# \n", [error localizedDescription]);
NSLog(#"Error reason-%#", [error localizedFailureReason]);
}
}
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return _persistentStoreCoordinator;
}
when i use simulator,i can find the database file in /documents .but when i use my iPhone to run the project,i can not find the database file.
what time should i create the database file or use this code in my project?
NSArray *searchPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentFolderPath = [searchPaths objectAtIndex:0];
NSString *dbFilePath = [documentFolderPath stringByAppendingString:DATABASENAME];
NSFileManager *fm = [NSFileManager defaultManager];
BOOL isExist = [fm fileExistsAtPath:dbFilePath];
if (!isExist) {
NSString *backupDbPath = [[[NSBundle mainBundle]resourcePath]stringByAppendingString:DATABASENAME];
[fm copyItemAtPath:backupDbPath toPath:dbFilePath error:nil];
}
For the first time or the database file does not exist in the documents directory, you have to copy DB file to document directory:
-(void)copyDatabaseIntoDocumentsDirectory{
// Check if the database file exists in the documents directory.
NSString *destinationPath = [self.documentsDirectory stringByAppendingPathComponent:self.databaseFilename];
if (![[NSFileManager defaultManager] fileExistsAtPath:destinationPath]) {
// The database file does not exist in the documents directory, so copy it from the main bundle now.
NSString *sourcePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:self.databaseFilename];
NSError *error;
[[NSFileManager defaultManager] copyItemAtPath:sourcePath toPath:destinationPath error:&error];
// Check if any error occurred during copying and display it.
if (error != nil) {
NSLog(#"%#", [error localizedDescription]);
}
}
}
Ref: http://www.appcoda.com/sqlite-database-ios-app-tutorial/
You can't access the directories of iPhone or iPad. So even if you successfully created a database, you won't see it. You can judge its existence by read data from it.
My app needs to create a subdirectory of the Documents directory. The code below returns the directory URL. First time through it creates the directory, but fails next time because fileExistsAtPath: claims the directory still doesn't exist. I know it exists though because I have set the bundle to make files visible in iTunes and I can see it in iTunes. Any idea what I'm doing wrong?
- (NSURL *)applicationDocumentsDirectory
{
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
- (NSURL *)applicationSubDirectory
{
NSFileManager *manager = [NSFileManager defaultManager];
NSURL *docDir = [self applicationDocumentsDirectory];
docDir = [docDir URLByAppendingPathComponent:#"Sub" isDirectory:YES];
NSString *docDirPath = [docDir absoluteString];
BOOL isFolder = YES;
if(!([manager fileExistsAtPath:docDirPath isDirectory:&isFolder] && isFolder)) {
NSError *error = nil;
BOOL ret = [manager createDirectoryAtURL:docDir withIntermediateDirectories:NO attributes:nil error:&error];
if(!ret) {
NSLog(#"ERROR app support: %#", error);
abort();
}
}
return docDir;
}
You want to use path instead of absoluteString The former returns the full url absolute path, something like "file:///..." while the latter only returns the file path.
NSString *docDirPath = [docDir path];
So, since you're looking for a file with the path "file:///...." which will never exist, the check always fails. When you go to create the directory, you create it with the URL, so it works.
I'm building an app which has non-consumable in-app purchases hosted on Apple's servers. I've been successful in getting my in-app purchases to download, but when I save them to the documents directory, I can't seem to locate or access them afterwards.
Here is the function I use to download the file from the download's contentURL. It is called after the download is completed, passing in download.contentURL to move it's location in the cache to the documents folder.
-(void)downloadFromURL: (NSURL *) temporaryURL {
NSLog(#"The download's contentURL is %#", temporaryURL.absoluteString);
NSString *folderName = [[temporaryURL path] lastPathComponent];
NSArray *pathArr = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *folder = [pathArr objectAtIndex:0];
NSString *filePath = [folder stringByAppendingPathComponent:folderName];
NSURL *fileURL = [NSURL fileURLWithPath:filePath];
NSError *writeError = nil;
NSData *downloadData = [[NSData alloc] initWithContentsOfURL:temporaryURL];
[downloadData writeToURL: fileURL options:0 error:&writeError];
if( writeError) {
NSLog(#"Error in writing file %#' : \n %# ", filePath , writeError);
return;
}
NSLog(#"File successfully downloaded. Url is %#",fileURL.absoluteString);
myFileURL = fileURL;
}
myFileURL is a global variable that is called upon later to initialize an AVAudioPlayer, but when I call
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:[myFileURL path]]){
NSLog(#"File DOES NOT exist at that url");
} else{
NSLog(#"File DOES exist at that url");
}
It says that a file does not exist at that path. Any ideas or simple ways to write and access in app purchase content downloaded from apple's servers? I've also tried adding "/Contents/filename.mp3" to the end of the URL to no avail.
Resolved using the code found here: http://xinsight.ca/blog/iap-content-download-in-ios6
I used the Master-Detail-Application example at Xcode 4.3.3 to develope a data viewer. The app is downloading several files and append each file to a cell at the tableview. everything works fine. but if the user starts the download again, I need to remove all the previous data from the database and the tableview.
I ended up with the following steps:
remove the old store from coordinator
remove the old sqlite database file
copy the default ( empty ) sqlite db file from the bundle dir into the doc dir
update store coordinator
update tableview.
but now the problem is, that if I do so, the new data is not written into sqlite file.
Please, can someone check my code. The following code is located at the MasterViewController.m ! I working on this since several days and I am totally stuck !!!
Thank you!
NSLog(#"Delete existing database file and copy default from bundle dir!");
NSFileManager* fileManager = [[NSFileManager alloc] init];
fileManager = [[NSFileManager alloc] init];
NSError *error = nil;
//get the documents directory:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
// create database path documents dir
NSString *databasepath = [documentsDirectory stringByAppendingPathComponent:#"MyDatabase.sqlite"];
NSLog(#"Destination Database Path = %#", databasepath);
// create database path bundle dir
NSString *resourceDBFolderPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"MyDatabase.sqlite"];
NSLog(#"Recource Database Path = %#", resourceDBFolderPath);
// remove old store from coordinator
error = nil;
NSManagedObjectModel *managedObjectModel;
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"MyDatabase" withExtension:#"momd"];
managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
// Returns the persistent store coordinator for the application.
// If the coordinator doesn't already exist, it is created and the application's store added to it.
NSPersistentStoreCoordinator *persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL]];
NSURL *applicationDocumentsDirectory = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
NSURL *storeURL = [applicationDocumentsDirectory URLByAppendingPathComponent:#"MyDatabase.sqlite"];
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error])
if (error != nil){
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
}
NSPersistentStore *persistentStore = [[persistentStoreCoordinator persistentStores] objectAtIndex:0];
[persistentStoreCoordinator removePersistentStore:persistentStore error:&error];
if (error)
if (error != nil){
NSLog(#"error removing persistent store %# %#", error, [error userInfo]);
}
// Remove old database file
[[NSFileManager defaultManager] removeItemAtPath: [documentsDirectory stringByAppendingPathComponent: #"MyDatabase.sqlite"] error: &error];
if (error != nil){
NSLog(#"delete Database status: %#", [error localizedDescription]);
}
// copy default empty database file into documents dir
[fileManager copyItemAtPath: resourceDBFolderPath toPath: databasepath
error: &error];
if (error != nil){
NSLog(#"copy default Database status: %#", [error localizedDescription]);
}
// then update storecoordinator
// add clean store file back by adding a new persistent store with the same store URL
if (![persistentStoreCoordinator addPersistentStoreWithType: NSSQLiteStoreType
configuration: nil
URL: storeURL
options: nil
error: &error]) {
NSLog(#"failed to add db file, error %#, %#", error, [error userInfo]);
}
NSLog(#"Database replacement end!");