I'm trying to seek 1,000 bytes into a file handle and write it to an instance of NSData (or NSMutableData).
What am I doing wrong here?
int offset = 1000;
NSFileHandle *fHandle;
NSMutableData *data;
fHandle = [NSFileHandle fileHandleForReadingAtPath:#"bigtextfile.txt"];
[fHandle seekToFileOffset:offset];
data = [NSMutableData data];
[fHandle writeData:data];
[fHandle closeFile];
[data length]; // this comes out to 0 bytes?
I am not sure you trying to read data after seeking or want to write some thing there? -- you are opening file for reading then you are trying to write empty data.
If you want to read then using following line or similar API's not write
data = [fHandle availableData];
If you want to write then open the file for writing -- then have some content in NSData object and write it to the file.
write it to an instance of NSData
That's the basic problem right there. NSFileHandle's -writeData: method doesn't write to an instance of NSData. It writes from a data object to a file. So your code creates an empty data object, then tries to write it to a read-only file handle. It's not actually doing anything that would change the contents of the data object at all.
To read data from the file, you want to use either -readDataToEndOfFile, or -readDataOfLength:.
Related
I'm using [str writeToFile:path atomically encoding error]
to write in file. It works successfully for NSString but doesn't work for NSDate/NSData.
Please tell me how to write in file.
Simple, cheater solution: put it inside a structure that does support writing to a file.
NSDate* variable = ...;
[#[ variable ] writeToFile:path atomically:YES];
That's to say, put it inside an array or dictionary.
If you want to output it to a text file (as you title suggests but you don't mention in the question), you need to convert the date into a string first. Use NSDateFormatter.
Without knowing what's inside your NSData it's not really possible to say how to output to a text file. Maybe convert to base 64 first?
What's the reason that I can't parse a base64 string from a JSON request? when I make it a small string it works.
To clarify a little:
else if([connection isEqual:self.appearanceConnection]){
NSArray *arrayOfAppearances = [NSJSONSerialization JSONObjectWithData:[[[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding] dataUsingEncoding:NSUTF8StringEncoding]options:NSJSONReadingAllowFragments error:&error];
NSLog(#"het aantal appearances is: %i", arrayOfAppearances.count);
[self syncAppearances:arrayOfAppearances];
}
When I edit it to a small string, I get the response that the length of the received array is 1. If I change it again to the base 64 of the image, the length is 0.
http://cl.ly/image/470Z0X1P3K1b (image form JSON response)
The error I get on the String:
Updated answer:
You now inform us that JSONObjectWithData is reporting an error:
Unterminated string around character 62
Character 62 is the start of the logo. I'm not seeing the end of the JSON in any of your screen snapshots. It looks like it's getting cut off.
You haven't shown us how you are populating data, but it looks almost like you're using a NSURLConnection but trying to parse in didReceiveData as opposed to waiting for the full results and only invoking the the JSON parse in connectionDidFinishLoading. NSURLConnection will break a long response into several calls to didReceiveData and you have to append all of those NSData to a single NSMutableData, and only try to parse it when it's done retrieving everything.
You either need to (a) show us the code where you're loading data and/or (b) share the full JSON. Either your JSON isn't properly terminated or you're trying to parse it before the whole thing is downloaded (probably the latter).
Original answer:
I'm not sure if this is the problem, but your line that says:
NSArray *arrayOfAppearances = [NSJSONSerialization JSONObjectWithData:[[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] dataUsingEncoding:NSUTF8StringEncoding]options:NSJSONReadingAllowFragments error:&error];
should simply be:
NSArray *arrayOfAppearances = [NSJSONSerialization JSONObjectWithData:data
options:0
error:&error];
The JSONObjectWithData method takes a NSData, not a NSString.
And, if you're not getting anything returned from this method, you should examine the contents of error and see what it says.
If you're still unable to figure out what the problem is, perhaps you can share the full JSON response with us (give us a URL or upload it somewhere) and we can take a look at it.
With a big thanks to #Rob!
Here a little summary:
Create a variable NSMutableData (don't forget to initialise in the viewdidload)
In the didReceiveData, you append the data to your mutable data using [self.appearancedata appendData:data];
In the connectionDidFinishLoading you parse your JSON
Looking for some advice with an iOS application.
Essentially what my app does is generate a CSV file that logs certain events within a period of time. So users can press a button and an entry will be added to the log saying "Event of type X happened at Time T"
The way I'm doing this is by maintaining an NSMutableArray which stores NSStrings. Each event adds a string to the NSMutableArray.
When the user is done with a session, they can "export" the file. I'm using the NSMutableArray's writeToFile; then I use an e-mail interface to send that file as a CSV to a target e-mail.
It all works, except the CSV file that is generated has some meta-data in it. Specifically, I believe at the top of the file I see and at the beginning of each row of cells when opened in excel.
Is this something inherent in the data structure (NSMutableArray) or data type (NSString) that I am using? Is there a way for me to just get the raw data?
I can upload code if need be (I'm not near the work computer now though, so I'm testing the waters to see if there is something simple I can do to stop seeing this meta-data).
Thank you!
CSV is a very simple format. You can separate the strings with semi-colons and then write everything to a file using NSOutputStream.
This code assumes you already have a string array with CSV rows:
NSOutputStream* csvoutput = [NSOutputStream outputStreamToFileAtPath:filepath append:NO];
[csvoutput open];
for (NSString* str in array) {
NSString* tempStr = [str stringByAppendingString:#"\n"]; //new line
NSData *strData = [tempStr dataUsingEncoding:NSUTF8StringEncoding];
[csvoutput write:(uint8_t *)[strData bytes] maxLength:[strData length]];
}
[csvoutput close];
You better create a model class (Event) and fill the array with Event-instances instead of strings. Thats cleaner and more efficient. Then you would create the CSV-strings when exporting to a file.
Basically, I am searching through a list of foods. The fields I am using in the .csv file are: the name of the food, the type of the food represented by a number (type of food would be meat, vegetable, fruit, etc). I want to go through the .csv file line by line, and if the type of food is say a fruit (represented by the number 1), then I want to save that entire line in a new file. I want to go through the ENTIRE list of foods and save each to the new file. How could I go about doing this in objective c? My idea was to search the string for a substring (in this case, the number 1) and if it contains the substring, then I want to save the entire line in a new file, called fruit. I understand this in theory, but am having trouble understanding how to parse a .csv file in this way.
NJones is right - CSV files suck and you don't see them often in Objective-C, so try to avoid them.
However, you can load a CSV file with the following code:
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"food" ofType:#"csv"];
NSString *fileContents = [[NSString alloc] initWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:&error];
If you have the contents of a CSV stored in memory, either from a file on disk or from a web service, you can turn it into an array of line records:
NSArray *lines = [fileContents componentsSeparatedByString:#"\n"];
The first line in a CSV file is typically you're header, but after removing it (or ignoring it), it's simply a matter of enumerating over the remaining lines.
for (NSString *record in lines) {
NSArray *values = [record componentsSeparatedByString:#","];
//values is now an array of the contents of the CSV file. Do stuff with it.
}
This code assumes a lot about the CSV file structure, such as the fact that there are no commas in your food names, etc. In general, avoid CSV files whenever possible. Take a look into persisting data on disk as JSON or, better yet, as a Core Data store.
-(BOOL)readFromURL:(NSURL *)absoluteURL ofType:(NSString )typeName error:(NSError *)outError
{
NSString *fileString = [NSString stringWithContentsOfURL:absoluteURL
encoding:NSUTF8StringEncoding error:outError];
NSLog(#"------- file string ----- %#",fileString);
if ( nil == fileString )
return NO;
NSArray* allLinedStrings =
[fileString componentsSeparatedByCharactersInSet:
[NSCharacterSet newlineCharacterSet]];
NSLog(#"------- file string ----- %#",allLinedStrings);
// write your code how you want display
}
If your csv file is fairly simple with a well defined format, you may have the best luck with your own code based upon the suggestion from #Ash Furrow.
If you are facing a more complicated import, you may find the tutorial and CSV parsing class created by Matt Gallagher to be very helpful. He did a really nice job creating a nice way to deal with CSV files. You can check it out here: http://cocoawithlove.com/2009/11/writing-parser-using-nsscanner-csv.htmlhttp://cocoawithlove.com/2009/11/writing-parser-using-nsscanner-csv.html
I want to read a list of integers from a text file, I just want to write code like
int temp;
fin>>temp;
But when I read the Cocoa documentation, I found NSFileHandle is suggested, and there is no method like I assumed, only one related method:
- (NSData *)readDataOfLength:(NSUInteger)length
Is there any class/method can help me do this in Objective C? Thanks.
I want to read a list of integers from a text file, I just want to
write code like
int temp; fin>>temp;
You have a lot of choices for file access. If you want to use C++-style access, you can, but you naturally need to open the file using the appropriate C++ file or stream methods. If you use Objective-C++, though, you can easily mix C++ code into your Objective-C.
You can also use the C standard library file routines like fopen(), fread(), etc.
Using C or C++ to read files is often a good choice if the files are coming from a source other than your program, something beyond your control.
But when I read Cocoa document, I found NSFileHandle is suggested, and
there is no method like I assumed, only one related method:
Again, lots of choices. Yes, you can use NSFileHandle to read bytes from the file into a NSData object, and then you can get ranges of bytes out of the data object. A much more common way to write and read data, though, is to use NSKeyedArchiver and NSKeyedUnarchiver:
NSData *data = [NSData dataWithContentsOfFile:pathToFile];
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
int age = [unarchiver decodeIntForKey:#"Age"];
int weight = [unarchiver decodeIntForKey:#"Weight"];
NSString *name = [unarchiver decodeObjectForKey:#"Name"];
That's just the tip of the iceberg, though. It seems like a lot of code compared to what you were looking for, but it can also be a lot less work. Because objects and their relationships can be stored and read, you can read in a complex graph of objects with very little code:
OrgChart *chart = [NSUnarchiver unarchiveObjectWithFile:pathToFile];
Another option is to use property lists, which are very easy to use, but limited in the data types that can be used.
If you want to learn more about these topics, read Archives and Serializations Programming Guide, Property List Programming Guide, and File System Programming Guide.
You could use Objective-C++ and iostreams as you're used to.
You could use the C I/O functions like fopen and fscanf. (Probably what I'd do.)
Apple provides NSScanner for parsing, but it only reads from a string, not from an input stream. If you really want to use it, first you'll have to read your whole file (or a large chunk) into an NSString (or an NSData and then convert that to NSString).
If you can require the text file to be in JSON format, you can read it in one gulp and use NSJSONSerialization to parse it.