2012-05-16 19 views
50

Estoy pirateando un programa node.js que captura correos SMTP y actúa sobre los datos de correo. La biblioteca del nodo 'smtp-protocol' proporciona los datos del correo en vivo como una secuencia, y como novato node.js no estoy seguro de cómo escribir esa secuencia en una variable de cadena. En este momento tengo que escribir en la salida estándar utilizando la línea:Escribir flujo node.js en una variable de cadena

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

Como dije, tengo que conseguir estos datos de corriente al grabar en una variable de cadena en su lugar, lo que voy a utilizar a continuación, una vez que el flujo ha terminado.

Ayuda muy apreciada!

+0

Debe copiar el flujo o marcarlo con (autoClose: falso). Es una mala práctica contaminar la memoria. –

Respuesta

22

La clave es utilizar estos dos Stream events:

  • Evento: 'data'
  • Evento: 'final'

Para stream.on('data', ...) que debe recolectar sus datos de datos ya sea en un búfer (si es binario) o en una cadena.

Para on('end', ...) debe llamar a una devolución de llamada con el búfer completo, o si puede alinearlo y utilizar devolver utilizando una biblioteca Promises.

+0

Eso funcionó perfectamente. ¡Gracias! – obrienmd

+76

Un par de líneas de código que ilustran la respuesta es preferible a solo señalar un enlace en la API. No esté en desacuerdo con la respuesta, simplemente no crea que es lo suficientemente completa. – arcseldon

+1

Con las versiones más nuevas de node.js, esto es más limpio: http://stackoverflow.com/a/35530615/271961 –

40

Espero que esto sea más útil que la respuesta anterior (que ahora tiene un enlace roto).

También tenga en cuenta que la concatenación de cadenas no es una forma eficaz de recoger las partes de cuerda, pero se usa por simplicidad (y tal vez su código no se preocupa por la eficiencia)

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

¿Cuál sería una forma más eficiente de recopilar partes de cuerdas? TY – sean2078

+2

puede usar un búfer https://docs.nodejitsu.com/articles/advanced/buffers/how-to-use-buffers, pero realmente depende de su uso. –

+2

Utilice una matriz de cadenas donde anexe cada fragmento nuevo a la matriz y llame a 'join (" ")' en la matriz al final. –

7

De los nodejs documentation que debiera hacer esto - recuerda siempre una cadena sin conocer la codificación es sólo un montón de 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

estoy usando por lo general esta función sencilla para transformar una secuencia en una cadena:

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

Ejemplo de uso:

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

. Respuesta útil pero parece que cada trozo debe convertirse en una cadena antes de que se inserte en la matriz: 'chunks.push (chunk.toString());' –

+0

¡Tienes razón! ¡Yo lo cambie! – dreampulse

+0

¡No te olvides de vincular el evento de error! –

24

Ninguna de las anteriores trabajado para mí. Necesitaba usar el objeto Buffer:

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

esta es la forma más limpia de hacerlo;) – Ivo

+0

Limpio, eficiente y funciona bien con datos binarios. – giosh94mhz

+0

Funciona muy bien. Solo una nota: si quieres un tipo de cadena adecuado, necesitarás llamar a .toString() en el objeto Buffer resultante desde la llamada concat() –

5

corrientes no tienen un simple .toString() función (que entiendo), ni algo así como una función .toStringAsync(cb) (que no entiendo).

así que creé mi propia función auxiliar:

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

Esto funcionó para mí y se basa en 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

¿Qué pasa con algo así como un reductor de flujo?

Aquí hay un ejemplo de cómo utilizar las clases de ES6.

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')); 
    }) 
); 
Cuestiones relacionadas