Creating tab delimited file in objective-c - iphone

I found this snippet online to write, and then append data to a text file:
- (void)appendText:(NSString *)text toFile:(NSString *)filePath {
// NSFileHandle won't create the file for us, so we need to check to make sure it exists
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:filePath]) {
// the file doesn't exist yet, so we can just write out the text using the
// NSString convenience method
NSError *error = noErr;
BOOL success = [text writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:&error];
if (!success) {
// handle the error
NSLog(#"%#", error);
}
}
else {
// the file already exists, so we should append the text to the end
// get a handle to the file
NSFileHandle *fileHandle = [NSFileHandle fileHandleForWritingAtPath:filePath];
// move to the end of the file
[fileHandle seekToEndOfFile];
// convert the string to an NSData object
NSData *textData = [text dataUsingEncoding:NSUTF8StringEncoding];
// write the data to the end of the file
[fileHandle writeData:textData];
// clean up
[fileHandle closeFile];
}
}
This makes sense to me. I have a class that has 3 properties, of NSString, NSInteger, and NSString. When I try to use this method, I do this:
for (MyObject *ref in array) {
NSString *stringToFile = [NSString stringWithFormat:#"%#\t%i\t%#", ref.ChrID, ref.Position, ref.Sequence];
[self appendText:stringToFile toFile:filePath];
}
It doesn't look quite right. My data looks like this:
NSString *tab* NSInteger *single space* NSStringNSString *tab* NSInteger newline
NSStringNSString *tab* NSInteger newline
NSStringNSString *tab* NSInteger newline
NSStringNSString *tab* NSInteger newline
NSStringNSString *tab* NSInteger newline
NSStringNSString *tab* NSInteger newline
NSStringNSString *tab* NSInteger newline
NSStringNSString *tab* NSInteger newline
...
I'm not sure what is going on to make it look like this. When I NSLog the data, it looks fine. But something with the first line gets messed up, and then everything seems to be off. Any thoughts? Thanks.

There are several issues with the method appendText:
if the file does not exist, the first line is written with the NSString writeToFile method without the \n
following lines are written with the NSData writeData method
it's very inefficient to use a filemanager to check for existence, get a filehandle, seek to EOF and then write just one line, omitting the close too. And repeating this for every following line.
So better do it this way:
get the filehandle for writing, it will be created if it's not there yet
seek to EOF
do your loop with writeData for each line
close the file

Related

Delete a line of text in txt file iOS

Is it possible to delete a line of text that store in .txt file. I am currently successful to extract each line inside txt file and add into array then display each line in TableView. Now I if I want to delete particular line How do I do it?
Put the strings from your NSArray into a NSMutableArray, delete the line that you want deleted, convert to a single NSString by joining elements with #"\n" string, and then write the string to file, like this:
NSMutableArray *tmp = [myArray mutableCopy];
[tmp removeObjectAtIndex:indexToRemove];
NSString *tmpStr = [NSString componentsJoinedByString:#"\n"];
NSError *err = nil;
[tmpStr writeToFile:myFile
atomically:NO
encoding:NSUTF8StringEncoding // <== use an encoding that you need
error:&err];

Not able to edit first byte of file using NSFileHandle

In my app, I am using NSFileHandle to edit some file but it is not editing.
Below is the code: with comments & logs output
//Initialize file manager
NSFileManager *filemgr;
filemgr = [NSFileManager defaultManager];
//Initialize file handle
NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:filePath];
//Check if file is writable
if ([filemgr isWritableFileAtPath:filePath] == YES)
NSLog (#"File is writable");
else
NSLog (#"File is read only");
//Read 1st byte of file
NSData *decryptData = [fileHandle readDataOfLength:1];
//Print first byte & length
NSLog(#"data1: %d %#",[decryptData length],decryptData); //data2: 1 <37>
//Replace 1st byte
NSData *zeroData = 0;
[fileHandle writeData:zeroData];
//Read 1st byte to check
decryptData = [fileHandle readDataOfLength:1];
//Print first byte
NSLog(#"data2: %d %#",[decryptData length],decryptData); //data2: 1 <00>
NSURL *fileUrl=[NSURL fileURLWithPath:filePath];
NSLog(#"fileUrl:%#",fileUrl);
[fileHandle closeFile];
Any Suggestions?
If you want to write using NSFileHandle you need to open the file for writing as well as reading:
NSFileHandle *fileHandle = [NSFileHandle fileHandleForUpdatingAtPath:filePath];
If you aren't sure if the file at the specified path is writable, you should check for the appropriate permissions before you open it and display an error to the user if they are insufficient for what you need to do.
Also, to write data you need to create an instance of NSData. The line of code
NSData *zeroData = 0;
is creating a nil object, not an object containing a zero byte. I think you want
int8_t zero = 0;
NSData *zeroData = [NSData dataWithBytes:&zero length:1];

Can not read file in XCODE 4.2, worked in 4.0?

I have upgraded from XCODE 4 to 4.2 and now i have problems.
The following code worked pre 4.2 to read the file in "filePath":
// Fill myString with questions from the .txt file and then read .txt file
NSString *filePath = whatFile;
NSString *myString = [[NSString alloc] initWithContentsOfFile:filePath];
// Load array
NSArray* myArray = [myString componentsSeparatedByString:#"\r"];
NSLog (#"\n \n Number of elements in myArray = %i", [myArray count]);
With 4.2 the "initWithContentsOfFile" in the following code line is deprecated:
NSString *myString = [[NSString alloc] initWithContentsOfFile:filePath];
...and should be replaced with the below according to the manual:
NSString *myString = [NSString stringWithContentsOfFile:filePath encoding: NSUTF8StringEncoding error:&err];
and i can not get this to read the records in the same file by replacing the code line. BTW, i have defined the &err.
When i NSLog myString i get (null).
I am getting a bit desperate to solve this and would very much appreciate any help.
Cheers
NSLog the err variable if there is an error. Also NSLog filePath.
Perhaps the encoding is not UTF-8, are you sure about the encoding?
The best non-UTF-8 encoding bet is NSMacOSRomanStringEncoding which supports 8-bit characters.
Try :
NSError* error = nil;
NSStringEncoding encoding;
NSString *fileContent = [NSString stringWithContentsOfFile:filePath usedEncoding:&encoding error:&error];
If that does not works, try in your code : NSASCIIStringEncoding
The file probably doesn't contain a UTF8 encoded string. See apple's documentation, which has an example of reading a file where you do not know the encoding: Reading data with an unknown encoding
You need to use the [string|init]WithContentsOfFile:usedEncoding:error method, and if that fails there are a few more things you can try before finally presenting an error message to the user (for example, try reading it as an NSAttributedString).
For example, you could do this:
// Fill myString with questions from the .txt file and then read .txt file
NSString *filePath = whatFile;
NSStringEncoding encoding;
NSError *error;
NSString *myString = [[NSString alloc] initWithContentsOfFile:filePath usedEncoding:&encoding error:&error];
if (!myString) {
myString = [[NSString alloc] encoding:NSUTF8StringEncoding error:&error]
}
if (!myString) {
myString = [[NSString alloc] encoding:NSISOLatin1StringEncoding error:&error]
}
if (!myString) {
NSLog(#"error: %#", error);
return;
}
// Load array
NSArray* myArray = [myString componentsSeparatedByString:#"\r"];
NSLog (#"\n \n Number of elements in myArray = %i", [myArray count]);

read text file with delimiter nsstring

I have a text file like this
question1
question2
question3
I want to read only the first line into a nsstring
after that I want to mark the first line so the next time, skip the first line, but I don't know how to do it, I have this code for read but give me only the third line
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"qa" ofType:#"txt"];
NSString *myText = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
NSArray *lines = [myText componentsSeparatedByString:#"\n"];
for(myText in lines)
{
texview.text = myText;
}
}
Ok I try this code, Do not work, what I am Doing wrong?
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString * const kKey = #"OneTimeKey";
NSObject *keyValue = [defaults objectForKey:kKey];
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"qa" ofType:#"txt"];
NSString *myText = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
NSArray *lines = [myText componentsSeparatedByString:#"|"];
if (keyValue==nil) {
for(myText in lines)
{
preguntadia.text = myText;
[defaults setBool:YES forKey:kKey];
}
}
The problem is that your "for" is executed really fast, so fast that you can only see when the last element of the array is set to your text view.
What you can do is have a variable which specifies which one of the strings to show next and, with a timer, set a different string on your text view every number of seconds, so you can actually see the changes.
Bonus, you can make it cycle with something like this:
-(void)updateText{
[textView setText:[lines objectAtIndex:currentIndex]];
currentIndex++;
currentIndex = currentIndex % [lines count];
}
So when it reaches the last string, it shows the first again.
You'll need to store a line counter locally to keep track, I think. That is easily accomplished with something like this to save:
[[NSUserDefaults standardDefaults] setInteger:lineCount forKey:#"lineCountKey"];
and fetch:
int lineCount = [[NSUserDefaults standardDefaults] integerForKey:#"lineCountKey"];
and then just read and discard lineCount lines when you open the file.
Now, splitting the line you want into multiple pieces, you can use the NSString method componentsSeparatedByString:, but be careful. If your "questions" are actually multi-word questions, you'll need to pick a separator other than space. Vertical bar (|) might be a good choice, then you can do something like this:
NSArray *questions = [line componentsSeparatedByString:#"|"];
NB: Code typed from memory; not compiled. :-)

Problem writing string to a file ...(iPhone SDK )

I want to grab all URL's accessed in webview and write them to a text file.I don't want to use writeToFile coz in -(BOOL)webView method it would overwrite instead of appending to file. I can create file but all it writes to that file is string I used to create the file using FileManager createFileAtPath with Content ...
Also in the -(BOOL) webView method... when I tried to see if the file is read-only or writable ( isWritableFileAtPath ) it gives read-only.
POSIX Permissions in viewDidLoad -> 511 ...
checked file attributes in terminal going to that location its -rwxrwxrwx
I am new to Stack Overflow don't know how to post code here so using pastebin...http://pastebin.com/Tx7CsXVB
- (void)viewDidLoad {
[super viewDidLoad];
[myBrowser loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.apple.com"]]]; // UIWebView *myBrowser; is an instance variable
NSFileManager *fileMgr=[NSFileManager defaultManager];
NSDictionary* fileAttrs = [NSDictionary dictionaryWithObject:[NSNumber numberWithInteger:777] forKey:NSFilePosixPermissions]; /*for setting attribute to rwx for all users */
NSDictionary *attribs; // To read attributes after writing something to file
NSString *aPath = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents/file1.txt"];
myBrowser.delegate = self; // UIWebView delegate Self
// if the File Doesn't exist create one
if([fileMgr fileExistsAtPath:aPath])
{
NSLog(#"File Exists at this Location");
}
else
{
NSString *someString = #"This is start of file";
NSData *startString =[someString dataUsingEncoding: NSASCIIStringEncoding];
[fileMgr createFileAtPath:aPath contents:startString attributes: fileAttrs]; // earlier attributes was nil changed to fileAttrs
}
NSLog(#"aPath is %#",aPath);
attribs = [fileMgr attributesOfItemAtPath:aPath error: NULL];
NSLog (#"Created on %#", [attribs objectForKey: NSFileCreationDate]);
NSLog (#"File type %#", [attribs objectForKey: NSFileType]);
NSLog (#"POSIX Permissions %#", [attribs objectForKey: NSFilePosixPermissions]);
}
//UIWebView delegate calls this method every time user touches any embedded URL's in the current WebPage. I want to grab all the URL's accessed and write them to file.
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
NSFileManager *fileManager =[NSFileManager defaultmanager];
NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents/file1.txt"];
fileHandle = [NSFileHandle fileHandleForWritingAtPath:path];
[fileHandle seekToEndOfFile]; // Moved up next to fileHandleForWritingAtPath since the above would place pointer to start of file again so setting handle to seek to End of File
/* section of code to check if the file at that path is writable or not */
if ([fileManager isWritableFileAtPath:path] == YES)
NSLog (#"File is writable");
else
NSLog (#"File is read only");
/* section of code to check if the file at that path is writable or not ENDS*/
NSURL *url = request.URL;
NSString *currenturl = url.absoluteString;
NSString *currentURL = [NSString stringWithFormat:#"%#\n",currenturl];
NSString *str =[NSString stringWithFormat:#"%#",currentURL];/* has already been set up */
[fileHandle writeData:[str dataUsingEncoding:NSUTF8StringEncoding]];
// testing if string has been written to file by reading it...
NSData *dataBuffer = [fileMgr contentsAtPath:path];
NSString *some;
some = [[NSString alloc] initWithData:dataBuffer encoding:NSASCIIStringEncoding];
NSLog(#"SOme String is: %#",some);
[fileHandle closeFile];
}
I think your issue may be that you're testing Documents/file1.txt and not /Documents/file1.txt
The leading '/' is important
[edit]
May I make a suggestion? Distill this down to what works first and then figure out what makes it fail?
I would recommend using the following form and continuing from there:
if ([fileManager isWritableFileAtPath: #"/Documents/file1.txt"] == YES)
NSLog (#"File is writable");
else
NSLog (#"File is read only");
[/edit]