2012-05-16 10 views
50

Ich hacke auf einem node.js-Programm, das SMTP-Mails erfasst und auf die Mail-Daten wirkt. Die 'smtp-protocol'-Knotenbibliothek stellt die Mail-Daten live als Stream zur Verfügung, und als node.js-Neuling bin ich mir nicht sicher, wie ich diesen Stream in eine String-Variable schreiben soll. Im Moment habe ich es mit der Linie nach stdout schreiben:Schreiben von node.js stream in eine String-Variable

stream.pipe(process.stdout, { end : false }); 

Wie gesagt, ich brauche stattdessen ein String-Variable schreiben Diese Strom-Daten zu erhalten, die ich dann benutzen, wenn der Strom beendet ist.

Hilfe sehr geschätzt!

+0

Sie sollten den Stream kopieren oder mit (autoClose: false) kennzeichnen. Es ist eine schlechte Übung, die Erinnerung zu verschmutzen. –

Antwort

22

Der Schlüssel ist, diese beiden Stream events zu verwenden:

  • Veranstaltung: 'data'
  • Veranstaltung: 'Ende'

Für stream.on('data', ...) Sie Ihre Daten Daten entweder in einem Puffer sammeln sollte (wenn es binär ist) oder in eine Zeichenfolge.

Für on('end', ...) sollten Sie einen Rückruf mit Ihnen abgeschlossenen Puffer aufrufen, oder wenn Sie es inline und verwenden können, Rückgabe mithilfe einer Promises-Bibliothek.

+0

Das hat perfekt funktioniert. Vielen Dank! – obrienmd

+76

Ein paar Codezeilen, die die Antwort illustrieren, sind vorzuziehen, wenn Sie nur auf einen Link in der API zeigen. Widersprich nicht der Antwort, glaube einfach nicht, dass es vollständig genug ist. – arcseldon

+1

Mit neueren node.js-Versionen ist dies sauberer: http://StackOverflow.com/a/35530615/271961 –

40

Hoffe, das ist nützlicher als die obige Antwort (die jetzt einen defekten Link hat).

auch, dass die String-Verkettung zu beachten ist kein effizienter Weg, um die Zeichenfolge Teile zu sammeln, aber es ist der Einfachheit halber verwendet (und vielleicht auch Ihren Code kümmert sich nicht um Effizienz)

var string = '' 
stream.on('readable',function(buffer){ 
    var part = buffer.read().toString(); 
    string += part; 
    console.log('stream data ' + part); 
}); 


stream.on('end',function(){ 
console.log('final output ' + string); 
}); 
+3

Was wäre eine effizientere Möglichkeit zum Sammeln von Stringteilen? TY – sean2078

+2

Sie könnten einen Puffer https://docs.nodejitsu.com/articles/advanced/buffers/how-to-use-buffers verwenden, aber es hängt wirklich von Ihrer Verwendung ab. –

+2

Verwenden Sie ein Array von Strings, bei dem Sie jeden neuen Chunk an das Array anhängen und 'join (" ")' auf dem Array am Ende aufrufen. –

7

Von den NodeJS documentation Sie sollten dies tun - immer einen String erinnern, ohne die Codierung zu wissen, ist nur ein Haufen von Bytes:

var readable = getReadableStreamSomehow(); 
readable.setEncoding('utf8'); 
readable.on('data', function(chunk) { 
    assert.equal(typeof chunk, 'string'); 
    console.log('got %d characters of string data', chunk.length); 
}) 
12

ich benutze in der Regel diese einfache Funktion einen Strom in einen String zu verwandeln:

function streamToString(stream, cb) { 
    const chunks = []; 
    stream.on('data', (chunk) => { 
    chunks.push(chunk.toString()); 
    }); 
    stream.on('end',() => { 
    cb(chunks.join('')); 
    }); 
} 

Anwendungsbeispiel:

let stream = fs.createReadStream('./myFile.foo'); 
streamToString(stream, (data) => { 
    console.log(data); // data is now my string variable 
}); 
+0

Nützliche Antwort aber Es sieht so aus, als ob jeder Chunk in eine Zeichenkette umgewandelt werden muss, bevor er in das Array geschoben wird: 'chunks.push (chunk.toString());' –

+0

Sie haben recht! Ich ändere es! – dreampulse

+0

Vergessen Sie nicht, das Fehlerereignis zu binden! –

24

Keine der oben für mich gearbeitet. Ich brauchte die Buffer-Objekt zu verwenden:

const chunks = []; 

    readStream.on("data", function (chunk) { 
    chunks.push(chunk); 
    }); 

    // Send the buffer or you can put it into a var 
    readStream.on("end", function() { 
    res.send(Buffer.concat(chunks)); 
    }); 
+2

das ist eigentlich der sauberste Weg es zu tun;) – Ivo

+0

Sauber, effizient und funktioniert gut mit Binärdaten. – giosh94mhz

+0

Funktioniert gut. Nur ein Hinweis: Wenn Sie einen richtigen String-Typ wünschen, müssen Sie .toString() für das resultierende Buffer-Objekt von concat() aufrufen –

5

Streams haben keine einfache .toString() Funktion (was ich verstehen) noch so etwas wie eine .toStringAsync(cb) Funktion (die ich nicht verstehe).

Also habe ich meine eigene Hilfsfunktion:

var streamToString = function(stream, callback) { 
    var str = ''; 
    stream.on('data', function(chunk) { 
    str += chunk; 
    }); 
    stream.on('end', function() { 
    callback(str); 
    }); 
} 

// how to use: 
streamToString(myStream, function(myStr) { 
    console.log(myStr); 
}); 
0

Das ist für mich gearbeitet und basiert auf Node v6.7.0 docs:

let output = ''; 
stream.on('readable', function() { 
    let read = stream.read(); 
    if (read !== null) { 
     // New stream data is available 
     output += read.toString(); 
    } else { 
     // Stream is now finished when read is null. 
     // You can callback here e.g.: 
     callback(null, output); 
    } 
}); 

stream.on('error', function(err) { 
    callback(err, null); 
}) 
1

Was ist so etwas wie ein Strom Minderer?

Hier ist ein Beispiel mit ES6-Klassen, wie man einen verwendet.

var stream = require('stream') 

class StreamReducer extends stream.Writable { 
    constructor(chunkReducer, initialvalue, cb) { 
    super(); 
    this.reducer = chunkReducer; 
    this.accumulator = initialvalue; 
    this.cb = cb; 
    } 
    _write(chunk, enc, next) { 
    this.accumulator = this.reducer(this.accumulator, chunk); 
    next(); 
    } 
    end() { 
    this.cb(null, this.accumulator) 
    } 
} 

// just a test stream 
class EmitterStream extends stream.Readable { 
    constructor(chunks) { 
    super(); 
    this.chunks = chunks; 
    } 
    _read() { 
    this.chunks.forEach(function (chunk) { 
     this.push(chunk); 
    }.bind(this)); 
    this.push(null); 
    } 
} 

// just transform the strings into buffer as we would get from fs stream or http request stream 
(new EmitterStream(
    ["hello ", "world !"] 
    .map(function(str) { 
    return Buffer.from(str, 'utf8'); 
    }) 
)).pipe(new StreamReducer(
    function (acc, v) { 
    acc.push(v); 
    return acc; 
    }, 
    [], 
    function(err, chunks) { 
    console.log(Buffer.concat(chunks).toString('utf8')); 
    }) 
); 
Verwandte Themen