답변:
.NET 4.5부터는 Stream.CopyToAsync
방법이 있습니다.
input.CopyToAsync(output);
Task
완료되면 계속할 수있는 a 를 반환합니다 .
await input.CopyToAsync(output)
// Code from here on will be run in a continuation.
호출 위치에 따라 CopyToAsync
다음 코드는이를 호출 한 동일한 스레드에서 계속 될 수도 있고 그렇지 않을 수도 있습니다.
SynchronizationContext
호출 할 때 캡처 한 것을 await
계속이에 실행됩니다 스레드 결정됩니다.
또한이 호출 (및 변경 될 수있는 구현 세부 사항 임)은 여전히 읽기 및 쓰기 시퀀스를 수행합니다 (I / O 완료시 스레드 차단을 낭비하지 않습니다).
.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 :이 방법을 사용하면 진행 상황을보고 할 수 있습니다 (x 지금까지 읽은 바이트 수 ...)
참고 2 : 왜 고정 버퍼 크기를 사용 input.Length
합니까? 해당 길이를 사용하지 못할 수 있습니다! 로부터 문서 :
Stream에서 파생 된 클래스가 탐색을 지원하지 않으면 Length, SetLength, Position 및 Seek를 호출하면 NotSupportedException이 발생합니다.
81920
바이트가 아님32768
MemoryStream은 .WriteTo (outstream);
.NET 4.0에는 일반 스트림 객체에 .CopyTo가 있습니다.
.NET 4.0 :
instream.CopyTo(outstream);
다음 확장 방법을 사용합니다. 하나의 스트림이 MemoryStream 인 경우에 대해 과부하를 최적화했습니다.
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);
}
실제로 스트림 복사를 수행하는 덜 무거운 방법이 있습니다. 그러나 이는 전체 파일을 메모리에 저장할 수 있음을 의미합니다. 주의없이 수백 메가 바이트 이상의 파일로 작업하는 경우에는 사용하지 마십시오.
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()
RAM에 모든 것을 넣습니다
.NET Framework 4에는 System.IO 네임 스페이스의 스트림 클래스에 대한 새로운 "CopyTo"메서드가 도입되었습니다. 이 방법을 사용하면 한 스트림을 다른 스트림 클래스의 다른 스트림으로 복사 할 수 있습니다.
이에 대한 예는 다음과 같습니다.
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();
그러나 읽을 클래스가 없으면 Stream 클래스의 다른 구현이 다르게 동작 할 수 있습니다. 로컬 하드 드라이브에서 파일을 읽는 스트림은 읽기 작업이 디스크에서 충분한 데이터를 읽어 버퍼를 채우고 파일 끝에 도달 할 때 더 적은 데이터 만 반환 할 때까지 차단 될 것입니다. 반면, 네트워크에서 읽는 스트림은 수신 할 데이터가 더 있어도 더 적은 데이터를 반환 할 수 있습니다.
일반 솔루션을 사용하기 전에 항상 사용중인 특정 스트림 클래스의 문서를 확인하십시오.
닉이 게시 된 다른 스트림으로 스트림을 복사하기위한 절차를 원하지만 위치 재설정이 누락 된 경우
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);
}