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...
Related
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
}
}
I want to use codes like this.
NSMetadataQuery *query = [[NSMetadataQuery alloc] init];
[query setSearchScopes: [NSArray arrayWithObject: [NSURL fileURLWithPath:#"/Users/Someone/Music" isDirectory:YES]]];
[query setPredicate: predicate];
...
...
Now how do I suppose to set "predicate" to filter out those files with unsupported format??
kMDItemCodezs,kMDItemMediaTypes,kMDItemContentType,kMDItemKind?
Which one should I use? And what are all the possible values of these attibutes corresponding to the supported format in AVAudioPlayer in Lion 10.7? Thanks a lot.
To obtain a list of most supported formats, you can use AudioFileGetGlobalInfo in the AudioToolbox framework to get the UTIs supported by Core Audio (using kAudioFileGlobalInfo_AllUTIs):
UInt32 size;
NSArray *all;
OSStatus err;
err = AudioFileGetGlobalInfoSize(kAudioFileGlobalInfo_AllUTIs, 0, NULL, &size);
if (err == noErr)
err = AudioFileGetGlobalInfo(kAudioFileGlobalInfo_AllUTIs, 0, NULL, &size, &all);
if (err == noErr)
NSLog(#"UTIs: %#", all);
[all release];
On 10.7, this gives me:
"public.aiff-audio",
"public.ulaw-audio",
"org.3gpp.adaptive-multi-rate-audio",
"com.microsoft.waveform-audio",
"public.3gpp2",
"com.apple.coreaudio-format",
"public.3gpp",
"public.mp3",
"public.au-audio",
"public.mpeg-4-audio",
"public.mpeg-4",
"com.apple.m4a-audio",
"public.aifc-audio"
Unfortunately UTIs aren't defined for some of the more obscure data formats (e.g. .mp1/.mp2) Core Audio supports; if you're happy with the above subset, then just use the UTIs.
Then turn those into a NSMetadataQuery (kMDItemContentType for kAudioFileGlobalInfo_AllUTIs). If you want to cover the rest of the formats, you can match by HFS type and extension: kMDItemFSTypeCode for kAudioFileGlobalInfo_AllHFSTypeCodes, and a wildcard match of kMDItemFSName for kAudioFileGlobalInfo_AllExtensions. You can use afconvert -hf to display both of these.
Matching with NSMetadataQuery will of course not look inside all of the files, so it'll still find text files renamed with a .mp3 extension. Since Spotlight does try to index other audio attributes, you could try checking kMDItemAudioBitRate and so forth; these will be missing on a file that isn't actually an audio file. Depending on how accurate you want to be in filtering, you can also try opening each file to see if it's playable.
Use kMDItemContentTypeTree, and the audio type. This will match any audio files, ignoring movie files. If you want to include movie files, search for the audio-visual content type, which the audio type conforms to (descends from).
Edit: This will match all known audio types, regardless of whether Core Audio (let alone AVAudioPlayer) can play them. Nicholas Riley's solution is better.
I have two NSData objects
NSData *toScan = /* initialized somehow with "Hello, this world." */;
NSData *toMatch = /* initialized somehow with "this" */;
What is the best way to know the toMatch bytes are the subset of toScan bytes?
I use C-functions for this purposes at this point: something like this
strstr([[toScan identifier] bytes], [[toMatch identifier] bytes]);
// returned bytes are null-terminated
but I think there is not the best way to use C-functions in object-oriented environment...
As of Snow Leopard and iOS 4.0, NSData has -rangeOfData:options:range: which should do what you want.
It's also pretty darn fast.
In a different question, I wrote an answer containing an NSData category with a rangeOfData: method:
Elegant Algorithm for Parsing Data Stream Into Record
That'll do what you're looking for.
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.
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.)