javascript - Node.js وضع نفس التدفق المقارن في عدة أهداف(قابلة للكتابة)




stream pipe node.js-stream (5)

يجب عليك إنشاء نسخة طبق الأصل من الدفق عن طريق توصيله إلى دفقين. يمكنك إنشاء دفق بسيط مع دفق PassThrough ، فإنه ببساطة يمر الإدخال إلى الإخراج.

const spawn = require('child_process').spawn;
const PassThrough = require('stream').PassThrough;

const a = spawn('echo', ['hi user']);
const b = new PassThrough();
const c = new PassThrough();

a.stdout.pipe(b);
a.stdout.pipe(c);

let count = 0;
b.on('data', function (chunk) {
  count += chunk.length;
});
b.on('end', function () {
  console.log(count);
  c.pipe(process.stdout);
});

انتاج:

8
hi user

أحتاج إلى تشغيل أمرين في سلسلة تحتاج إلى قراءة البيانات من نفس الدفق. بعد توجيه تيار إلى آخر ، يتم إفراغ المخزن المؤقت لذلك لا يمكنني قراءة البيانات من ذلك الدفق مرة أخرى حتى لا ينجح ذلك:

var spawn = require('child_process').spawn;
var fs = require('fs');
var request = require('request');

var inputStream = request('http://placehold.it/640x360');
var identify = spawn('identify',['-']);

inputStream.pipe(identify.stdin);

var chunks = [];
identify.stdout.on('data',function(chunk) {
  chunks.push(chunk);
});

identify.stdout.on('end',function() {
  var size = getSize(Buffer.concat(chunks)); //width
  var convert = spawn('convert',['-','-scale',size * 0.5,'png:-']);
  inputStream.pipe(convert.stdin);
  convert.stdout.pipe(fs.createWriteStream('half.png'));
});

function getSize(buffer){
  return parseInt(buffer.toString().split(' ')[2].split('x')[0]);
}

طلب يشكو من هذا

Error: You cannot pipe after data has been emitted from the response.

ويؤدي تغيير inputStream إلى fs.createWriteStream إلى إصدار نفس المشكلة بالطبع. لا أرغب في الكتابة في ملف ، ولكن أعِد استخدامها بطريقة ما التي ينتجها الطلب (أو أي شيء آخر لهذا الأمر).

هل هناك طريقة لإعادة استخدام دفق مقروء بمجرد الانتهاء من الأنابيب؟ ما هي أفضل طريقة لإنجاز شيء مثل المثال السابق؟


للمشكلة العامة ، يعمل التعليمة البرمجية التالية بشكل جيد

var PassThrough = require('stream').PassThrough
a=PassThrough()
b1=PassThrough()
b2=PassThrough()
a.pipe(b1)
a.pipe(b2)
b1.on('data', function(data) {
  console.log('b1:', data.toString())
})
b2.on('data', function(data) {
  console.log('b2:', data.toString())
})
a.write('text')

ماذا عن الأنابيب في اثنين أو أكثر من تيارات لا في نفس الوقت؟

فمثلا :

var PassThrough = require('stream').PassThrough;
var mybiraryStream = stream.start(); //never ending audio stream
var file1 = fs.createWriteStream('file1.wav',{encoding:'binary'})
var file2 = fs.createWriteStream('file2.wav',{encoding:'binary'})
var mypass = PassThrough
mybinaryStream.pipe(mypass)
mypass.pipe(file1)
setTimeout(function(){
   mypass.pipe(file2);
},2000)

لا ينتج عن الكود السابق أي أخطاء ولكن الملف file2 فارغ


لدي حل مختلف للكتابة على مسارين في وقت واحد ، بطبيعة الحال ، فإن وقت الكتابة سيكون إضافة مرتين ، ولكن يمكنني استخدامه للرد على طلب التنزيل ، حيث أريد الاحتفاظ بنسخة من الملف الذي تم تنزيله على خادمي (في الواقع أستخدم نسخة احتياطية من S3 ، لذا أقوم بتخزين الملفات الأكثر استخدامًا محليًا لتجنب نقل الملفات المتعددة)

/**
 * A utility class made to write to a file while answering a file download request
 */
class TwoOutputStreams {
  constructor(streamOne, streamTwo) {
    this.streamOne = streamOne
    this.streamTwo = streamTwo
  }

  setHeader(header, value) {
    if (this.streamOne.setHeader)
      this.streamOne.setHeader(header, value)
    if (this.streamTwo.setHeader)
      this.streamTwo.setHeader(header, value)
  }

  write(chunk) {
    this.streamOne.write(chunk)
    this.streamTwo.write(chunk)
  }

  end() {
    this.streamOne.end()
    this.streamTwo.end()
  }
}

يمكنك بعد ذلك استخدام هذا ك OutputStream العادية

const twoStreamsOut = new TwoOutputStreams(fileOut, responseStream)

وتمريرها إلى الطريقة الخاصة بك كما لو كانت استجابة أو ملف


في ما يلي نظرة موجبة إلى لغة جافا سكريبت البديلة التي تعرض كيفية التقاط الاسم الأخير للأشخاص "مايكل" ​​كاسمهم الأول.

1) بالنظر إلى هذا النص:

const exampleText = "Michael, how are you? - Cool, how is John Williamns and Michael Jordan? I don't know but Michael Johnson is fine. Michael do you still score points with LeBron James, Michael Green Miller and Michael Wood?";

الحصول على مجموعة من الأسماء الأخيرة من الأشخاص الذين يدعون مايكل. يجب أن تكون النتيجة: ["Jordan","Johnson","Green","Wood"]

2) الحل:

function getMichaelLastName2(text) {
  return text
    .match(/(?:Michael )([A-Z][a-z]+)/g)
    .map(person => person.slice(person.indexOf(' ')+1));
}

// or even
    .map(person => person.slice(8)); // since we know the length of "Michael "

3) تحقق من الحل

console.log(JSON.stringify(    getMichaelLastName(exampleText)    ));
// ["Jordan","Johnson","Green","Wood"]

تجريبي هنا: http://codepen.io/PiotrBerebecki/pen/GjwRoo

يمكنك أيضًا تجربته عن طريق تشغيل المقتطف أدناه.

const inputText = "Michael, how are you? - Cool, how is John Williamns and Michael Jordan? I don't know but Michael Johnson is fine. Michael do you still score points with LeBron James, Michael Green Miller and Michael Wood?";



function getMichaelLastName(text) {
  return text
    .match(/(?:Michael )([A-Z][a-z]+)/g)
    .map(person => person.slice(8));
}

console.log(JSON.stringify(    getMichaelLastName(inputText)    ));





javascript node.js stream pipe node.js-stream