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

Reply via email to