[C#] 한 스트림의 내용을 다른 스트림으로 어떻게 복사합니까?

한 스트림의 내용을 다른 스트림으로 복사하는 가장 좋은 방법은 무엇입니까? 이에 대한 표준 유틸리티 방법이 있습니까?



답변

.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이 발생합니다.


답변

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


답변

“CopyStream”의 구현을 차별화하는 기본 질문은 다음과 같습니다.

  • 판독 버퍼의 크기
  • 쓰기의 크기
  • 하나 이상의 스레드를 사용할 수 있습니까 (읽는 동안 쓰기).

이 질문에 대한 답변은 CopyStream의 구현 방식이 크게 다르며 어떤 종류의 스트림과 최적화하려는 스트림에 따라 다릅니다. “최상의”구현은 스트림이 읽고 쓰는 특정 하드웨어를 알아야합니다.


답변

실제로 스트림 복사를 수행하는 덜 무거운 방법이 있습니다. 그러나 이는 전체 파일을 메모리에 저장할 수 있음을 의미합니다. 주의없이 수백 메가 바이트 이상의 파일로 작업하는 경우에는 사용하지 마십시오.

public static void CopyStream(Stream input, Stream output)
{
  using (StreamReader reader = new StreamReader(input))
  using (StreamWriter writer = new StreamWriter(output))
  {
    writer.Write(reader.ReadToEnd());
  }
}

참고 : 이진 데이터 및 문자 인코딩과 관련하여 일부 문제가있을 수도 있습니다.


답변

.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/>");


답변

불행히도 실제로 간단한 해결책은 없습니다. 당신은 그런 것을 시도 할 수 있습니다 :

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 클래스의 다른 구현이 다르게 동작 할 수 있습니다. 로컬 하드 드라이브에서 파일을 읽는 스트림은 읽기 작업이 디스크에서 충분한 데이터를 읽어 버퍼를 채우고 파일 끝에 도달 할 때 더 적은 데이터 만 반환 할 때까지 차단 될 것입니다. 반면, 네트워크에서 읽는 스트림은 수신 할 데이터가 더 있어도 더 적은 데이터를 반환 할 수 있습니다.

일반 솔루션을 사용하기 전에 항상 사용중인 특정 스트림 클래스의 문서를 확인하십시오.