Writing variables and strings to a text file (objective-c) - objective-c

I was surfing on the Net a lot, but still I haven't found an answer to my question: how to write variables to a .txt file and what's the best way to write NSStrings to .txt files. I've tried using writeToFile method, but if I have two calls of this method, then the text that was written when the first one was called will be overwritten. I want to have a kind of history of what has happened, and values of some variables in my .txt file. How should I do it?

If you just want to append a string to a .txt file, you could do this:
NSString *string = ...; // your string
NSString *path = ...; // path to your .txt file
// Open output file in append mode:
NSOutputStream *stream = [[NSOutputStream alloc] initToFileAtPath:path append:YES];
[stream open];
// Make NSData object from string:
NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
// Write data to output file:
[stream write:data.bytes maxLength:data.length]; // XXX
[stream close];
Remark: If this is in an .mm file and therefore compiled as Objective-C++, then the second to last line (marked with XXX) must be replaced by
[stream write:static_cast<const uint8_t *>(data.bytes) maxLength:data.length];
because C++ requires an explicit cast from const void * to const uint8_t *.

Related

Is there any way to know why NSHFSTypeOfFile fails?

I am having the following code to check the file type of a file in mac:
OSType GetFileTypeFromPath( const std::string & inFilePath )
{
NSString * pathToFile = [[NSString alloc] initWithBytes:inFilePath.data()
length:inFilePath.size() * sizeof(char)
encoding:NSUTF8StringEncoding];
NSString *fileType = NSHFSTypeOfFile( pathToFile );
return NSHFSTypeCodeFromFileType( fileType );;
}
I found the function, 'NSHFSTypeOfFile', in https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Miscellaneous/Foundation_Functions/Reference/reference.html#//apple_ref/c/func/NSFileTypeForHFSTypeCode
The functions returns me the result for some file. I am interested in pdf files alone. For some pdf files it works fine but for others the string returned by the function in nil. I don't know whether it is anything wrong with the file or the filepath I am providing (like encoding. Is there any way to get the reason for the function NSHFSTypeOfFile to fail?

Parsing a binary MOBI file: best approach?

It contains METADATA in between binary data. I'm able to parse the first line with the title Agent_of_Chang2e, but I need to get the metadata on the bottom of the header as well. I know there are not standard specifics for it.
This code isn't able to decode the bottom lines. For example I get the following wrong formatted text:
FÃHANGE</b1èrX)¯­ÌiadenÕniverse<sup><smalÀ|®¿8</¡Îovelÿ·?=SharonÌeeándÓteveÍiller8PblockquoteßßÚ>TIa÷orkyfiction.Áll#eãacÐ0hðortrayedén{n)áreïrzus0¢°usly.Ôhatíean0authhmxétlõp.7N_\
©ß© 1988âyÓOOKãsòeserved.0ðart)publicaZmayâehproduc
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
char buffer[1024];
FILE* file = fopen([path UTF8String], "r");
if (file != 0)
{
while(fgets(buffer, 1024, file) != NULL)
{
NSString* string = [[NSString alloc] initWithCString: buffer encoding:NSASCIIStringEncoding];
NSLog(#"%#",string);
[string release];
}
fclose(file);
}
[pool drain];
nielsbot already posted a link to the format specification.
As you can read there, the file is not text file, but binary encoded. Parsing it with NSString instances is no good idea.
You have to read the file binary, i. e. using NSData:
NSData content = [NSData dataWithContentsOfFile:path];
Then you have to take out the relevant information by yourself. For example, if you want to read the uncompressed text length, you will find in the linked document that this information starts at position 4 and has a length of 4.
int32_t uncompressedTextLength; // 4 bytes are 32 bit.
[content getBytes:&uncompressedLenght range:NSMakeRange(4, 4)];
Maybe you have to deal with endianess.
Use NSTask or system() to pass the file through the strings utility and parse the output of that:
strings /bin/bash | more
...
...
677778899999999999999999999999999999:::;;<<====>>>>>>>>>>>????????
#(#)PROGRAM:bash PROJECT:bash-92
...
...
First, I am pretty sure the texts will be UTF-8 or UTF-16 encoded.
Second, you cannot just take random 1024 bytes and expect them to work as a text. What about byte order (big endian vs little endian)?

Reading text file as a floating number in Objective-C

I have a text file with a single floating number in it that needs to be opened and read as a floating value so I can use it in my equations. I have successfully read in the text file as a string and checked it in UITextView to make sure the file was in the correct path etc. Below is how I am reading the file and I have tried using an NSScanner to read the number as a float but cannot get it to work.
NSString *filePath2 = [[NSBundle mainBundle] pathForResource: #"time" ofType: #"txt"];
NSString *textFromFile = [NSString stringWithContentsOfFile:filePath];
// i know the above won't work because it reads the file as a string
Use
[textFromFile doubleValue];

Create file with fixed size in Cocoa

My MAC app need create file that has fixed size. Example : I want to create file has name : test.txt, fixed size : 1069 bytes. How can i do that? I use below code to write file :
NSError *err;
NSString* arrayText = [writeArray componentsJoinedByString: #"\n"];
[filemgr createFileAtPath:[NSString stringWithFormat:#"%#/test.txt",sd_url] contents:nil attributes:nil];
[arrayText writeToFile:[NSString stringWithFormat:#"%#/test.txt",sd_url] atomically:YES encoding:NSUTF8StringEncoding error:&err];
Thanks
This function will write some junk data to file.
+(BOOL)writeToFile:(NSString *)path withSize:(size_t)bytes;
{
FILE *file = fopen([path UTF8String], "wb");
if(file == NULL)
return NO;
void *data = malloc(bytes); // check for NULL!
if (data==NULL) {
return NO;
}
fwrite(data, 1, bytes, file);
fclose(file);
return YES;
}
If you dont want to use fwrite
+(BOOL)writeToFile:(NSString *)path withSize:(size_t)bytes;
{
void *data = malloc(bytes); // check for NULL!
if (data==NULL) {
return NO;
}
NSData *ldata = [NSData dataWithBytes:data length:bytes];
[ldata writeToFile:path atomically:NO];
return YES;
}
In order for the file to contain a certain number of bytes, you must write that many bytes to the file. There's no way to make a file's size be something other than the number of bytes it contains.
You can use FSAllocateFork (or fcntl with F_PREALLOCATE) to reserve space to write into. You'd use this, for example, if you were implementing your own download logic (if, for some reason, NSURLDownload wasn't good enough) and wanted to (a) make sure enough space is available for the file you're downloading and (b) grab it before something else does.
But, even that doesn't actually change the size of the file, just ensures (if successful) that your writes will not fail for insufficient space.
The only way to truly grow a file is to write to it.
The best way to do that is to use either -[NSData writeToURL:options:error:], which is the easy way if you have the data all ready at once, or NSFileHandle, which will enable you to write the data in chunks rather than having to build it all up in memory first.

Why does this NSString created from an NSData object fail to show it has contents?

Why does the following code produce the logging at the bottom ?
Here is the anomaly- my second NSLog should print the chrStr but produces nothing, empty, which is verified by this debug command:
(gdb) po chrStr
object returns empty description
However, the third NSString where I re-convert the NSString back to NSData object DOES display the the data, the same value as in the first NSLog, as it should. This would indicate to me that chrStr must have actual contents. But it seems not to be so from the NSLOG or the po command. Why ?
NSString *login;
NSString *pass;
// Purpose: NSString *loginString = [NSString stringWithFormat:#"\000%#\000%#", login, pass];
login = #"Loginname"; // text string1
pass = #"Password"; // text string2
// convert text strings to data objects
NSData *subData1 = [login dataUsingEncoding:NSUTF8StringEncoding];
NSData *subData2 = [pass dataUsingEncoding:NSUTF8StringEncoding];
// embed a NULL into new NSData object
NSMutableData *data = [NSMutableData data];
unsigned char zeroByte = 0;
[data appendBytes:&zeroByte length:1];
// append string1, NULL, string2 to data object
[data appendData:subData1];
[data appendBytes:&zeroByte length:1];
[data appendData:subData2];
NSLog(#"1.NSData: %#", data); // print data object
// create a character string from data object
NSString *chrStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"2.NSString: %#", chrStr); // print character string
// create data object from string object
NSData *chrData = [chrStr dataUsingEncoding:NSUTF8StringEncoding];
NSLog(#"3.NSDATA: %#", chrData); // print data object
Produces:
[1071:207] 1.NSData: 004c6f67 696e6e61 6d650050 61737377 6f7264
[1071:207] 2.NSString:
[1071:207] 3.NSDATA: 004c6f67 696e6e61 6d650050 61737377 6f7264
This is a real mystery to me. If chrStr is empty then 3-NSDATA could not display its info, but it does !
What am I trying to accomplish ? Well, check my very first comment line: // purpose:
That line when uncommented produces a warning, even though it actually works, so I was trying to do it another way that allowed me to have a clean compile. If you see a better way to accomplish that objective, I all eyes and ears. But please don't dwell on why that #"\000%#\000%#" string is necessary, start out accepting that it is. Thanks.
In C (and therefore objective-c), a null byte is used to represent the end of a string. When you create the string object, it takes all of the data you have given it without parsing, which is why you can convert it back to data successfully. However, when you display the string, the system reads the string up to the first null byte, which is the first byte. Therefore, the string contains data, but any system functions which read byte by byte instead of using the strings returned length will think it is empty. When you work with non-displayable characters, you should try to use data objects over string objects as often as possible.