I want to write a file on my iPhone app. My file is in my project's folder, but when I try to reach it :
NSString *myFile = [[NSBundle mainBundle] pathForResource:#"myFile" ofType:#"txt"];
NSLog(#"%#",myFile);
I get the following path :
2012-06-13 17:36:56.398 MyFileApp[610:15203] /Users/Damian/Library/Application Support/iPhone Simulator/5.1/Applications/1FFD4436-DCCA-4280-9E47-F6474BEE0183/MyFileApp.app/myFile.txt
Why ?
Thanks for your advices
You ask:
Why?
It's that path because that's where the file is stored.
On the device it will be different.
Note that you can't write a file to that folder anyway. You should perhaps instead write to your app's documents folder:
//Get the documents folder
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0];
//Get the final path of your file.
NSString *finalPath = #"myfile.txt"];
//And actually write that file.
[[NSFileManager defaultManager] createFileAtPath:finalPath contents:/*fileData as NSData*/ attributes:nil];
As already said you can't write to the main bundle on an actual device.
To your other question:
When you run your app in the simulator xcode will copy your project to a folder in your library directory .. in your case to:
/Users/Damian/Library/Application Support/iPhone Simulator/5.1/Applications/
Every app you run in your simulator has a folder there. Apps are not run in the folders where you actually edit your code.
Related
Im trying to find a file with NSFileManager. The file exists but my path is never correct no matter how its phrased. The code I'm using is below. Why is NSFileManager not finding the file?
NSString *myFile = #"file1658.pdf";
NSFileManager *fileManager = [NSFileManager defaultManager];
if ([fileManager fileExistsAtPath:myFile]) {
NSLog(#"good");
}
MyFile is not a full path (e.g., "/Users/Joe/Documents/file1658.pdf"), so NSFileManager is looking for it in the current working directory. You can see what that is with -[NSFileManager currentDirectoryPath].
You need to either include the full path to the file as part of myFile, or set the proper working directory with -[NSFileManager changeCurrentDirectoryPath:].
// If myFile is in "/Users/joe/Documents"...
[fileManager changeCurrentDirectoryPath:#"/Users/joe/Documents"];
if ([fileManager fileExistsAtPath:myFile]) {
NSLog(#"good");
}
Apple tries hard to get you to put your files in sensible places. The file my exist, but you will have to either give the full path, e.g. /Users/user2759189/file1658.pdf or specify what folder it is in by other means.
App bundle
If the file is in your app bundle (for example, you have added it using "Add files to [project]" in XCode) you can get its path by something like:
NSString *myFile = [[NSBundle mainBundle] pathForResource:#"file1658" ofType:#"pdf"];
Search paths
You can look for user documents in a civilised manner by using the foundation function NSSearchPathForDirectoriesInDomains and some built in constants. If the file is in the user's Documents folder, for example, you can use something like:
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *myFile = [documentsPath stringByAppendingPathComponent:#"file1658.pdf"];
So I have the following method to get a path:
- (NSString *)filePath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *filePath = [[paths objectAtIndex:0] stringByAppendingPathComponent:[NSString stringWithFormat:#"%#_json", self.identifier]];
return filePath;
}
this path will be used for a keychain access kSecAttrAccount and kSecAttrGeneric. So therefore I am expecting it to have the same path. However it turns out that after I upgrade my app this path changes.
Before it was:
/var/mobile/Applications/CEE344F7-4FE1-4455-BD6D-A4D6EAA4F5FE/Documents
and after wards it was:
/var/mobile/Applications/A6429F46-972C-4BC1-A71B-2786312663E8/Documents/
What can cause this to happen?
That means that iOS installs the updated version of the app in a new folder. Once that is done it will move the user data over to the new folder and remove the old one. This is probably done, so an error during installation won't corrupt the existing app.
The Situation:
I have an iOS app that deals with files and lets the user save, edit, open and perform various operations with these files. I'd like to be able to have some pre-made documents for the user to look at when they open the app (ex. a template) alongside their own custom documents.
The Problem:
How can I create a document (or template file) and have it appear in the Documents folder after the user installs my app and launches it (and all preceding times)?
Background:
This document (the one that'd be installed into the app's documents directory) is created by me, not the user.
I know that to do this you need to save it in your bundle, and then when your app runs for the first time silently copy it into the Documents Directory. Should I copy it in the appDidFinishLaunchingWithOptions method or in my viewDidLoad method and write logic to detect if it's the first time the app has run?
My Code:
At this webpage: http://textsnip.com/d35fbc
But when it runs, it always says: "File does not exist [in documents folder]", then it tells me that it's being copied. The problem is that when I examine the app's documents folder it is never there, it's still in the bundle.
Why won't it copy with this code
How does this work?
the files must in fact be added to the app bundle, then copied silently when the app launches.
The following code copies a text file from the top level of my bundle to the documents directory if it doesn't already exist.
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *txtPath = [documentsDirectory stringByAppendingPathComponent:#"txtFile.txt"];
if ([fileManager fileExistsAtPath:txtPath] == NO) {
NSString *resourcePath = [[NSBundle mainBundle] pathForResource:#"txtFile" ofType:#"txt"];
[fileManager copyItemAtPath:resourcePath toPath:txtPath error:&error];
}
The only flaw in this code is that if the user deletes the file, it immediately reappears when they open the app again.
As you said, you include it in your app bundle (add it to your project and make sure it's part of your target). Then you can access it's path by calling something like this:
NSString *bundlePath = [[NSBundle mainBundle] pathForResource:#"MyTemplateDoc"
ofType:#"extension"];
Then you copy it to your app's documents folder.
NSString *docPath = <a path in your documents folder>
NSError *error = nil;
[[NSFileManager defaultManager] copyItemAtPath:bundlePath
toPath:docPath
error:&error];
if (error) {
// handle copy error.
}
I have been working on a Core Data iOS app that works perfectly through Apple's "channels" – iOS simulator & Xcode installing, yet when I try to manually install it onto a device, the application crashes. My main goal is to put the app on Cydia.
A guide to preparing an app for Cydia
I read this article, and I at the bottom it said
Appstore app has a Documents folder that is created by the installation process. Jailbroken app does not. It is up to the app to create its own folder. Should you need this type of folder, you must create this with a simple mkdir command in your applicationDidFinishLaunching function. Just add a simple function: mkdir(“/var/mobile/Library/YOURAPPNAME”, 0755); If the folder already exists, no harm done. You want to do this because the install process runs as user root and the app runs as user mobile. If Cydia does this for you then the folder will have the incorrect permissions.
I do not know much about how exactly Core Data works, but I know the Core Data "database" is stored in the Documents folder, and I now believe this is the cause of the crash of my app.
The mkdir function did not work in creating a Documents folder.
How would I go about creating a Documents folder, and how would I get it to work with Core Data, ensuring the database is loaded from this folder I created?
Thanks in advance
Most likely you are still using the AppStore friendly Documents path in the methods which create and load the CoreData database file (I think Xcode will put these in your AppDelegate by default).
Check the method which loads the persistentStorageCoordinator and look for a line like this:
NSURL *storeUrl = [NSURL fileURLWithPath: [docPath stringByAppendingPathComponent:#"my_cool_app.sqlite"]];
And make sure that docPath is "/var/mobile/Library/My_Cool_App" and not originating from the standard AppStore friendly:
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docPath = [documentPaths objectAtIndex:0];
You might want to create a method which returns the proper Documents directory depending on what target you compile the app for:
+(NSString *)documentsDirectoryPath
{
#ifdef JAILBREAK
NSString *documentPath = #"/var/mobile/Library/My_Cool_App";
if (![[NSFileManager defaultManager] fileExistsAtPath:documentPath])
{
[[NSFileManager defaultManager] createDirectoryAtPath:documentPath
withIntermediateDirectories:NO
attributes:nil
error:NULL];
}
return documentPath;
#else
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
return [documentPaths objectAtIndex:0];
#endif
}
I am trying to take content from one file and write it into another. I am reading fine, but I am not able to write it into another file.
I have a database of words. I want to separate the words into different files based on the number of letters. All four letter words go into one file, and so on. I added a txt file called "4letter" into my resources and the following is my code:
NSError *error;
//READ
NSString *dbFile = [[NSBundle mainBundle] pathForResource:#"words" ofType:#"txt"];
NSString *test = [NSString stringWithContentsOfFile:dbFile encoding:NSUTF8StringEncoding error:&error];
//convert from string to array
NSArray *lines = [test componentsSeparatedByString:#"\n"];
NSFileHandle *logFile = nil;
logFile = [NSFileHandle fileHandleForWritingAtPath:[[NSBundle mainBundle] pathForResource:#"4letter" ofType:#"txt"]];
//Test if write works
for (int i=0; i<5; i++)
{
NSString *randomAnagram = [[lines objectAtIndex:i] lowercaseString];
[logFile writeData: [randomAnagram dataUsingEncoding: NSNEXTSTEPStringEncoding]];
}
In iOS, you can't write into a file in your app's bundle -- the entire bundle is read-only. Use a path into the Documents folder instead.
See special File System Programming Guide for better understnading.
In iOS, you can't write into a file in your app's bundle -- the entire bundle is read-only.
Consider reading iOS Data Storage Guidelines to better understand the purpose of directories below, in context of iCloud backup.
<Application_Home>/AppName.app
This is the bundle directory containing the app itself. Do not write
anything to this directory. To prevent tampering, the bundle directory
is signed at installation time. Writing to this directory changes the
signature and prevents your app from launching again.
<Application_Home>/Documents/
Use this directory to store critical user documents and app data
files. Critical data is any data that cannot be recreated by your app,
such as user-generated content. The contents of this directory can be
made available to the user through file sharing. The contents of this
directory are backed up by iTunes.
<Application_Home>/Library/
This directory is the top-level directory for files that are not user
data files. You typically put files in one of several standard
subdirectories but you can also create custom subdirectories for files
you want backed up but not exposed to the user. You should not use
this directory for user data files. The contents of this directory
(with the exception of the Caches subdirectory) are backed up by
iTunes. For additional information about the Library directory, see
“The Library Directory Stores App-Specific Files.”
See full list (tmp/, Documents/Inbox) in iOS Standard Directories: Where Files Reside
UPDATE
I use NSFileManager method URLForDirectory:inDomain:appropriateForURL:create:error:
Like Caleb said, you can't write to your app's directory, but you can write to your app's Documents folder. You can get it like this:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
Your app's bundle is read-only. There is two ways I could see:
1) Write in documents folder:
NSArray *pathList = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path = [myPathList objectAtIndex:0];
2) Use sqlite database. This is the same as 1 (you must save db in documents anyway), but you're using sqlite database. I think this is better than a lot of txt and plist files: here's a tutorial on the topic.
I use the following code :
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *appFile = [documentsDirectory stringByAppendingPathComponent:#"set.txt"];
NSString *data=#"Kostas";
[data writeToFile:appFile atomically:YES];
NSString *myData = [NSString stringWithContentsOfFile:appFile];
NSLog(#"Data : %# ",myData);