Open file and read from file Objective-c - objective-c

I'm trying to open a file, and read from it.. but I'm having some issues.
FILE *libFile = fopen("/Users/pineapple/Desktop/finalproj/test242.txt","r");
char wah[200];
fgets(wah, 200, libFile);
printf("%s test\n", wah);
this prints: \377\376N test rather than any of the contents of my file.
any idea why?
complete code:
#import <Cocoa/Cocoa.h>
#import <stdio.h>
int main(int argc, char *argv[])
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
FILE *libFile = fopen("/Users/pineapple/Desktop/finalproj/test242.txt","r");
if(libFile){
char wah[200];
fgets(wah, 200, libFile);
printf("%s test\n", wah);
}
[pool drain];
return 0;
}
And the test242.txt doesn't contain more than 200 chars.

If this is for Objective-C, why not do something like:
use NSFileHandle:
NSString * path = #"/Users/pineapple/Desktop/finalproj/test242.txt";
NSFileHandle * fileHandle = [NSFileHandle fileHandleForReadingAtPath:path];
NSData * buffer = nil;
while ((buffer = [fileHandle readDataOfLength:1024])) {
//do something with the buffer
}
or use NSString:
NSString * fileContents = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
or if you need to read it line-by-line:
How to read data from NSFileHandle line by line?
IMO, there's no need to drop down to the C-level fileIO functions unless you have a very very very good reason for doing so (ie, open a file using O_SHLOCK or something)

Your file is stored in UTF-16 (Unicode). The first character in your file is "L", which is code point 0x4C. The first 4 bytes of your file are FF FE 4C 00, which are a byte-order mark (BOM) and the letter L encoded in UTF-16 as two bytes.
fgets is not Unicode-aware, so it's looking for the newline character '\n', which is the byte 0x0A. Most likely this will happen on the first byte of a Unicode newline (the two bytes 0A 00), but it could also happen on plenty of other non-newline characters such as U+010A (LATIN CAPITAL LETTER A WITH DOT ABOVE) or anything in the Gurmukhi or Gujarati scripts (U+0A00 to U+0AFF).
In any case, though, the data that's ending up in the buffer wah has lots of embedded nulls and looks something like FF FE 4C 00 47 00 4F 00 4F 00 0A 00. NUL (0x00) is the C string terminator, so when you attempt to print this out using printf, it stops at the first null, and all you see is \377\376L. \377\376 is the octal representation of the bytes FF FE.
The fix for this is to convert your text file to a single-byte encoding such as ISO 8859-1 or UTF-8. Note that must single-byte encodings (UTF-8 excepted) cannot encode the full range of Unicode characters, so if you need Unicode, I strongly recommend using UTF-8. Alternatively, you can convert your program to be Unicode-aware, but then you can no longer use a lot of standard library functions (such as fgets and printf), and you need to use wchar_t everywhere in place of char.

If you don't mind reading all of a file you can do something like this:
NSData* myData = [NSData dataWithContentsOfFile:myFileWithPath];
and then do whatever you'd like with the data from there. You will get nil if the file doesn't exist.
If you are assuming text (string) data in this file you can additionally do something like this and then parse it as a NSString:
NSString* myString = [[NSString alloc] initWithBytes:[myData bytes] length:[myData length] encoding:NSUTF8StringEncoding];
Since you mentioned you are relatively new to objective-c you can search NSStrings fairly well. Have a look here for more info on this.

I wanted this as well and thought "do this instead" did not answer the question, here is a working example below. Beware that fgets reads the \n delimiter and appends to your text.
NSString * fName = [[NSBundle mainBundle] pathForResource:#"Sample" ofType:#"txt"];
FILE *fileHandle = fopen([fName UTF8String],"r");
char space[1024];
while (fgets(space, 1024, fileHandle) != NULL)
{
NSLog(#"space = %s", space);
}
fclose(fileHandle);

printf("%s test\n");
You're not passing the string to printf. Try
printf("%s test\n", wah);
Also, if your file contains a line more than 200 characters long, fgets will read 200 characters into wah - then add a NUL to the end, which will be off the end of wah (since you declared it to be 200 characters) and will trample over something random, and the behaviour of your program will be undefined and may set fire to your cat.

Slycrel's got it. Expanding on that answer, here is another (in my opinion, simpler) way of turning that data into a string:
NSString *myFileString = [[NSString alloc] initWithData:someData encoding:NSUTF8StringEncoding];
This declares a new NSString directly using the NSData specified.

Related

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)?

Weird error with NSString: No known class method for selector 'stringWithBytes:length:encoding:'

I am attempting to use scanf to assign a value to an NSString, as per the answers to this question by Omar. This is the code, taken straight from progrmr's answer:
char word[40];
int nChars = scanf("%39s", word); // read up to 39 chars (leave room for NUL)
NSString* word2 = [NSString stringWithBytes:word
length:nChars
encoding:NSUTF8StringEncoding];
However, I'm getting an error on the last line that makes absolutely no sense to me:
No known class method for selector 'stringWithBytes:length:encoding:'
What in the world could be causing this error?
And yes, I do have #import <Foundation/Foundation.h> at the top of the file.
NSString does not have a stringWithBytes:length:encoding: class method, but you can use
NSString* word2 = [[NSString alloc] initWithBytes:word
length:nChars
encoding:NSUTF8StringEncoding];
Note however, that scanf() returns the number of scanned items and
not the number of scanned characters. So nChars will contain 1 and not the string length, so you should set nChars = strlen(word) instead.
A simpler alternative is (as also mentioned in one answer to the linked question)
NSString* word2 = [NSString stringWithUTF8String:word];
NSString does not respond to the selector stringWithBytes:length:encoding:. You probably wanted initWithBytes:length:encoding:.
Story in short: you might want to consider a const char C-string suitable initializer for your NSString object. Also, allocate memory before sending any initializer message to the NSString object. I would expect something like:
char word[40];
int nChars = scanf("%39s", word);
NSString *word2 = [[NSString alloc] initWithCString:word encoding:NSASCIIStringEncoding];
Note that initWithCString per design only supports properly null '\0' terminated 8-bit character arrays. For unterminated bytes arrays you have initWithBytes:length:encoding: instead.
For Unicode characters you could consider initWithCharactersNoCopy:length:freeWhenDone:.

How to print unsigned char* in NSLog()

Title pretty much says everything.
would like to print (NOT in decimal), but in unsigned char value (HEX).
example
unsigned char data[6] = {70,AF,80,1A, 01,7E};
NSLog(#"?",data); //need this output : 70 AF 80 1A 01 7E
Any idea? Thanks in advance.
There is no format specifier for an char array. One option would be to create an NSData object from the array and then log the NSData object.
NSData *dataData = [NSData dataWithBytes:data length:sizeof(data)];
NSLog(#"data = %#", dataData);
Nothing in the standard libraries will do it, so you could write a small hex dump function, or you could use something else that prints non-ambigious full data. Something like:
char buf[1 + 3*dataLength];
strvisx(buf, data, dataLength, VIS_WHITE|VIS_HTTPSTYLE);
NSLog(#"data=%s", buf);
For smallish chunks of data you could try to make a NSData and use the debugDescription method. That is currently a hex dump, but nothing promises it will always be one.
To print char* in NSLog try the following:
char data[6] = {'H','E','L','L','0','\n'};
NSString *string = [[NSString alloc] initWithUTF8String:data];
NSLog(#"%#", string);
You will need to null terminate your string.
From Apple Documentation:
- (instancetype)initWithUTF8String:(const char *)nullTerminatedCString;
Returns an NSString object initialized by copying the characters from a given C array of UTF8-encoded bytes.

Objective-C: Reading contents of a file into an NSString object doesn't convert unicode

I have a file, which I'm reading into an NSString object using stringWithContentsOfFile. It contains Unicode for Japanese characters such as:
\u305b\u3044\u3075\u304f
which I believe is
せいふく
I would like my NSString object to store the string as the latter, but it is storing it as the former.
The thing I don't quite understand is that when I do this:
NSString *myString = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
It stores it as: \u305b\u3044\u3075\u304f.
But when I hardcode in the string:
NSString *myString = #"\u305b\u3044\u3075\u304f";
It correctly converts it and stores it as: せいふく
Does stringWIthContentsOfFile escape the Unicode in some way? Any help will be appreciated.
Thanks.
In the file \u305b\u3044\u3075\u304f are just normal characters. So you are getting them in string. You need to save actual Japanese characters in the file. That is, store せいふく in file and that will be loaded in the string.
You can try this, dont know how feasible it is..
NSArray *unicodeArray = [stringFromFile componentsSeparatedByString:#"\\u"];
NSMutableString *finalString = [[NSMutableString alloc] initWithString:#""];
for (NSString *unicodeString in unicodeArray) {
if (![unicodeString isEqualToString:#""]) {
unichar codeValue;
[[NSScanner scannerWithString:unicodeString] scanHexInt:&codeValue];
NSString* betaString = [NSString stringWithCharacters:&codeValue length:1];
[finalString appendString:betaString];
}
}
//finalString should have せいふく
Something like \u305b in an Objective-C string is in fact an instruction to the compiler to replace it with the actual UTF-8 byte sequence for that character. The method reading the file is not a compiler, and only reads the bytes it finds. So to get that character (officially called "code point"), your file must contain the actual UTF-8 byte sequence for that character, and not the symbolic representation \u305b.
It's a bit like \x43. This is, in your source code, four characters, but it is replaced by one byte with value 0x43. So if you write #"\x43" to a file, the file will not contain the four characters '\', 'x', '4', '3', it will contain the single character 'C' (which has ASCII value 0x43).

Using scanf with NSStrings

I want the user to input a string and then assign the input to an NSString. Right now my code looks like this:
NSString *word;
scanf("%s", &word);
The scanf function reads into a C string (actually an array of char), like this:
char word[40];
int nChars = scanf("%39s", word); // read up to 39 chars (leave room for NUL)
You can convert a char array into NSString like this:
NSString* word2 = [NSString stringWithBytes:word
length:nChars
encoding:NSUTF8StringEncoding];
However scanf only works with console (command line) programs. If you're trying to get input on a Mac or iOS device then scanf is not what you want to use to get user input.
scanf does not work with any object types. If you have a C string and want to create an NSString from it, use -[NSString initWithBytes:length:encoding:].
scanf does not work with NSString as scanf doesn’t work on objects. It works only on primitive datatypes such as:
int
float
BOOL
char
What to do?
Technically a string is made up of a sequence of individual characters. So to accept string input, you can read in the sequence of characters and convert it to a string.
use:
[NSString stringWithCString:cstring encoding:1];
Here is a working example:
NSLog(#"What is the first name?");
char cstring[40];
scanf("%s", cstring);
firstName = [NSString stringWithCString:cstring encoding:1];
Here’s an explanation of the above code, comment by comment:
You declare a variable called cstring to hold 40 characters.
You then tell scanf to expect a list of characters by using the %s format specifier.
Finally, you create an NSString object from the list of characters that were read in.
Run your project; if you enter a word and hit Enter, the program should print out the same word you typed. Just make sure the word is less than 40 characters; if you enter more, you might cause the program to crash — you are welcome to test that out yourself! :]
Taken from: RW.
This is how I'd do it:
char word [40];
scanf("%s",word);
NSString * userInput = [[NSString alloc] initWithCString: word encoding: NSUTF8StringEncoding];
yes, but sscanf does, and may be a good solution for complex NSString parsing.
Maybe this will work for you because it accepts string with spaces as well.
NSLog(#"Enter The Name Of State");
char name[20];
gets(name);
NSLog(#"%s",name);
Simple Solution is
char word[40];
scanf("%39s", word);
NSString* word2 = [NSString stringWithUTF8String:word];
The NSFileHandle class is an object-oriented wrapper for a file descriptor. For files, you can read, write, and seek within the file.
NSFileHandle *inputFile = [NSFileHandle fileHandleWithStandardInput];
NSData *inputData = [inputFile availableData];
NSString *word = [[NSString alloc]initWithData:inputData encoding:NSUTF8StringEncoding];