Programing

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

lottogame 2020. 2. 12. 08:00
반응형

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


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


.NET 4.5부터는 Stream.CopyToAsync방법이 있습니다.

input.CopyToAsync(output);

Task완료되면 다음과 같이 계속할 수 있는를 반환합니다 .

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

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

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

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


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

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

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


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

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


작업중인 스트림 종류에 따라이 작업을보다 효율적으로 수행 할 수있는 방법이있을 수 있습니다. 스트림 중 하나 또는 둘 모두를 MemoryStream으로 변환 할 수있는 경우 GetBuffer 메서드를 사용하여 데이터를 나타내는 바이트 배열로 직접 작업 할 수 있습니다. 이를 통해 fryguybob이 제기 한 모든 문제를 추상화하는 Array.CopyTo와 같은 메소드를 사용할 수 있습니다. .NET을 신뢰하면 데이터를 복사하는 최적의 방법을 알 수 있습니다.


닉이 게시 된 다른 스트림으로 스트림을 복사하기위한 절차를 원하지만 위치 재설정이 누락 된 경우

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

참고 URL : https://stackoverflow.com/questions/230128/how-do-i-copy-the-contents-of-one-stream-to-another



반응형