Yanıtlar:
.NET 4.5'ten itibaren, Stream.CopyToAsync
yöntem var
input.CopyToAsync(output);
Bu, Task
tamamlandığında devam edebilecek bir şekilde geri dönecektir, şöyle:
await input.CopyToAsync(output)
// Code from here on will be run in a continuation.
Çağrının yapıldığı yere bağlı olarak CopyToAsync
, izleyen kodun onu çağıran aynı iş parçacığında devam edip etmeyebileceğini unutmayın.
SynchronizationContext
Çağrılırken yakalandığı await
devamı üzerinde yürütülecek iplik neyi belirleyecektir.
Ek olarak, bu çağrı (ve bu değişime tabi bir uygulama detayıdır) hala okuma ve yazma dizileri (sadece G / Ç tamamlanmasını engelleyen bir iş parçacığını boşa harcamaz).
.NET 4.0'dan itibaren, Stream.CopyTo
yöntem var
input.CopyTo(output);
.NET 3.5 ve öncesi için
Buna yardımcı olmak için çerçevede pişmiş hiçbir şey yoktur; içeriği manuel olarak kopyalamanız gerekir, şöyle:
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);
}
}
Not 1: Bu yöntem ilerlemeyi raporlamanıza izin verir (şimdiye kadar okunan x bayt ...)
Not 2: Neden sabit bir tampon boyutu kullanalım input.Length
? Çünkü bu Uzunluk mevcut olmayabilir! Gönderen docs :
Stream'den türetilen bir sınıf aramayı desteklemiyorsa, Length, SetLength, Position ve Seek çağrıları bir NotSupportedException özel durumu oluşturur.
81920
bayt değil,32768
MemoryStream öğesinde .WriteTo (akış dışı);
ve .NET 4.0 normal akış nesnesinde .CopyTo öğesine sahiptir.
.NET 4.0:
instream.CopyTo(outstream);
Aşağıdaki uzantı yöntemlerini kullanıyorum. Bir akış bir MemoryStream olduğunda aşırı yüklenmeleri optimize ettiler.
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);
}
"CopyStream" uygulamalarını farklılaştıran temel sorular şunlardır:
Bu soruların cevapları CopyStream'in çok farklı uygulamalarıyla sonuçlanır ve ne tür akışlara sahip olduğunuza ve neyi optimize etmeye çalıştığınıza bağlıdır. "En iyi" uygulamanın, akışların hangi belirli donanımı okuduğunu ve yazdığını bile bilmesi gerekir.
Aslında, bir kopyasını yapmanın daha az ağır bir yolu var. Ancak bunun tüm dosyayı bellekte saklayabileceğinizi unutmayın. Dikkatli olarak yüzlerce megabayt veya daha fazlasına giren dosyalarla çalışıyorsanız bunu denemeyin ve kullanmayın.
public static void CopyStream(Stream input, Stream output)
{
using (StreamReader reader = new StreamReader(input))
using (StreamWriter writer = new StreamWriter(output))
{
writer.Write(reader.ReadToEnd());
}
}
NOT: İkili veri ve karakter kodlamaları ile ilgili bazı sorunlar da olabilir.
reader.ReadToEnd()
her şeyi RAM'e koyar
.NET Framework 4, System.IO ad alanının Stream Class'ın yeni "CopyTo" yöntemini sunar. Bu yöntemi kullanarak bir akışı farklı akış sınıfının başka bir akışına kopyalayabiliriz.
İşte bunun için örnek.
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()
kullanımı teşvik edilir.
Ne yazık ki, gerçekten basit bir çözüm yok. Böyle bir şey deneyebilirsiniz:
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();
Ancak, okunacak hiçbir şey yoksa, Stream sınıfının farklı uygulamasının farklı davranabilmesiyle ilgili sorun. Yerel bir sabit sürücüden dosya okuyan bir akış, okuma işlemi diskten arabelleği dolduracak ve yalnızca dosya sonuna ulaştığında daha az veri döndürene kadar yeterli veri okuyana kadar engellenir. Öte yandan, ağdan okunan bir akım, alınacak daha fazla veri olmasına rağmen daha az veri döndürebilir.
Genel bir çözüm kullanmadan önce her zaman kullandığınız belirli sınıfın belgelerine bakın.
Hangi tür akışla çalıştığınıza bağlı olarak bunu daha verimli bir şekilde yapmanın bir yolu olabilir. Akışlarınızdan birini veya her ikisini MemoryStream'e dönüştürebiliyorsanız, doğrudan verilerinizi temsil eden bir bayt dizisiyle çalışmak için GetBuffer yöntemini kullanabilirsiniz. Bu, fryguybob tarafından ortaya atılan tüm sorunları soyutlayan Array.CopyTo gibi yöntemleri kullanmanıza izin verir. Verileri kopyalamanın en iyi yolunu bilmek için .NET'e güvenebilirsiniz.
bir prodüksiyonun bir yayını, nickin yayınladığı bir akışa kopyalamasını istiyorsanız, ancak konum sıfırlama eksikse,
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
}
ancak çalışma zamanında bir prosedür kullanmıyorsa, bellek akışını kullanmalısınız
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
Yanıtların hiçbiri bir akıştan diğerine eşzamanlı olmayan bir kopyalama yöntemi içermediğinden, burada bir bağlantı yönlendirme uygulamasında bir ağ akışından diğerine veri kopyalamak için başarıyla kullandığım bir model var. Deseni vurgulamak için istisna yönetimi yoktur.
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);
}
Kolay ve güvenli - orijinal kaynaktan yeni akış yapın:
MemoryStream source = new MemoryStream(byteArray);
MemoryStream copy = new MemoryStream(byteArray);