Improving text file reading speed in Xcode? - objective-c

I'm currently working on a project that involves a lot of text file reading. I need to get the contents of the files into NSStrings so I can go and manipulate them further. What I'm using:
NSString *file = [[NSBundle mainBundle] pathForResource:fileName ofType:#"txt"];
NSString *fileContents = [NSString stringWithContentsOfFile:file encoding:NSUTF8StringEncoding error:nil];
It works well enough, but as my project grows so does the number of text files. I'm starting to think there should be a more efficient way of searching through the text files included in the project.
In many cases, I know exactly what file I want to search. I have the files organized into group folders based on when they need to be read. Is there any way to narrow the range of the initial file search? It seems like searching through the entire application bundle every time is pointless when I know where the files I need are on a more specific level.
Is there some way to search through groups as opposed to bundles? Can I somehow exclude certain files from the search? From what I can tell, defining custom bundles for this context would not be an appropriate use of the NSBundle functionality.

Have you looked at the method -[NSBundle pathForResource:ofType:inDirectory:]?

I had almost similar kind of situation, for more optimization, i had kept all resource file inside dictionary with some key ,
you may try following
1 -- in our application you may have some kind of pattern or where you could find major group,
2 -- have multiple dictionary each for each group, and inside group, you could store file name,
3 -- As ken suggested to go with the -[NSBundle pathForResource:ofType:inDirectory:]

Related

NSURL Bookmarks: A Faster Alternative?

Context
My app's model is a tree of objects where each object represents a filesystem item (a folder or file) on disk beneath a given starting folder.
Periodically, I recursively walk this tree from top-down in order to "sync" it to the actual state of the filesystem. That is, I visit each object in the model and verify that the file/folder it represents still exists in the same location on disk.
If the file/folder has moved, I use an NSURL bookmark to ascertain the new location of the file/folder so that I can update my model's state. (I create an NSURL bookmark when I first create the model object and then store the bookmark data as a property of the object so that I can resolve it later.)
The Problem
NSURL bookmarks simply aren't performant enough. It's not uncommon for my model graph to have 20,000 nested objects. Each one has a bookmark. Here's what I'm seeing when I profile performance:
The recursivelyValidateExistingChildItemsOfParentItem:... method is what walks my model tree. 90% of the time involved is just resolving bookmarks (and, if they are stale, re-creating them as described in Apple's documentation).
The app takes almost 2 minutes to complete the walk thanks to this. So, I need a faster alternative to NSURL bookmarks.
What I've Considered
Extended File Attributes. I could add a UUID attribute to each file on disk. Instead of walking my model graph, I could walk the actual filesystem underneath the starting folder. When I find a new file, I could see if it has a UUID extended attribute. If so, I could then search my model graph for the object with that UUID to handle moved/relocated files. The trouble here is that many things clobber extended file attributes—they aren't guaranteed to stick around.
BDAlias or NDAlias. I used to use BDAlias before I migrated to NSURL bookmarks, but that wasn't exceptionally more performant.
Bottom Line
I need a faster alternative to NSURL's bookmarks. But I still need to be able to track files across launches of my app, so simply keeping file descriptors open or using file id's won't work.
I don't care how low-level I have to get; I just need performance. Thanks!
I know the question is old. But this is my answer:
I only use resolving bookmark as a fallback. I save both file path and URL bookmark data in my model. When I want to open file, first I check if the file still exists in the previously known location. If not, I would try to resolve url's bookmark data. This would narrow calling to URL.init(resolvingBookmarkData) only to a limited subset of items. I would then update model with new path after resolving bookmark to keep performance reasonable.
If you need to assure you are working with exactly the same file, you can check file's date, size or a specific EA as an extra measurement.

In Objective-C, how to read the contents of several files packed inside a ZIP archive, into an NSString variable

In Objective-C (for iOS), is there any way to read the files inside a ZIP archive into memory?
So, each file inside the ZIP is a text file. And what I need to do is to iterate through the files inside the ZIP archive until I locate the one I need by name, and then to read its contents (which is text data) to an NSString variable.
Is this possible to do with zlib? I can't see in the header of this library anything to perform such a task, as reading files inside a zip archive.
Also other libraries i checked on the interent seem to decompress to a directory only, but, what I need is to read the contents of the files inside the zip archive into an NSString variable only.
Thanks
You can do this fairly quickly using my zipzap library:
ZZArchive* archive = [ZZArchive archiveWithContentsOfURL:zipFileURL];
NSString* foundContent = nil;
for (ZZArchiveEntry* entry in archive.entries)
if ([entry.fileName isEqualToString:fileNameToFind])
foundContent = [[NSString alloc] initWithData:entry.data
encoding:NSUTF8StringEncoding];
There are many libraries out there you can use. Google is your friend. libzip, libarchive are just two.

Are any archive file formats natively supported in IOS?

Generating a UIWebView with on-board resources is easy enough with the following code.
NSString *path = [[NSBundle mainBundle] bundlePath];
NSURL *baseURL = [NSURL fileURLWithPath:path];
[webView loadHTMLString:htmlString baseURL:baseURL];
However, what I need to do is move one step past simply having pre-generated data on the device, to actually downloading the data from a server to store locally. A lot of that I can handle myself with a reasonable degree of ease, but the question becomes: 'what archive formats does IOS natively support?'
I know there are add-ons that let me support ZIP or PKZip, but if possible it would be preferable to restrict to Apple's built-in tools.
No.
Apparently no native archive format support exists.
If we interpret "archive" generously, as a way to store heterogeneous data in a single file without necessarily compressing it, then you could consider property lists and SQLite databases as archive formats. And, yes, the word "archive" is sometimes used that way, as in .tar format.

Hiding (or encrypting) app resources?

I've developing a Cocoa app that has certain resources (images) which I wish to protect, but still display. Normally one would just place these in the resources folder, but storing there makes it quite easy to grab and use. Is there any way to keep these images hidden, but still access them within the app?
Simple solution:
Merge all files into one big data-file, optionally using 'salts'.
Then retrieve specific files with something like this:
NSData *dataFile = [NSData dataWithContentsOfFile:filePath];
NSData *theFile = [dataFile subdataWithRange: NSMakeRange(startPos,endPos)];
This does not really protect the files,
but prevents people simply dragging out the resources.
At least, the data-file is unusable, certainly with salts.
Another solution:
Create NSData object for every resource.
Add all objects to a NSMutableArray.
Convert the array to one big NSData object.
Write the NSData object to a file.
And add it to the resources folder.
Your app can then read the data-file.
And retrieve the array with the resources.
// Convert array to data
NSData* data=[NSKeyedArchiver archivedDataWithRootObject:theArray];
Use NSKeyedUnarchiver to retrieve the array again.
In order for you to protect the images in one big file, you can just dump the image data to a NSData object sequentially.
If you want, you can use either salts, as previously mentioned, or you can use AES encryption method, as shown here.
Then, you will have to either save the image files structurally (using an NSArray or similar) or record the image offsets so you can retrieve the image data blocks correctly.
This has some drawbacks, specially if your images change over time. That way you will have to monitor those changes and re-structure the file accordingly.
On other option is for you to simply mask the image files by changing name/extension to one of your choice. This will leave some users away from touch.
Finally, you can search for some archiving frameworks using zip like functions and keep the images there (as Blizzard uses in their MPQ format). This will be the best option (since it provides you with encryption methods and it abstracts you of the mechanisms of encryption and archiving) but it may not be easy to find such a framework.
Why do you want to protect the images? It goes without saying that anything you display can be recorded with a screenshot, so if you're trying to protect the images from the person viewing them, there isn't much point.
If you still want to protect them (say, some images should only be available to certain people), encrypting them on disk might be an option. I'm not an Objective-C guy, but this1 seems like a good place to look.

Accessing data files in Objective-C or cocoa

I am fairly new to a objective-c or in whole mac/iphone development. My question is how can I acces a data files(text files or flat files) in objective-c? For example I have a sample.txt file, how can I open this files and access its data? Do I need to use a class? And I heard about dictionary, is this term related to my problems?
Please kindly redirect me to a good site.
Thanks alot.
sasayins.
You can use regular fopen and fread to access the contents of a file. Alternatively, you can use NSString if your file contains only text or NSData for non-text data.
NSString *myString = [NSString stringWithContentsOfFile:#"/path/to/file"];
NSData *myData = [NSData dataWithContentsOfFile:#"/path/to/file"];
Edit
#"/path/to/file" a constant “Objective-C” style string. It is different to a regular C string (i.e. without the # prepended) because it behaves like an object; you can send it messages, and it is able to be stored in NSArrays etc. From a Mac Programmer's point of view, these Objective-C strings can be treated just like NSString objects.
The Mac OS X filesystem layout typically looks like this:
/System contains system files similar to C:\windows\
/Library contains libraries, similar to C:\windows\system32\
/Users similar to Windows' C:\Documents and Settings\
/Applications Mac's version of C:\Program Files\
/Developer Where Xcode, SDKs, and other developer tools live.
If your username on your Mac is "smith", then your Home directory is /Users/smith. If you have a file in your Documents folder of your Home directory called data.txt, then you can use the following code to access it (but I wouldn't recommend hard-coding paths like this)
NSString *myString = [NSString stringWithContentsOfFile:#"/Users/smith/Documents/data.txt"];
There are various functions available for reliably obtaining your home directory and other directories of particular interest. The NSString documentation explains the various methods available for manipulating strings containing paths.