I have a score system and I would like to log all scores in a text file separated by line breaks. Here is my current save code:
NSData *dataToWrite = [[NSString stringWithFormat:#"String to write ID:%i \n",random] dataUsingEncoding:NSUTF8StringEncoding];
NSString *docsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *path = [docsDirectory stringByAppendingPathComponent:#"text.txt"];
// Write the file
[dataToWrite writeToFile:path atomically:YES];
When retrieving this data, I only see the latest save. How do I make it so it saves all in a list?
Thanks.
[dataToWrite writeToFile:path atomically:YES]; overwrites the file at that location, replacing whatever is there with the contents of dataToWrite.
You can likely use NSFileHandle's fileHandleForWritingAtPath: and then call seekToEndOfFile to append to said file.
Do you have an example?
Try something like:
NSFileHandle *f = [NSFileHandle fileHandleForWritingAtPath: p];
[f seekToEndOfFile];
[f writeData: d];
[f close];
All typed into SO; the compiler/runtime might differ with my opinions of correctness.
Related
Well, I know it may sounds basic, but I have literally been looking everywhere and could not find a straight answer to that. I am trying to save location coordinates to a file every time I get an update - sounds simple.... I have two problems: one is with the data type (writeToFile seems to save only NSData) and the other one is with appending to the end of the file. I tried to use NSKeyedArchiver but it wrote a bunch of garbage and I could not find how to append to the end of file with it.
Here is my code - if you could help I would greatly appreciate that. Thanks!
....
NSMutableArray *array = [[NSMutableArray alloc] init];
NSNumber *numLat = [NSNumber numberWithFloat:location.coordinate.latitude];
NSNumber *numLong = [NSNumber numberWithFloat:location.coordinate.longitude];
[array addObject:numLat];
[array addObject:numLong];
NSFileHandle *file;
file = [NSFileHandle fileHandleForUpdatingAtPath: #"./location.txt"];
if (file == nil)
NSLog(#"Failed to open file");
[file seekToEndOfFile];
[file writeData: array]; //BTW - this line doesn't work if I replace array with numLat which is an NSNumber - unlike what many people have said in various discussions here
OR - for the saving to file portion (last two lines):
NSString *path = #"./location.txt";
[NSKeyedArchiver archiveRootObject:array toFile:path];
// Get the path to the Documents (this is where your app saves data)
NSArray *searchPaths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
NSString* documentsPath = [searchPaths objectAtIndex: 0];
[array writeToFile:[documentsPath stringByAppendingPathComponent:#"location"] atomically:YES];
To load the data back into the array, use
NSArray *searchPaths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
NSString* documentsPath = [searchPaths objectAtIndex: 0];
array = [[NSMutableArray alloc] initWithContentsOfFile:[documentsPath stringByAppendingPathComponent:#"location"];
i am using following code to log into a file...
NSData *dataToWrite = [[NSString stringWithString:#"log data"] dataUsingEncoding:NSUTF8StringEncoding];
NSString *docsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *path = [docsDirectory stringByAppendingPathComponent:#"fileName.txt"];
[dataToWrite writeToFile:path atomically:YES];
But when this method gets called again...it doest show the last entry...??
Could anyone suggest?
thanks
It is better you try using NSFileHandle , because the write operation to a file on NSData simply a convenience function and can not do a full fledged file operations like appending.
How can I remove last line in a file in iOS.
Below is the code that let's me go to the end of file but then I don't know how to remove that last line.
NSArray *paths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
//make a file name to write the data to using the documents directory:
NSString *file = [NSString stringWithFormat:#"%#/%#.daa", documentsDirectory, MFILE_NAME];
NSFileHandle *aFileHandle = [NSFileHandle fileHandleForWritingAtPath:file];
//setting aFileHandle to write at the end of the file
[aFileHandle truncateFileAtOffset:[aFileHandle seekToEndOfFile]];
Thanks for your help.
Ok, after some documentation reading this is what I ended up with:
NSArray *paths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *file = [NSString stringWithFormat:#"%#/%#.txt", documentsDirectory, #"file_name"];
NSData *orgData = [NSData dataWithContentsOfFile:file];
//Because there is only one char on my last line I make a range from 0 to length of data - 1 byte.
NSRange range = {0, [orgData length]-1};
NSData* shortData = [[NSData dataWithContentsOfFile:file] subdataWithRange:range];
[shortData writeToFile:file atomically:YES];
If you know a better way please let me know.
Pretty sure that this can be your solution:
NSFileHandle *file;
file = [NSFileHandle fileHandleForUpdatingAtPath:[self filePath]];
if (file == nil)
NSLog(#"Failed to open file");
//get the last character count
long long lastChar = [file seekToEndOfFile];
lastChar--;
lastChar--;
//from where do you want to remove
NSLog (#"Offset = %llu", lastChar);
//Move to position
[file seekToFileOffset: lastChar];
//write an empty string
[file writeData:[#" " dataUsingEncoding:NSUTF8StringEncoding]];
[file closeFile];
This is possibly okay, depending on the file.
Removing one character doesn't address thing like a trailing carriage return, so this may not actually work in practice. A better (more general) solution would be to load the file, and step backwards from the last character until you find the beginning of the last line (i.e. everything between the next-to-last carriage return and the final one), and then rewrite the file without the final line.
As a practice, I am trying to write an app similar to the built-in notes app.
But I cannot figure out how to save the file and display it in a UITableView.
Right now, I have a UITextView that the user can type in. I also have a save button.
When the user taps the save button, I want to save it, and later have it displayed in a table view.
I am very lost so if you know of any relevant tutorials etc. it would be greatly appreciated.
As noted by the commenters in the real world, you're definitely going to want to look at Core Data or some other data persistence strategy. If you're dead set on pursuing this as a learning experience, something like this should solve your problem:
- (void)writeStringToFile:(NSString*)aString {
// Build the path, and create if needed.
NSString* filePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString* fileName = #"myTextFile.txt";
NSString* fileAtPath = [filePath stringByAppendingPathComponent:fileName];
if (![[NSFileManager defaultManager] fileExistsAtPath:fileAtPath]) {
[[NSFileManager defaultManager] createFileAtPath:fileAtPath contents:nil attributes:nil];
}
// The main act...
[[aString dataUsingEncoding:NSUTF8StringEncoding] writeToFile:fileAtPath atomically:NO];
}
- (NSString*)readStringFromFile {
// Build the path...
NSString* filePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString* fileName = #"myTextFile.txt";
NSString* fileAtPath = [filePath stringByAppendingPathComponent:fileName];
// The main act...
return [[[NSString alloc] initWithData:[NSData dataWithContentsOfFile:fileAtPath] encoding:NSUTF8StringEncoding] autorelease];
}
The easiest way to save text is using NSUserDefaults.
[[NSUserDefaults standardUserDefaults] setObject:theText forKey:#"SavedTextKey"];
or, if you want to have the user name each "file" or be able to have multiple files
NSMutableDictionary *saveTextDict = [[[[NSUserDefaults standardUserDefaults] objectForKey:#"SavedTextKey"] mutableCopy] autorelease];
if (saveTextDict == nil) {
saveTextDict = [NSMutableDictionary dictionary];
}
[saveTextDict setObject:theText forKey:fileName];
[[NSUserDefaults standardUserDefaults] setObject:saveTextDict forKey:#SavedTextKey"];
I am using the following code to open a file's contents and save it to another file.
when it runs the original file length is 793 but the saved file is 0. I have also tried just to copy the file. Nothing seems to work.
Is there some kind of permissions I'm missing on the documents directory?
NSError *error;
NSString *basePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString* nGram = [basePath stringByAppendingPathComponent:#"contacts.gram"];
NSString *oGram = [basePath stringByAppendingPathComponent:#"/../vText.app/model/lm/TAR9230/contacts.gram"];
NSString *gramString = [[NSString alloc] initWithContentsOfFile:oGram encoding:NSUTF8StringEncoding error:&error];
BOOL ok = [gramString writeToFile:nGram atomically:NO encoding:NSUnicodeStringEncoding error:&error];
if(!ok) NSLog(#"Mayday!");
NSLog(#"%d",[gramString length]);
gramString = [[NSString alloc] initWithContentsOfFile:nGram encoding:NSUTF8StringEncoding error:&error];
NSLog(#"%d",[gramString length]);
This entire block is unnecessary. All you need is:
NSString *fp=[[NSBundle mainBundle] pathForResource:#"contacts" ofType:#"gram"];
NSString *gramString = [[NSString alloc] initWithContentsOfFile:fp
encoding:NSUTF8StringEncoding
error:&error];
You certainly don't want to try to directly access a file in the app bundle using a hardcoded path because the file isn't guaranteed to be in the same exact place in every build.
In the code you do have, you want to use the same encoding constant for reading as you did for writing. You write with NSUnicodeStringEncoding but you read with NSUTF8StringEncoding. These should overlap but why take the chance if you know the exact coding used?