Great! Thanks for the advises. Now I have to zip and unzip a NSData (not a zip file) to a NSData. In other words, I have to zip and unzip "data to data", without using any file. Some idea?
-- Leonardo > Da: Ben Haller <bhcocoa...@sticksoftware.com> > Data: Sun, 28 Nov 2010 08:52:33 -0500 > A: Leonardo <mac.iphone....@gmail.com>, Cocoa List <cocoa-dev@lists.apple.com> > Oggetto: Re: NSTask with unzip > > 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