Scanning a disk for files quickly with progress bar - macos

I need to search a folder (and all sub folders) for certain files. This needs to be done as quickly as possible and I need to be able to display a progress indicator to the user.
To display a progress indicator I would need to quickly retrieve, for example, the total number of folders underneath my folder being searched. That way I can count the sub folders as I scan them and report something useful back to the user.
Is this information available somewhere?
Note that this functionality is specifically for disks that aren't indexed using Spotlight. For Spotlight indexed drives I just run an NSMetadataQuery.

For the actual scan you can use Cocoa classes, such as NSDirectoryEnumerator, or lower-level facilities, such as fts - there are multiple ways just pick what suits you best.
The more interesting part is your progress indicator. The file system does not maintain a "child" count for a folder, i.e. a count of all the children, grandchildren, great grandchildren, etc. However the number of files on a whole volume is available, e.g. see statfs.
The number of items in a particular folder is quick and easy to determine; e.g. NSFileManager's contentsOfDirectoryAtPath:error: returns an array, the fts routines return a linked list, and you can even work it out use the hard link count - obtainable via NSURL's getResourceValue:forKey:error:. Using such methods on entry to a directory you can add its child count to a total, so as you scan the tree you maintain both the number of items processed and the currently known number that need to be processed. Your UI can be of the form "n of m" where both can increase.
If you don't like that then the number of items in a whole tree requires (pre)scanning the tree, which takes a certain amount of time (you can see this in the Finder - just select any folder, the closer to the root of the disk the better, and do a Get Info and you will see a pause while the information is collected). It is not hard to do this using any of the scanning methods mentioned above. You have to consider the time/value/memory tradeoff - e.g. while you can say produce a list of all the items in the tree (a directory enumerator will give you that) count it and then process it one item at a time you risk having a large memory footprint and a pause before anything at all happens - like the pause you see in the Finder's Get Info window).
So your goal of "quickly with progress bar" is a challenge.
HTH

Maybe you can use NSDirectoryEnumarator for that?
You can have your total number of files to check on enumerator and then you just update your progress bar while iterating.
Here's a small piece of code checking all sub folders. It already checks if URL is a directory ,so you can just ignore it.
NSFileManager *fileManager = [[NSFileManager alloc] init] ;
NSArray *keys = [NSArray arrayWithObject:NSURLIsDirectoryKey];
NSString *path = #"YOUR PATH HERE"
NSMutableArray *files = [[NSMutableArray alloc] init];
NSDirectoryEnumerator *enumerator = [fileManager
enumeratorAtURL:[NSURL fileURLWithPath:path]
includingPropertiesForKeys:keys
options:0
errorHandler:^(NSURL *url, NSError *error) {
// Handle the error.
// Return YES if the enumeration should continue after the error.
return YES;
}];
for (NSURL *url in enumerator) {
NSError *error;
NSNumber *isDirectory = nil;
if (! [url getResourceValue:&isDirectory forKey:NSURLIsDirectoryKey error:&error]) {
// handle error
NSLog(#"error-%#", error );
}
else if (! [isDirectory boolValue]) {
//CHECK FOR YOUR FILES ON THIS URL AND UPDATE PROGRESS INDICATOR
}
}

Related

OS X: comparing to images use all the processor

I need to compare images about 2000 images but looping into the images use all the processors.
Here is how I'm comparing the images:
NSImage *file = [[NSImage alloc] initWithContentsOfFile:path];
NSImage *fileTwo = [[NSImage alloc] initWithContentsOfFile:pathTwo];
NSData *imgDataOne = [file TIFFRepresentation];
NSData *imgDataTwo = [fileTwo TIFFRepresentation];
if ([imgDataOne isEqualToData: imgDataTwo])
{
NSLog(#"is the same image");
}
I'm doing something wrong in the comparison or how can I compare the images without taking over the processors of my computer?
The fastest way is to get a list of all the files and then, for each one, get its size and then say that files that are not the same size cannot be equal. That is fast, since it doesn't even require you to read the files from disk.
Once you find two, or more files of equal size, you can MD5 checksum them to see if the contents are identical - if you store the MD5 checksums as you calculate them, it is again faster than comparing every pair of files since you only read each file once.
There is certainly no need to create the TIFFRepresentation of each file...

How do I determine that two paths are hard links to the same file in Cocoa?

I need to create hard links at runtime for file at paths longer than 255 characters (this is a workaround for an infuriating Excel/Word 2011 limitation). But since the same file may be opened later again, I don't want to recreate the hard link if I already have it at the path I created it the first time (I have a scheme to create such a -short- path using a UUID). Which means I need to check wether the file already 'cached' as a hard link is still indeed a hard link to the file I am opening for the user. So I need to check wether 2 paths are hard links to the same file. And I realize there is a potential race condition when testing for this, but the hard links are entirely managed by my app.
Here's the modern way to do it:
NSError* error;
id fileID1, fileID2;
if (![url1 getResourceValue:&fileID1 forKey:NSURLFileResourceIdentifierKey error:&error])
/* handle error */;
if (![url2 getResourceValue:&fileID2 forKey:NSURLFileResourceIdentifierKey error:&error])
/* handle error */;
if ([fileID1 isEqual:fileID2])
/* URLs point to the same file (inode) */;
NSURLFileResourceIdentifierKey is exactly made for this purpose.
I found a solution:
NSDictionary *attr1 = [[NSFileManager defaultManager] attributesOfItemAtPath:url1.path error:NULL];
NSDictionary *attr2 = [[NSFileManager defaultManager] attributesOfItemAtPath:url2.path error:NULL];
NSLog(#"ino1: %#", attr1[NSFileSystemFileNumber]);
NSLog(#"ino2: %#", attr2[NSFileSystemFileNumber]);
NSLog(#"fs1 : %#", attr1[NSFileSystemNumber]);
NSLog(#"fs2 : %#", attr2[NSFileSystemNumber]);
If ino1 and ino2 are the same, and fs1 and fs2 are the same, the inode is the same, so the files are hard links:
BOOL hardLInks = [ino1 isEqual:ino2] && [fs1 isEqual:fs2];

How to add a double from a text field to a NSMutableArray xcode

Thanks To all that helped problem solved. :)
For some reason this wont work for me please help
array = [[NSMutableArray alloc] init];
inputted = [input.text doubleValue];
[array addObject:[NSNumber numberWithDouble:inputted]];
NSLog(#"%i",array.count);
where array is a NSMutableArray, inputted is a double and input is a text field
All that happens is that one saves but deletes the last one entered. how do i make it so that it saves everything entered?
You're always re-creating and re-initializing the "array" mutable array each time you go through your function so it's no wonder you are getting a result of "1" (one object in the array).
If you initialize your array once and only once, and move it out and away from the rest of that code (i.e. into a different function or whatever), then you will add additional objects to your mutable array and you'll see the count increment each time you add an object to your mutable array.
Makes sense?

I have a plist that is an array of dictionaries I need to save to documents directory is this code correct?

Is the code below correct for saving to disk?
// get the path to the "Documents" directory
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
// get the path to our plist ("Documents/foo.plist")
NSString *plistPath = [documentsDirectory stringByAppendingPathComponent:#"foo.plist"];
// read or create plist
NSMutableDictionary *dict;
// check if our plist already exists in the Documents directory...
NSFileManager *fileManager = [NSFileManager defaultManager];
if ( [fileManager fileExistsAtPath:plistPath] ) {
// ...if it does, read it
NSLog(#"dict existed, reading %#", plistPath);
dict = [NSMutableDictionary dictionaryWithContentsOfFile:plistPath];
} else {
// ...if it doesn't, create it
NSLog(#"dict didn't exist, creating...");
dict = [NSMutableDictionary dictionaryWithCapacity:1];
No.
For one thing, it's missing a closing brace at the end, but maybe you just left that out when copying the code into the question.
For another, the code reads in a dictionary; it does not get an array (of anything) from anywhere, nor does it write anything (array or anything else) out.
It sounds like you copied the code from somewhere, hoping that it's what you need. Don't do that. Write your own code. Read code if you want, but only read it; do not just copy code into your program without understanding what it does, and don't rely on other people to tell you what code does.
In order to be a programmer in any language or framework, you must be able to read code in that language/framework. Read the Objective-C Programming Language and read the Cocoa Fundamentals Guide; once you know the concepts those guides teach, all that remains is to practice reading code.
You must also, obviously, be able to write code in the target language/framework. Copying other people's code is not a substitute. At best, you will end up with a shoddy program that is flaky or just doesn't work; at worst (if you're “programming” as a contractor or employee), you will be guilty of plagiarism.

Cocoa: Element count of property list without building dictionary?

What is the best way to count the number of entries in a property list?
I currently build a dictionary from the plist entries (*) and then use the dictionary's count:
NSData *plistXML = [[NSFileManager defaultManager] contentsAtPath:myPlistPath];
NSDictionary *myPlistDict = (NSDictionary *) [NSPropertyListSerialization
propertyListFromData:plistXML
mutabilityOption:NSPropertyListMutableContainersAndLeaves
format:&format
errorDescription:&errorDesc];
NSLog(#"There are %d entries in the plist.", [myPlistDict count]);
This strikes me as unnecessarily "heavy", but I was not able to find a more efficient solution. Any ideas?
(*) targeting 10.5 and therefore using the deprecated +propertyListFromData:… class method.
Well... if you're converting to XML anyway, you could use NSXMLNode's childCount method. The documentation does suggest that it's more efficient than calling [children count], but the creation of the NSXMLNode might make this just as bad (or even worse than) the NSDictionary method.
Have you profiled? Are you working with particularly large plists? Are you requesting this count often? I say: use NSDictionary, cache the value if you request it often, and move on unless this is unacceptably slow. (Yeah, it looks ugly right now, but there are bigger things to worry about.)

Resources