আমি কোনও নোড.জেএস স্ট্রিমের সামগ্রীগুলি স্ট্রিং ভেরিয়েবলের মধ্যে কীভাবে পড়ব?


113

আমি একটি নোড প্রোগ্রাম হ্যাক করছি smtp-protocolযা এসএমটিপি ইমেলগুলি ক্যাপচার করতে এবং মেইল ​​ডেটাতে কাজ করতে ব্যবহার করে। লাইব্রেরিটি একটি স্ট্রিম হিসাবে মেল ডেটা সরবরাহ করে এবং কীভাবে স্ট্রিংয়ের মধ্যে পাবেন তা আমি জানি না।

আমি বর্তমানে এটি স্টাডআউট করার জন্য লিখছি stream.pipe(process.stdout, { end: false }), তবে যেমনটি বলেছিলাম, তার পরিবর্তে আমার স্ট্রিং ডেটা দরকার, যা আমি একবার স্ট্রিমটি শেষ হয়ে গেলে ব্যবহার করতে পারি।

আমি কোনও নোড.জেএস স্ট্রিমের স্ট্রিংয়ে সমস্ত ডেটা কীভাবে সংগ্রহ করব?


আপনার স্ট্রিমটি অনুলিপি করা উচিত বা এটিকে ফ্ল্যাগ করা উচিত (স্বয়ংক্রিয়র বন্ধ: মিথ্যা)। স্মৃতি কলুষিত করা খারাপ অভ্যাস।
19 ই

উত্তর:


41

(এই উত্তরটি বহু বছর আগে, যখন এটি সর্বোত্তম উত্তর ছিল below এর নীচে এখন আরও ভাল উত্তর রয়েছে I আমি নোড.জেএস সহ রাখি নি, এবং আমি এই উত্তরটি মুছতে পারি না কারণ এটি "এই প্রশ্নের সঠিক হিসাবে চিহ্নিত হয়েছে) "। আপনি যদি নীচে ক্লিক করার কথা ভাবছেন তবে আপনি আমাকে কী করতে চান?)

কীটি হ'ল পাঠযোগ্য স্ট্রিমের ইভেন্ট dataএবং endইভেন্টগুলি ব্যবহার করা । এই ঘটনাগুলি শুনুন:

stream.on('data', (chunk) => { ... });
stream.on('end', () => { ... });

আপনি যখন dataইভেন্টটি পান , ডেটা সংগ্রহ করার জন্য তৈরি করা বাফারে ডেটার নতুন অংশ যুক্ত করুন।

আপনি যখন endইভেন্টটি পান , সম্পূর্ণ বাফারটিকে স্ট্রিংয়ে রূপান্তর করুন, যদি প্রয়োজন হয়। তারপরে আপনার যা করার দরকার তা করুন।


149
উত্তরটি চিত্রিত কোডের কয়েকটি লাইন কেবলমাত্র এপিআই-তে একটি লিঙ্ক দেখানো ভাল। উত্তরের সাথে একমত নন, কেবল বিশ্বাস করুন না যে এটি যথেষ্ট পরিমাণে সম্পূর্ণ।
আর্কসেল্ডন

3
নতুন নোড.জেএস সংস্করণ সহ, এটি পরিষ্কার: স্ট্যাকওভারফ্লো
.com/a/35530615

প্রতিশ্রুতি পাঠাগার ব্যবহার না করার জন্য উত্তরটি আপডেট করা উচিত, তবে দেশীয় প্রতিশ্রুতি ব্যবহার করুন।
ড্যান ড্যাসকলেসকু

@ ড্যানডাসক্লেস্কু আমি আপনার সাথে একমত সমস্যাটি হ'ল আমি এই উত্তরটি 7 বছর আগে লিখেছি এবং আমি নোড.জেএস দিয়ে রাখি নি। আপনি যদি অন্য কেউ হন তবে এটি আপডেট করতে চান, এটি দুর্দান্ত। অথবা আমি কেবল এটি মুছতে পারি, কারণ ইতিমধ্যে এর থেকে আরও ভাল উত্তর বলে মনে হচ্ছে। আপনি কি সুপারিশ করতেন?
কন্ট্রোলএলটেল

@ কন্ট্রোলআল্টেল: একটি উত্তর মুছে ফেলার আপনার উদ্যোগকে আমি প্রশংসা করি যা এখন আর সেরা নয়। অন্যদেরও অনুরূপ শৃঙ্খলা থাকতে চাই
ড্যান ড্যাসকলেসকু

129

আর একটি উপায় হ'ল স্ট্রিমটিকে একটি প্রতিশ্রুতিতে রূপান্তর করা (নীচের উদাহরণটি দেখুন) এবং then(অথবা await) ব্যবহার করে সমাধানের মানটি একটি ভেরিয়েবলের জন্য বরাদ্দ করতে পারেন।

function streamToString (stream) {
  const chunks = []
  return new Promise((resolve, reject) => {
    stream.on('data', chunk => chunks.push(chunk))
    stream.on('error', reject)
    stream.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')))
  })
}

const result = await streamToString(stream)

আমি সত্যিই স্ট্রিম এবং প্রতিশ্রুতি নতুন আছি এবং আমি এই ত্রুটি পেয়ে করছি: SyntaxError: await is only valid in async function। আমি কি ভুল করছি?
JohnK

অ্যাসিঙ্ক ফাংশনের মধ্যে আপনাকে স্ট্রিমটস্ট্রিং ফাংশনটি কল করতে হবে। এটি এড়াতে আপনি streamToString(stream).then(function(response){//Do whatever you want with response});
এগুলি

23
এটি শীর্ষ উত্তর হওয়া উচিত। (1) বাফার হিসাবে খণ্ডগুলি সঞ্চয় করে এবং .toString("utf8")শেষে ডেকে একটি একক সমাধান তৈরি করার জন্য অভিনন্দন, যদি কোনও মাল্টিবাইট চরিত্রের মাঝে অংশ বিভক্ত হয় তবে ডিকোড ব্যর্থতার সমস্যা এড়াতে; (২) প্রকৃত ত্রুটি পরিচালনা (3) কোডটি কোনও ফাংশনে রেখে দেওয়া, যাতে এটি পুনরায় ব্যবহার করা যেতে পারে, অনুলিপি-আটকানো নয়; (4) প্রতিশ্রুতি ব্যবহার করে যাতে ফাংশনটি awaitচালু করা যায়; (5) ছোট কোড যা নির্দিষ্ট এনপিএম লাইব্রেরির বিপরীতে মিলিয়ন নির্ভরতাতে টানতে পারে না; ()) ES6 সিনট্যাক্স এবং আধুনিক সেরা অনুশীলন
গুণমানবাইজার

প্রতিশ্রুতিতে খণ্ডগুলি অ্যারে সরানো হবে না কেন?
জেনি ও'রিলি

1
আমি ইঙ্গিত হিসাবে বর্তমান শীর্ষ উত্তরটি ব্যবহার করে মূলত একই কোডটি নিয়ে আসার পরে, আমি লক্ষ্য করেছি যে উপরের কোডটি Uncaught TypeError [ERR_INVALID_ARG_TYPE]: The "list[0]" argument must be an instance of Buffer or Uint8Array. Received type stringযদি stringস্ট্রমের পরিবর্তে খণ্ড সৃষ্টি করে তবে ব্যর্থ হতে পারে Buffer। ব্যবহার chunks.push(Buffer.from(chunk))উভয় stringএবং Bufferখণ্ড সঙ্গে কাজ করা উচিত ।
আন্দ্রেই

67

উপরের কেউই আমার পক্ষে কাজ করেনি। আমার বাফার অবজেক্টটি ব্যবহার করা দরকার:

  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));
  });

7
এটি আসলে এটি করার সবচেয়ে পরিষ্কার উপায়;)
আইভো

7
দুর্দান্ত কাজ করে। কেবলমাত্র একটি নোট: আপনি যদি একটি সঠিক স্ট্রিং টাইপ চান, আপনাকে কনট্যাট () কল থেকে ফলাফল বাফার অবজেক্টে .toString () কল করতে হবে
ব্রায়ান জনসন

64

আশা করি উপরের উত্তরের চেয়ে এটি আরও কার্যকর হবে:

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

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

দ্রষ্টব্য যে স্ট্রিং অংশগুলি সংগ্রহ করার সবচেয়ে কার্যকর উপায় নয়, তবে এটি সরলতার জন্য ব্যবহৃত হয় (এবং সম্ভবত আপনার কোড দক্ষতার বিষয়ে যত্নশীল নয়)।

এছাড়াও, এই কোডটি অ ASCII টেক্সটের জন্য অনুমানযোগ্য ব্যর্থতা তৈরি করতে পারে (এটি ধরে নেওয়া হয় যে প্রতিটি চরিত্র একটি বাইটে ফিট করে) তবে সম্ভবত আপনি এটি সম্পর্কেও চিন্তা করেন না।


4
স্ট্রিং পার্টস সংগ্রহ করার আরও কার্যকর উপায় কী হবে? TY
sean2078

2
আপনি একটি বাফার ডকস ব্যবহার করতে পারেন nনোডজেটস.কম / আর্টিকেলস / অ্যাডভান্সড / বুফারস / হাউ টু ইউজ- বুফারস এটি আপনার ব্যবহারের উপর নির্ভর করে।
টম ক্র্যাচরে

2
স্ট্রিংগুলির একটি অ্যারে ব্যবহার করুন যেখানে আপনি প্রতিটি নতুন অংশ join("")অ্যারেতে যুক্ত করেন এবং শেষে অ্যারেটিতে কল করুন।
ভ্যালেরিও পলোş

14
এটা ঠিক নয় যদি বাফারটি একটি মাল্টি-বাইট কোড পয়েন্টের অর্ধেক পথ ধরে থাকে তবে টসস্ট্রিং () বিকৃত utf-8 পাবেন এবং আপনি আপনার স্ট্রিংয়ের একগুচ্ছ with দিয়ে শেষ করবেন।
alextgordon

2
@alextgordon ঠিক আছে। কিছু খুব বিরল ক্ষেত্রে যখন আমার প্রচুর অংশ ছিল আমি সেগুলি পেয়েছিলাম - খণ্ডগুলির শুরু এবং শেষের দিকে। বিশেষত যখন সেখানে প্রান্তগুলিতে রাশিয়ান চিহ্ন রয়েছে। সুতরাং খণ্ডগুলি সংশ্লেষ করার পরিবর্তে এগুলি সংশ্লেষ করা এবং চূড়ান্ত রূপান্তরিত করার পরিবর্তে তাদের শেষের দিকে রূপান্তর করা এবং তাদের সাথে সংক্ষেপণ করা ঠিক। আমার ক্ষেত্রে অনুরোধটি একটি পরিষেবা থেকে অন্য পরিষেবাতে অনুরোধ করা হয়েছিল। ডিফল্ট এনকোডিং সহ
জিক্স

21

একটি স্ট্রিমকে স্ট্রিংয়ে রূপান্তর করতে আমি সাধারণত এই সাধারণ ফাংশনটি ব্যবহার করছি:

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

ব্যবহারের উদাহরণ:

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

1
দরকারী উত্তর তবে এটি দেখে মনে হচ্ছে যে প্রতিটি chunks.push(chunk.toString());
অংশটিকে অ্যারেতে ঠেকানোর

1
এই একমাত্র আমার জন্য কাজ করেছেন! দুর্দান্ত ধন্যবাদ
538 রোমো

1
এটি একটি দুর্দান্ত উত্তর ছিল!
Aft3rL1f3

12

এবং প্রতিশ্রুতি ব্যবহার করে স্ট্রিংয়ের জন্য আরও একটি:

function getStream(stream) {
  return new Promise(resolve => {
    const chunks = [];

    # Buffer.from is required if chunk is a String, see comments
    stream.on("data", chunk => chunks.push(Buffer.from(chunk)));
    stream.on("end", () => resolve(Buffer.concat(chunks).toString()));
  });
}

ব্যবহার:

const stream = fs.createReadStream(__filename);
getStream(stream).then(r=>console.log(r));

.toString()প্রয়োজনে বাইনারি ডেটা সহ ব্যবহারটি সরিয়ে ফেলুন ।

আপডেট : @ এন্ড্রেইলডিডি সঠিকভাবে চিহ্নিত করেছে এতে স্ট্রিংগুলির সমস্যা রয়েছে। আমার কাছে থাকা নোডের সংস্করণটি দিয়ে আমি স্ট্রিম ফেরার স্ট্রিংগুলি পাইনি, তবে এপিআই নোটগুলি এটি সম্ভব।


আমি লক্ষ্য করেছি যে উপরের কোডটি ব্যর্থ হতে পারে Uncaught TypeError [ERR_INVALID_ARG_TYPE]: The "list[0]" argument must be an instance of Buffer or Uint8Array. Received type stringযদি স্ট্রিমটির stringপরিবর্তে খণ্ড সৃষ্টি করে Buffer। ব্যবহার chunks.push(Buffer.from(chunk))উভয় stringএবং Bufferখণ্ড সঙ্গে কাজ করা উচিত ।
আন্দ্রেই

ভাল কথা, আমি উত্তর আপডেট করেছি। ধন্যবাদ।
ইস্তানী

8

নোডেজ ডকুমেন্টেশন থেকে আপনার এটি করা উচিত - সর্বদা এনকোডিং না জেনে একটি স্ট্রিং মনে রাখবেন কেবল বাইটের একটি গুচ্ছ:

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);
})

6

স্ট্রিমগুলির একটি সাধারণ .toString()ফাংশন নেই (যা আমি বুঝি) বা এর মতো কিছু নেই.toStringAsync(cb) ফাংশনের (যা আমি বুঝতে পারি না)।

সুতরাং আমি আমার নিজস্ব সহায়ক ফাংশন তৈরি করেছি:

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);
});

4

আমি এরকম ব্যবহার করে আরও ভাগ্য পেয়েছি:

let string = '';
readstream
    .on('data', (buf) => string += buf.toString())
    .on('end', () => console.log(string));

আমি নোড ব্যবহার করি v9.11.1এবং এটিই readstreamএকটি http.getকলব্যাক থেকে প্রাপ্ত প্রতিক্রিয়া ।


3

সবচেয়ে পরিষ্কার সমাধান হতে পারে "স্ট্রিং-স্ট্রিম" প্যাকেজটি ব্যবহার করা, যা একটি স্ট্রিমকে প্রতিশ্রুতি দিয়ে স্ট্রিংয়ে রূপান্তর করে।

const streamString = require('stream-string')

streamString(myStream).then(string_variable => {
    // myStream was converted to a string, and that string is stored in string_variable
    console.log(string_variable)

}).catch(err => {
     // myStream emitted an error event (err), so the promise from stream-string was rejected
    throw err
})

3

জনপ্রিয় (5 মিলিয়ন সাপ্তাহিক ডাউনলোডের উপরে) এবং হালকা গেট স্ট্রিম লাইব্রেরির সাথে সহজ উপায় :

https://www.npmjs.com/package/get-stream

const fs = require('fs');
const getStream = require('get-stream');

(async () => {
    const stream = fs.createReadStream('unicorn.txt');
    console.log(await getStream(stream)); //output is string
})();

2

স্ট্রিম রিডিউসারের মতো কী হবে?

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

1

এটি আমার পক্ষে কাজ করেছে এবং নোড v6.7.0 ডক্সের উপর ভিত্তি করে :

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

setEncoding ( 'UTF8');

উপরের সেবাস্তিয়ান জে ভাল করেছেন।

আমার কাছে কয়েকটি কোডের টেস্ট কোডের সাথে "বাফার সমস্যা" ছিল এবং আমি এনকোডিংয়ের তথ্য যুক্ত করেছি এবং এটি সমাধান করেছে, নীচে দেখুন।

সমস্যাটি প্রদর্শন করুন

সফটওয়্যার

// process.stdin.setEncoding('utf8');
process.stdin.on('data', (data) => {
    console.log(typeof(data), data);
});

ইনপুট

hello world

আউটপুট

object <Buffer 68 65 6c 6c 6f 20 77 6f 72 6c 64 0d 0a>

সমাধানটি প্রদর্শন করুন

সফটওয়্যার

process.stdin.setEncoding('utf8'); // <- Activate!
process.stdin.on('data', (data) => {
    console.log(typeof(data), data);
});

ইনপুট

hello world

আউটপুট

string hello world

1

তালিকাভুক্ত সমস্ত উত্তর প্রবাহিত মোডে পঠনযোগ্য স্ট্রিমটি খোলার জন্য প্রদর্শিত হবে যা নোডজেএস-এ ডিফল্ট নয় এবং এর সীমাবদ্ধতা থাকতে পারে কারণ নোডজেএস বিরাম পঠনযোগ্য স্ট্রিম মোডে সরবরাহ করে এমন ব্যাকপ্রেসার সমর্থনটির অভাব রয়েছে। জাস্ট বাফারস, নেটিভ স্ট্রিম এবং নেটিভ স্ট্রিম ট্রান্সফর্ম এবং অবজেক্ট মোডের জন্য সমর্থন ব্যবহার করে একটি বাস্তবায়ন এখানে দেওয়া হয়েছে

import {Transform} from 'stream';

let buffer =null;    

function objectifyStream() {
    return new Transform({
        objectMode: true,
        transform: function(chunk, encoding, next) {

            if (!buffer) {
                buffer = Buffer.from([...chunk]);
            } else {
                buffer = Buffer.from([...buffer, ...chunk]);
            }
            next(null, buffer);
        }
    });
}

process.stdin.pipe(objectifyStream()).process.stdout

1

আপনি এ ব্যপারে কী ভাবছেন ?

// lets a ReadableStream under stream variable 
const chunks = [];

for await (let chunk of stream) {
    chunks.push(chunk)
}

const buffer  = Buffer.concat(chunks);
const str = buffer.toString("utf-8")

কাজগুলি, খুব পরিষ্কার, কোনও নির্ভরতা নেই, দুর্দান্ত!
ViRuSTriNiTy

0

আপনার ইতিমধ্যে আপনার প্রকল্প নির্ভরতাগুলির মধ্যে বেশ জনপ্রিয় stream-buffersপ্যাকেজটি ব্যবহার করে এটি বেশ সোজা:

// imports
const { WritableStreamBuffer } = require('stream-buffers');
const { promisify } = require('util');
const { createReadStream } = require('fs');
const pipeline = promisify(require('stream').pipeline);

// sample stream
let stream = createReadStream('/etc/hosts');

// pipeline the stream into a buffer, and print the contents when done
let buf = new WritableStreamBuffer();
pipeline(stream, buf).then(() => console.log(buf.getContents().toString()));

0

আমার ক্ষেত্রে, সামগ্রীর ধরণের প্রতিক্রিয়া শিরোনামগুলি ছিল সামগ্রী-প্রকার: পাঠ্য / প্লেইন । সুতরাং, আমি বাফারের মতো ডেটা পড়েছি:

let data = [];
stream.on('data', (chunk) => {
 console.log(Buffer.from(chunk).toString())
 data.push(Buffer.from(chunk).toString())
});
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.