NSMutableArray Meta-Data when exported to CSV file - objective-c

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.

Related

how to write NSDate in text file

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?

NSPasteboard unable to read text when RTF data is copied to the pasteboard

I am using the NSPasteboard to read data off it and perform actions with the received data.
Specifically, I am interested in information of the types listed below in order of priority.
File path
Text data
Image data (this is not copying the image file, but actual parts of the image, for e.g. when you open an image in an editor, make a selection and press command+v)
This is what I have in code
_pasteBoard = [NSPasteboard generalPasteboard];
NSArray *types = [_pasteBoard types];
NSArray *files = [_pasteBoard propertyListForType: NSFilenamesPboardType];
NSString *text = [_pasteBoard propertyListForType: NSStringPboardType];
NSString *text2 = [_pasteBoard propertyListForType: NSPasteboardTypeString];
NSString *rtfText = [_pasteBoard propertyListForType: NSRTFPboardType];
NSData *imageData = [_pasteBoard dataForType: NSTIFFPboardType];
Right now, I am simply testing if I am able to get the required data or not. So When I select some files on the Destkop then files contains the selected file URLs. So that works.
Similarly when I select some parts of an image and copy it to the clipboard then imageData contains some data, which I then write to another file and can see that only the selected potion was copied, so that is OK too. Also, I understand that when I copy an image "file" to the clipboard then too imageData will not be nil, but that is ok because topmost priority goes to file URL and that is the case that will do what needs to be done.
The problem that I have run into is with the lines related to reading text from the pasteboard.
NSString *text = [_pasteBoard propertyListForType: NSStringPboardType];
NSString *text2 = [_pasteBoard propertyListForType: NSPasteboardTypeString];
NSString *rtfText = [_pasteBoard propertyListForType: NSRTFPboardType];
The Problem Descriptio:
I copied the URL of this page and both "text" and "text2" contain the string from the pasteboard. So it good here :)
I copy some lines from a .cs code file opened in TextEdit, the clipboard shows that I have "public.utf8-plain-text" and "NSStringPboardType" but "text" and "text2" are both nil;
From the same C#.NET .cs file, I select a single word, without any breaks for eg. "System.Threading", the clipboard shows that I have "public.utf8-plain-text" and "NSStringPboardType" and both "text" and "text2" have the copied text but any thing copied with spaces or lines will not. "myProject.Core.Helpers" will work but "namespace myProject.Core.Helpers" wont.
Similarly, I copy some text from a RTF file, the clipboard shows that I have a lot of RTF related information along with the same old "public.utf8-plain-text" and "NSStringPboardType" types too, but again "text", "text2" and, this time, "rtfText" are all nil.
So, how do I get the text that I need in all cases from the clipboard? I know that RTF data can contain a lot more then text but I am just concerned with getting the text out in a string file.
Any help will be greatly appreciated.
Thanks!
The problem is almost certainly that you're not accounting for multiple items on the pasteboard. In the old days (OS X 10.5 and earlier), there was only one item on the pasteboard. That item could have multiple types, which were just supposed to be representations of the same thing.
Now, the pasteboard can have multiple items. Each item can still have multiple types. The -types method returns a union of the types of all of the items. But -propertyListForType: will only examine the first item.
You could iterate over the array returned by -pasteboardItems and ask each for its types and then get the property list object for each type.
Or you could, for each type you're interested in, invoke -readObjectsForClasses:options: with a single-element array of the corresponding class. That wouldn't (and you generally shouldn't) distinguish among different plain text types. All of those would match NSString.
The most common approach, though, is to construct an array of all classes you can handle, in order of your app's preference (usually most expressive to least), and make a single call to -readObjectsForClasses:options:. Then process all objects returned. Each object will be for a single item on the pasteboard in the "best" available form.

access to different levels of a json file

how do I access the contents of group?
Currently, I can access bookmarks and blog.
I think the two characters after group generate problem of reading.
Here's code that selects the data from the json file to display data
NSDictionary *feed = [jsonObjects objectForKey:#"object"];
NSArray *entries = [feed objectForKey:#"bookmarks"];
for (NSDictionary *item in entries)
{
[item objectForKey:#"SomeDataIdentifierOfBookmarks"]
}
Here is the JSON file read by a NSMutableArray
EDIT REAL DATA JSON
{"object":
{"blog":[{"guid":181,"type":"object","subtype":"4","time_created":"","time_updated":"","container_guid":"180","owner_guid":"180","site_guid":"1","title":"ugyt","description":"scsa","url":"http://s210678217.onlinehome.fr/blog/view/181/ugg-sito-ufficiale-italiavyt"}],
"bookmarks":[{"guid":82,"type":"object","subtype":"9","time_created":"1372072736","time_updated":"1372072910","container_guid":"81","owner_guid":"33","site_guid":"1","title":"internet - ","description":"","url":"hr"},
{"guid":75,"type":"object","subtype":"9","time_created":"1371728924","time_updated":"1371728924","container_guid":"64","owner_guid":"52","site_guid":"1","title":" du ","description":"p>","url":"htts"},
{"guid":64,"type":"group","subtype":"0","time_created":"1371728148","time_updated":"1372068044","container_guid":"33","owner_guid":"33","site_guid":"1","name":" yvelines","description":"Le.</p>","url":"http://ses"}
]
]
}
Thanks
This is not close to being valid JSON. Use http://jsonlint.com to make sure you have valid inputs before worrying about your code for unpacking the data. You have multiple un-closed arrays (the "[" character starts an array, "]" ends it, and at least one missing comma (before "bookmarks"). It's hard to tell what is wrong with this JSON, because there are enough errors that the intent is not clear.
Your code for accessing the contents is mostly fine, except that "SomeDataIdentifierOfBookmarks" isn't a key that is in your JSON—I presume you mean that would be replaced with an actual value.
Edit: Your pasted actual JSON is trying to close the "object" object with a square bracket rather than a curly bracket. jsonlint will turn those errors up quickly.

I need help parsing a .csv file based on if a string contains a given substring and saving that string to a new file in Objective C

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

working with file offsets in objective-c

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:.