입력 스트림에서 바이트 배열을 만드는 데 선호되는 방법은 무엇입니까?
다음은 .NET 3.5의 현재 솔루션입니다.
Stream s;
byte[] b;
using (BinaryReader br = new BinaryReader(s))
{
b = br.ReadBytes((int)s.Length);
}
스트림 덩어리를 읽고 쓰는 것이 여전히 더 좋은 아이디어입니까?
입력 스트림에서 바이트 배열을 만드는 데 선호되는 방법은 무엇입니까?
다음은 .NET 3.5의 현재 솔루션입니다.
Stream s;
byte[] b;
using (BinaryReader br = new BinaryReader(s))
{
b = br.ReadBytes((int)s.Length);
}
스트림 덩어리를 읽고 쓰는 것이 여전히 더 좋은 아이디어입니까?
답변:
그것은 당신이 믿을 수 있는지 아닌지에 달려 있습니다 s.Length
. 많은 스트림의 경우 얼마나 많은 데이터가 있는지 알 수 없습니다. 이러한 경우-.NET 4 이전-다음과 같은 코드를 사용합니다.
public static byte[] ReadFully(Stream input)
{
byte[] buffer = new byte[16*1024];
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
return ms.ToArray();
}
}
.NET 4 이상으로, 내가 사용하는 거라고 Stream.CopyTo
만들기 - 내 코드에서 루프 기본적으로 동등한 인 MemoryStream
, 전화를 stream.CopyTo(ms)
한 후 반환 ms.ToArray()
. 작업이 완료되었습니다.
왜 내 답변이 다른 답변보다 긴지 설명해야합니다. Stream.Read
요청한 모든 내용을 읽도록 보장하지는 않습니다. 예를 들어 네트워크 스트림에서 읽는 경우 더 많은 데이터가 있더라도 하나의 패킷 가치를 읽은 다음 반환 될 수 있습니다. BinaryReader.Read
스트림이 끝날 때까지 또는 지정된 크기까지 계속 진행되지만 시작하려면 크기를 알아야합니다.
위의 방법은 MemoryStream
데이터가 부족해질 때까지 계속 읽고 읽 습니다. 그런 다음 MemoryStream
데이터의 복사본을 배열로 반환 하도록 요청합니다 . 크기를 시작으로 알고 있거나 확실하지 않은 경우 크기를 알고 있다고 생각되면를 시작 MemoryStream
하기 위해 해당 크기가되도록 구성 할 수 있습니다 . 마찬가지로 끝에 검사를 할 수 있으며 스트림의 길이가 버퍼와 크기가 같으면 (로 반환 MemoryStream.GetBuffer
) 버퍼를 반환 할 수 있습니다. 따라서 위의 코드는 최적화되지 않았지만 적어도 정확합니다. 스트림을 닫을 책임은 없습니다. 호출자가 그렇게해야합니다.
자세한 내용 및 대체 구현에 대해서는 이 기사 를 참조하십시오 .
16*1024
구체적으로 물어봐도 될까요?
Jon의 답변은 정확하지만 이미 존재하는 코드를 다시 작성하고 있습니다 CopyTo
. 따라서 .Net 4의 경우 Sandip 솔루션을 사용하지만 이전 버전의 .Net의 경우 Jon의 답변을 사용하십시오. Sandip의 코드는 CopyTo
많은 상황에서 예외가 있을 가능성이 높고 MemoryStream
폐기되지 않은 채 "사용"을 사용하여 개선 될 것 입니다.
public static byte[] ReadFully(Stream input)
{
using (MemoryStream ms = new MemoryStream())
{
input.CopyTo(ms);
return ms.ToArray();
}
}
input
이미 MemorySteam
단락되어 있는지 확인하는 것이 좋습니다. 나는 발신자가 어리석은 짓을한다는 것을 알고 MemoryStream
있지만 ...
MemoryStream
다음 최적화가 당신의 맥락에서 의미가 있는지 여부의 하나 복사하는 데 걸리는 시간에 대해 형식 변환의 수백만을 수행하는 데 걸리는 시간을 비교 한 MemoryStream
로를 다른 MemoryStream
.
이미 가지고있는 MemoryStream이있는 memorystream.ToArray()
경우 지적하십시오.
또한 알려지지 않은 또는 다른 하위 유형의 스트림을 처리하고 있고를 수신 MemoryStream
할 수있는 경우 해당 경우에 대해 상기 방법을 중계하고 다른 방법에 대해 여전히 허용 된 답변을 사용할 수 있습니다.
public static byte[] StreamToByteArray(Stream stream)
{
if (stream is MemoryStream)
{
return ((MemoryStream)stream).ToArray();
}
else
{
// Jon Skeet's accepted answer
return ReadFully(stream);
}
}
MemoryStream
. 물론 예제는 초기화되지 않은 변수를 사용하는 방법에 있어서도 불완전합니다.
stream.Seek(1L, SeekOrigin.Begin)
당신은 내의 readFully 호출하기 전에 스트림은 메모리 스트림 인 경우, 당신은 다른 스트림의 경우 1보다 더 많은 바이트를 얻을 것이다. 호출자가 현재 위치가 스트림의 끝까지 인 곳에서 읽을 것으로 예상하는 경우 CopyTo
또는 ToArray()
; 대부분의 경우 이것은 문제가되지 않지만 호출자가이 기발한 동작에 대해 알지 못하면 혼동 될 것입니다.
MemoryStream ms = new MemoryStream();
file.PostedFile.InputStream.CopyTo(ms);
var byts = ms.ToArray();
ms.Dispose();
내 커플 센트 ... 내가 자주 사용하는 연습은 이와 같은 방법을 사용자 정의 도우미로 구성하는 것입니다.
public static class StreamHelpers
{
public static byte[] ReadFully(this Stream input)
{
using (MemoryStream ms = new MemoryStream())
{
input.CopyTo(ms);
return ms.ToArray();
}
}
}
구성 파일에 네임 스페이스를 추가하고 원하는 곳에서 사용하십시오.
CopyTo
사용할 수 없었으므로 .NET 3.5 이하에서는 작동 하지 않습니다 Stream
.
확장 기능으로 더 멋지게 만들 수도 있습니다.
namespace Foo
{
public static class Extensions
{
public static byte[] ToByteArray(this Stream stream)
{
using (stream)
{
using (MemoryStream memStream = new MemoryStream())
{
stream.CopyTo(memStream);
return memStream.ToArray();
}
}
}
}
}
그런 다음 일반 메소드로 호출하십시오.
byte[] arr = someStream.ToByteArray()
Bob 's (즉, 질문자) 코드에서 컴파일 시간 오류가 발생합니다. Stream.Length는 길지만 BinaryReader.ReadBytes는 정수 매개 변수를 사용합니다. 필자의 경우 긴 정밀도를 요구할만큼 충분히 큰 스트림을 처리 할 것으로 예상하지 않으므로 다음을 사용합니다.
Stream s;
byte[] b;
if (s.Length > int.MaxValue) {
throw new Exception("This stream is larger than the conversion algorithm can currently handle.");
}
using (var br = new BinaryReader(s)) {
b = br.ReadBytes((int)s.Length);
}
누구나 좋아하는 경우 MemoryStream에서 불필요한 Dispose 호출없이 확장 방법으로 형성된 .NET 4+ 전용 솔루션이 있습니다. 이것은 절망적으로 사소한 최적화이지만 MemoryStream을 처리하지 못하는 것이 실제로 실패하지는 않습니다.
public static class StreamHelpers
{
public static byte[] ReadFully(this Stream input)
{
var ms = new MemoryStream();
input.CopyTo(ms);
return ms.ToArray();
}
}
위의 내용은 괜찮습니다 ...하지만 SMTP를 통해 물건을 보내면 데이터가 손상됩니다 (필요한 경우). 바이트 바이트를 올바르게 보내는 데 도움이되는 다른 것으로 변경했습니다. '
using System;
using System.IO;
private static byte[] ReadFully(string input)
{
FileStream sourceFile = new FileStream(input, FileMode.Open); //Open streamer
BinaryReader binReader = new BinaryReader(sourceFile);
byte[] output = new byte[sourceFile.Length]; //create byte array of size file
for (long i = 0; i < sourceFile.Length; i++)
output[i] = binReader.ReadByte(); //read until done
sourceFile.Close(); //dispose streamer
binReader.Close(); //dispose reader
return output;
}'
네임 스페이스 RestSharp.Extensions에는 ReadAsBytes 메소드가 있습니다. 이 메서드 안에는 MemoryStream이 사용되고이 페이지의 일부 예제와 같은 코드가 있지만 RestSharp를 사용하는 경우 가장 쉬운 방법입니다.
using RestSharp.Extensions;
var byteArray = inputStream.ReadAsBytes();
이것은 내가 사용하고 테스트하고 잘 작동 한 기능입니다. 'input'은 null이 아니어야하며 'input.position'은 읽기 전에 '0'으로 재설정되어야합니다. 그렇지 않으면 읽기 루프가 중단되고 배열로 변환하기 위해 아무것도 읽지 않습니다.
public static byte[] StreamToByteArray(Stream input)
{
if (input == null)
return null;
byte[] buffer = new byte[16 * 1024];
input.Position = 0;
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
byte[] temp = ms.ToArray();
return temp;
}
}
public static byte[] ToByteArray(Stream stream)
{
if (stream is MemoryStream)
{
return ((MemoryStream)stream).ToArray();
}
else
{
byte[] buffer = new byte[16 * 1024];
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
return ms.ToArray();
}
}
}
한 줄로 작동시킬 수있었습니다.
byte [] byteArr= ((MemoryStream)localStream).ToArray();
johnnyRose 에 의해 명확하게 , 위의 코드는 MemoryStream에서만 작동합니다
localStream
않으면 MemoryStream
어떻게됩니까? 이 코드는 실패합니다.
localStream
A와 MemoryStream
있지만 localStream
입니다 하지MemoryStream
, 그것은 것입니다 실패합니다. 이 코드는 잘 컴파일되지만 실제 유형에 따라 런타임에 실패 할 수 localStream
있습니다. 항상 기본 유형을 하위 유형으로 캐스트 할 수는 없습니다. 자세한 내용은 여기를 참조하십시오 . 이것은 왜 항상 이것을 할 수 없는지 를 설명하는 또 다른 좋은 예 입니다 .