একটি স্ট্রিমের বিষয়বস্তু অন্য প্রবাহে অনুলিপি করার সর্বোত্তম উপায় কী? এর জন্য কি কোনও স্ট্যান্ডার্ড ইউটিলিটি পদ্ধতি আছে?
একটি স্ট্রিমের বিষয়বস্তু অন্য প্রবাহে অনুলিপি করার সর্বোত্তম উপায় কী? এর জন্য কি কোনও স্ট্যান্ডার্ড ইউটিলিটি পদ্ধতি আছে?
উত্তর:
.NET 4.5 থেকে, Stream.CopyToAsync
পদ্ধতিটি রয়েছে
input.CopyToAsync(output);
এটি এমনটি ফিরিয়ে দেবে Task
যা সম্পূর্ণ হওয়ার পরে অবিরত করা যেতে পারে, যেমন:
await input.CopyToAsync(output)
// Code from here on will be run in a continuation.
নোট করুন যে যেখানে কল করা হয়েছে CopyToAsync
তার উপর নির্ভর করে , কোড অনুসরণ করা কোডটি একই থ্রেডে কল করতে পারে বা চালিয়ে যেতে পারে that
SynchronizationContext
যে যখন কলিং বন্দী করা হয় await
কি থ্রেড ধারাবাহিকতা উপর মৃত্যুদন্ড কার্যকর করা হবে নির্ধারণ করা হবে।
অতিরিক্তভাবে, এই কলটি (এবং এটি পরিবর্তনের সাপেক্ষে এটি বাস্তবায়নের বিশদ sequ
.NET 4.0 থেকে, Stream.CopyTo
পদ্ধতিটি রয়েছে
input.CopyTo(output);
.NET 3.5 এবং এর আগে
এটিকে সহায়তা করার জন্য ফ্রেমওয়ার্কটিতে বেকড কিছু নেই; আপনাকে কন্টেন্টটি ম্যানুয়ালি করতে হবে, যেমন:
public static void CopyStream(Stream input, Stream output)
{
byte[] buffer = new byte[32768];
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
output.Write (buffer, 0, read);
}
}
দ্রষ্টব্য 1: এই পদ্ধতিটি আপনাকে অগ্রগতির প্রতিবেদন করতে অনুমতি দেবে (এক্স বাইটগুলি এখনও অবধি পড়ে ...)
দ্রষ্টব্য 2: একটি নির্দিষ্ট বাফার আকার কেন ব্যবহার করবেন না input.Length
? কারণ যে দৈর্ঘ্য উপলব্ধ নাও হতে পারে! ডক্স থেকে :
স্ট্রিম থেকে প্রাপ্ত কোনও শ্রেণি যদি সন্ধানকে সমর্থন না করে তবে দৈর্ঘ্য, সেটলেন্থ, অবস্থান এবং কল করুন একটি নটসপোর্টড এক্সসেপশন নিক্ষেপ করুন।
81920
বাইট, না32768
মেমরিস্ট্রিম রয়েছে। রাইটওটো (আউটস্ট্রিম);
এবং .NET 4.0 এর সাধারণ স্ট্রিম অবজেক্টে কপিটি আছে।
নেট 4.0:
instream.CopyTo(outstream);
আমি নিম্নলিখিত এক্সটেনশন পদ্ধতি ব্যবহার করি। যখন একটি স্ট্রিম মেমরিস্ট্রিম হয় তখন তারা ওভারলোডগুলি অপ্টিমাইজ করেছে।
public static void CopyTo(this Stream src, Stream dest)
{
int size = (src.CanSeek) ? Math.Min((int)(src.Length - src.Position), 0x2000) : 0x2000;
byte[] buffer = new byte[size];
int n;
do
{
n = src.Read(buffer, 0, buffer.Length);
dest.Write(buffer, 0, n);
} while (n != 0);
}
public static void CopyTo(this MemoryStream src, Stream dest)
{
dest.Write(src.GetBuffer(), (int)src.Position, (int)(src.Length - src.Position));
}
public static void CopyTo(this Stream src, MemoryStream dest)
{
if (src.CanSeek)
{
int pos = (int)dest.Position;
int length = (int)(src.Length - src.Position) + pos;
dest.SetLength(length);
while(pos < length)
pos += src.Read(dest.GetBuffer(), pos, length - pos);
}
else
src.CopyTo((Stream)dest);
}
"কপিরাইটস্ট্রিম" এর প্রয়োগগুলি পৃথক করে এমন প্রাথমিক প্রশ্নগুলি হ'ল:
এই প্রশ্নের উত্তরগুলি কপিরাইট স্ট্রিমের বিস্তৃতভাবে বিভিন্ন বাস্তবায়নের ফলাফল দেয় এবং আপনার কী ধরণের প্রবাহ রয়েছে এবং আপনি কী অনুকূলিত করার চেষ্টা করছেন তার উপর নির্ভরশীল। "সেরা" বাস্তবায়ন এমনকি স্ট্রিমগুলি কী নির্দিষ্ট হার্ডওয়্যারটি পড়ছে এবং কী লিখছিল তাও জানতে হবে।
একটি স্ট্রিম অনুলিপি করার আসলে ভারী হাতে কম উপায় way তবে খেয়াল রাখুন, এর দ্বারা বোঝা যাচ্ছে যে আপনি পুরো ফাইলটি মেমরিতে সঞ্চয় করতে পারেন। আপনি যদি সাবধানতা ছাড়াই কয়েকশ মেগাবাইট বা তার বেশি সংখ্যক ফাইলগুলিতে চলে এমন ফাইলগুলির সাথে কাজ করে থাকেন তবে এটি ব্যবহার করে দেখুন না।
public static void CopyStream(Stream input, Stream output)
{
using (StreamReader reader = new StreamReader(input))
using (StreamWriter writer = new StreamWriter(output))
{
writer.Write(reader.ReadToEnd());
}
}
দ্রষ্টব্য: বাইনারি ডেটা এবং চরিত্রের এনকোডিং সম্পর্কিত কিছু সমস্যাও থাকতে পারে।
reader.ReadToEnd()
সবকিছু র্যামে রাখে
। নেট ফ্রেমওয়ার্ক 4 সিস্টেমের স্ট্রিম ক্লাসের নতুন "কপিরাইটো" পদ্ধতিটি প্রবর্তন করে। এই পদ্ধতিটি ব্যবহার করে আমরা একটি স্ট্রিমকে বিভিন্ন স্ট্রিম শ্রেণির অন্য স্ট্রিমে অনুলিপি করতে পারি।
এখানে এর জন্য উদাহরণ।
FileStream objFileStream = File.Open(Server.MapPath("TextFile.txt"), FileMode.Open);
Response.Write(string.Format("FileStream Content length: {0}", objFileStream.Length.ToString()));
MemoryStream objMemoryStream = new MemoryStream();
// Copy File Stream to Memory Stream using CopyTo method
objFileStream.CopyTo(objMemoryStream);
Response.Write("<br/><br/>");
Response.Write(string.Format("MemoryStream Content length: {0}", objMemoryStream.Length.ToString()));
Response.Write("<br/><br/>");
CopyToAsync()
উত্সাহিত করা হয়।
দুর্ভাগ্যক্রমে, সত্যিকারের কোনও সহজ সমাধান নেই। আপনি এরকম কিছু চেষ্টা করতে পারেন:
Stream s1, s2;
byte[] buffer = new byte[4096];
int bytesRead = 0;
while (bytesRead = s1.Read(buffer, 0, buffer.Length) > 0) s2.Write(buffer, 0, bytesRead);
s1.Close(); s2.Close();
তবে স্ট্রিম শ্রেণীর বিভিন্ন প্রয়োগ বাস্তবায়নের সমস্যা যদি পড়ার মতো কিছু না থাকে তবে ভিন্ন আচরণ করতে পারে। স্থানীয় হার্ডড্রাইভ থেকে একটি ফাইল পড়ার একটি স্ট্রিম সম্ভবত বাফারটি পূরণ করার জন্য ডিস্ক থেকে পর্যাপ্ত ডেটা না পড়ার আগ পর্যন্ত অবরুদ্ধ হয়ে থাকবে এবং কেবল ফাইলের শেষের দিকে পৌঁছালে কেবল কম ডেটা ফেরত আসবে। অন্যদিকে, নেটওয়ার্ক থেকে স্ট্রিম রিডিং কম তথ্য ফেরত আসতে পারে যদিও আরও বেশি ডেটা পেতে বাকি রয়েছে।
জেনেরিক সমাধান ব্যবহার করার আগে আপনি যে নির্দিষ্ট স্ট্রিম শ্রেণিটি ব্যবহার করছেন তা সর্বদা ডকুমেন্টেশন চেক করুন।
আপনি কী ধরণের স্ট্রিমের সাথে কাজ করছেন তার উপর নির্ভর করে আরও দক্ষতার সাথে এটি করার একটি উপায় থাকতে পারে। আপনি যদি আপনার দুটি বা দুটি স্ট্রিমকে মেমোরিস্ট্রিমে রূপান্তর করতে পারেন তবে আপনি আপনার ডেটা উপস্থাপন করে বাইট অ্যারে দিয়ে সরাসরি কাজ করতে গেটবফার পদ্ধতিটি ব্যবহার করতে পারেন। এটি আপনাকে অ্যারে.কপিটিওর মতো পদ্ধতি ব্যবহার করতে দেয় যা ফ্রাইগাইবব দ্বারা উত্থাপিত সমস্ত বিষয়কে অ্যাবস্ট্রাক্ট করে। ডেটা অনুলিপি করার সর্বোত্তম উপায়টি জানতে আপনি নেটকে বিশ্বাস করতে পারেন।
যদি আপনি চান যে কোনও পোস্ট স্ট্রিমের কাছে অনুলিপি করা কপির জন্য ভাল আছে তবে নিকটি পোস্টটি রিসেট মিস করছে, এটি হওয়া উচিত
public static void CopyStream(Stream input, Stream output)
{
byte[] buffer = new byte[32768];
long TempPos = input.Position;
while (true)
{
int read = input.Read (buffer, 0, buffer.Length);
if (read <= 0)
return;
output.Write (buffer, 0, read);
}
input.Position = TempPos;// or you make Position = 0 to set it at the start
}
তবে এটি রানটাইমের ক্ষেত্রে যদি কোনও পদ্ধতি ব্যবহার না করে তবে আপনি মেমরি স্ট্রিম ব্যবহার করবেন না
Stream output = new MemoryStream();
byte[] buffer = new byte[32768]; // or you specify the size you want of your buffer
long TempPos = input.Position;
while (true)
{
int read = input.Read (buffer, 0, buffer.Length);
if (read <= 0)
return;
output.Write (buffer, 0, read);
}
input.Position = TempPos;// or you make Position = 0 to set it at the start
যেহেতু উত্তরগুলির কোনওটিই একটি ধারা থেকে অন্য প্রবাহে অনুলিপি করার একটি অ্যাসিনক্রোনাস উপায়কে আচ্ছাদন করে না, তাই এখানে একটি প্যাটার্ন যা আমি সফলভাবে একটি পোর্ট ফরওয়ার্ডিং অ্যাপ্লিকেশনটিতে একটি নেটওয়ার্ক স্ট্রিম থেকে অন্য নেটওয়ার্কে ডেটা অনুলিপি করতে ব্যবহার করেছি। প্যাটার্নটিতে জোর দেওয়ার জন্য এটি ব্যতিক্রম হ্যান্ডলিংয়ের অভাব রয়েছে।
const int BUFFER_SIZE = 4096;
static byte[] bufferForRead = new byte[BUFFER_SIZE];
static byte[] bufferForWrite = new byte[BUFFER_SIZE];
static Stream sourceStream = new MemoryStream();
static Stream destinationStream = new MemoryStream();
static void Main(string[] args)
{
// Initial read from source stream
sourceStream.BeginRead(bufferForRead, 0, BUFFER_SIZE, BeginReadCallback, null);
}
private static void BeginReadCallback(IAsyncResult asyncRes)
{
// Finish reading from source stream
int bytesRead = sourceStream.EndRead(asyncRes);
// Make a copy of the buffer as we'll start another read immediately
Array.Copy(bufferForRead, 0, bufferForWrite, 0, bytesRead);
// Write copied buffer to destination stream
destinationStream.BeginWrite(bufferForWrite, 0, bytesRead, BeginWriteCallback, null);
// Start the next read (looks like async recursion I guess)
sourceStream.BeginRead(bufferForRead, 0, BUFFER_SIZE, BeginReadCallback, null);
}
private static void BeginWriteCallback(IAsyncResult asyncRes)
{
// Finish writing to destination stream
destinationStream.EndWrite(asyncRes);
}
.NET 3.5 এর জন্য এবং চেষ্টা করার আগে:
MemoryStream1.WriteTo(MemoryStream2);
সহজ এবং নিরাপদ - মূল উত্স থেকে নতুন স্ট্রিম তৈরি করুন:
MemoryStream source = new MemoryStream(byteArray);
MemoryStream copy = new MemoryStream(byteArray);