Yes, this looks good. I like your category on NSFileHandle (not a subclass!); it's cleaner than the code at the link I sent you, since it doesn't just eat the error, and it's better as a category.
Four things I would mention: 1) Checking that the pipe could be created and actually has a file handle for reading would be a good idea; [NSPipe pipe] is documented as being allowed to return nil 2) Checking -terminationStatus is a good idea once the task completes (after you're done pulling data out, you can then safely call -waitUntilExit on the task to be certain it has completed before calling -terminationStatus, AFAIK) 3) You only use a pipe for standard out, not for standard in, but it's worth noting that a pipe for standard in needs to receive a -closeFile call or the file descriptor for that pipe doesn't get deleted correctly. As a reminder to myself about this issue, I just send -closeFile to all of the pipes I'm using with a task, so that I don't forget to do it. But your code is correct; I mention this just in case someone reading the archives adapts this code to a task that requires a standard in pipe. 4) -launch can raise, so it is good to think about that; but as long as you're comfortable with your method raising, your code seems fine to me. Good stuff! If anybody on the list knows whether the bug that the -availableDataOrError: hack circumvents has been fixed, and in what OS X release, I'd love to know that so I know whether it's safe to delete that rather unpleasant hack from my code. Ben Haller McGill University On 2010-11-27, at 3:43 PM, Leonardo wrote: > Ben, thank you so much! I have successfully done it. > I post the code here for anyone to use it. I love this list. > > - (NSData*)UnzipFile:(NSString*)sourcePath > extractFileName:(NSString*)extractFileName > { > NSTask *unzip = [[[NSTask alloc] init] autorelease]; > NSPipe *aPipe = [NSPipe pipe]; > [unzip setStandardOutput:aPipe]; > [unzip setLaunchPath:@"/usr/bin/unzip"]; > [unzip setArguments:[NSArray arrayWithObjects:@"-p", sourcePath, > extractFileName, nil]]; > [unzip launch]; > > NSMutableData *dataOut = [NSMutableData data]; > NSData *dataIn = nil; > NSException *error = nil; > > while((dataIn = [[aPipe fileHandleForReading] > availableDataOrError:&error]) && [dataIn length] && error == nil){ > [dataOut appendData:dataIn]; > } > > if([dataOut length] && error == nil){ > return dataOut; > } > > return nil; > } > > > // Then I subclassed NSFileHandler this way > > @implementation NSFileHandle (MyOwnAdditions) > - (NSData*)availableDataOrError:(NSException**)returnError > { > for(;;){ > @try{ > return [self availableData]; > }...@catch (NSException *e) { > if ([[e name] isEqualToString:NSFileHandleOperationException]) { > if ([[e reason] isEqualToString:@"*** -[NSConcreteFileHandle > availableData]: Interrupted system call"]) { > continue; > } > if (returnError) > *returnError = e; > return nil; > } > @throw; > } > } > } > @end > > >> Da: Ben Haller <bhcocoa...@sticksoftware.com> >> Data: Sat, 27 Nov 2010 12:12:39 -0500 >> A: Dave DeLong <davedel...@me.com> >> Cc: "gMail.com" <mac.iphone....@gmail.com>, Cocoa List >> <cocoa-dev@lists.apple.com> >> Oggetto: Re: NSTask with unzip >> >> Here's a post that I found useful: >> >> http://dev.notoptimal.net/2007/04/nstasks-nspipes-and-deadlocks-when.html >> >> Dave, not sure what you mean here. NSPipe uses NSFileHandle. Does using an >> NSFileHandle directly change things somehow? If so, why? I think this is an >> avenue I haven't explored; once I (finally) figured out the right magic >> incantations to get things to work reliably with NSPipe, I now recycle that >> code everywhere I need an NSTask :->. >> >> Ben Haller >> McGill University >> >> >> On 2010-11-27, at 11:48 AM, Dave DeLong wrote: >> >>> The way I get around this is to use an NSFileHandle for standard out instead >>> of an NSPipe. It's a bit less efficient, but slightly more convenient. >>> >>> Dave >>> >>> Sent from my iPhone >>> >>> On Nov 27, 2010, at 7:59 AM, Ben Haller <bhcocoa...@sticksoftware.com> >>> wrote: >>> >>>> On 2010-11-26, at 7:33 AM, gMail.com wrote: >>>> >>>>> Hi, I can properly unzip a zip file launching a NSTask with /usr/bin/unzip >>>>> The task saves the unzipped file to the disk, then a I read the unzipped >>>>> file in a NSData. Well. My question is: >>>>> Can I do the same job without saving the unzipped file to the disk? >>>>> >>>>> I have tried to set the standard output to a pipe - which works well with >>>>> other tasks - but here it doesn't work. The task never exits. Here's the >>>>> wrong code: >>>>> >>>>> NSTask *unzip = [[[NSTask alloc] init] autorelease]; >>>>> [unzip setLaunchPath:@"/usr/bin/unzip"]; >>>>> [unzip setArguments:[NSArray arrayWithObjects:@"-p", zipfile, >>>>> @"filetounzip", nil]]; >>>>> >>>>> NSPipe *aPipe = [NSPipe pipe]; >>>>> [unzip setStandardOutput:aPipe]; >>>>> [unzip launch]; >>>>> [unzip waitUntilExit]; >>>>> >>>>> if([unzip terminationStatus] == noErr){ >>>>> dictData = [NSMutableData data]; >>>>> while((dataOut = [aPipe availableData]) && [dataOut length]){ >>>>> [dictData appendData:dataOut]; >>>>> } >>>>> } >>>> >>>> If I recall correctly, the problem is likely to be your use of >>>> -waitUntilExit. That API should apparently have a large red label on it >>>> ("Warnin', lark's vomit!") since everybody wants to use it this way. The >>>> problem is that the task's output pipe fills up because it isn't being >>>> serviced, and then things get locked up. You need to go with asynchronous >>>> reads to service the pipe as output gets stuffed into it. There should be >>>> lots of examples of this on this list, now that you know what to look for. >>>> >>>> What would be great would be a new call, along the lines of >>>> -dataFromWaitingUntilExit or some such, that does all this for you, since >>>> this is so commonly what people want to do. >>>> >>>> Ben Haller >>>> McGill University >>>> >>>> _______________________________________________ >>>> >>>> Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) >>>> >>>> Please do not post admin requests or moderator comments to the list. >>>> Contact the moderators at cocoa-dev-admins(at)lists.apple.com >>>> >>>> Help/Unsubscribe/Update your Subscription: >>>> http://lists.apple.com/mailman/options/cocoa-dev/davedelong%40me.com >>>> >>>> This email sent to davedel...@me.com >> > > _______________________________________________ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com