Stream.pipe,

http://nodejs.org/docs/latest/api/all.html#all_stream_pipe_destination_options

will handle this for you in exactly the way you want:

    var copy = function(from, to, cb){
      var stream = fs.createReadStream(from)
        .pipe(fs.createWriteStream(to))

      stream.on('error', cb)
      stream.on('end', cb)
    }

Take a look at the source for Stream.pipe and you'll see what I'm talking
about; It wraps the 'error' event callback and emits only once, then does
its own cleanup (you'll have to call destroy yourself, although I think
maybe pipe should do this in its cleanup...).

>From https://github.com/joyent/node/blob/master/lib/stream.js:


  source.on('error', onerror);
  dest.on('error', onerror);

  // remove all the event listeners that were added.
  function cleanup() {
    source.removeListener('data', ondata);
    dest.removeListener('drain', ondrain);

    source.removeListener('end', onend);
    source.removeListener('close', onclose);

    source.removeListener('error', onerror);
    dest.removeListener('error', onerror);

    source.removeListener('end', cleanup);
    source.removeListener('close', cleanup);

    dest.removeListener('end', cleanup);
    dest.removeListener('close', cleanup);
  }



Cheers,
Adam Crabtree

On Sun, Oct 7, 2012 at 7:57 PM, Alexey Petrushin <[email protected]
> wrote:

> > I'm missing how this would help ...
> With callbacks it may be something like code below:
>
> > so you'll still need to attach the two error handlers, and you'll still
> need
> > to handle the possibility of multiple notifications.
> Not sure about it but maybe `stream.destroy()` on first event should
> handle such cases.
>
>     var copy = function(from, to, cb){
>       var fromStream = null
>       var toStream = null
>
>       var finish = function(err){
>         fromStream.destroy()
>         toStream.destroy()
>         cb(err)
>       }
>
>       fromStream = fs.createReadStream(from, function(err){
>         if(err) return cb(err)
>         toStream = fs.createWriteStream(to, function(err){
>           if(err) return cb(err)
>
>           fromStream.on('error', finish)
>           toStream.on('error', finish)
>           fromStream.on('end', finish)
>           fromStream.pipe(toStream)
>         })
>       })
>     }
>
> On Monday, October 8, 2012 6:41:43 AM UTC+4, Martin Cooper wrote:
>
>> On Sun, Oct 7, 2012 at 5:54 PM, Alexey Petrushin
>> <[email protected]> wrote:
>> > Tried to copy files using streams and pipe and got funny results. Let's
>> > consider following code (highlighted version https://gist.github.com/**
>> 3850106 <https://gist.github.com/3850106>
>> > ):
>> >
>> >     var copy = function(from, to, cb){
>> >       var fromStream = fs.createReadStream(from)
>> >       fromStream.on('error', cb)
>> >       var toStream = fs.createWriteStream(to)
>> >       toStream.on('error', cb)
>> >       fromStream.on('end', cb)
>> >     }
>> >
>> >     copy('non existing file a', 'non existing dir/file b',
>> function(err){
>> >       console.log(err)
>> >     })
>> >
>> > There are errors in both streams (non existing source file and no
>> parent
>> > directory for destination file) - so, both of them will emit
>> > 'error' event, and the callback will be called twice with both errors.
>> >
>> >     // Error will be reported twice:
>> >     //
>> >     // { [Error: ENOENT, open 'non existing file a'] errno: 34,
>> >     //    code: 'ENOENT', path: 'non existing file a' }
>> >     // { [Error: ENOENT, open 'non existing dir/file b'] errno: 34,
>> >     //    code: 'ENOENT', path: 'non existing dir/file b' }
>> >
>> > I found the solution by looking at the source of `util.pump` - it does
>> it by
>> > wrapping callback into function that calls callback only once - for the
>> fist
>> > error and ignoring others.
>> >
>> > But maybe it would be nice to have a callback for `createXxxStream` or
>> > something like 'ready' or 'success' events to know that it created
>> > successfully?
>>
>> I'm missing how this would help. If there was such an event, either
>> stream could still emit an error before it (e.g. open error) or after
>> it (e.g. read or write error), so you'll still need to attach the two
>> error handlers, and you'll still need to handle the possibility of
>> multiple notifications. What would be the benefit of having another
>> event to listen for?
>>
>> --
>> Martin Cooper
>>
>>
>> > --
>> > Job Board: http://jobs.nodejs.org/
>> > Posting guidelines:
>> > https://github.com/joyent/**node/wiki/Mailing-List-**Posting-Guidelines<https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines>
>> > You received this message because you are subscribed to the Google
>> > Groups "nodejs" group.
>> > To post to this group, send email to [email protected]
>> > To unsubscribe from this group, send email to
>> > nodejs+un...@**googlegroups.com
>> > For more options, visit this group at
>> > http://groups.google.com/**group/nodejs?hl=en?hl=en<http://groups.google.com/group/nodejs?hl=en?hl=en>
>>
>  --
> Job Board: http://jobs.nodejs.org/
> Posting guidelines:
> https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
> You received this message because you are subscribed to the Google
> Groups "nodejs" group.
> To post to this group, send email to [email protected]
> To unsubscribe from this group, send email to
> [email protected]
> For more options, visit this group at
> http://groups.google.com/group/nodejs?hl=en?hl=en
>



-- 
Better a little with righteousness
       than much gain with injustice.
Proverbs 16:8

-- 
Job Board: http://jobs.nodejs.org/
Posting guidelines: 
https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
You received this message because you are subscribed to the Google
Groups "nodejs" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/nodejs?hl=en?hl=en

Reply via email to