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