Qual é o método preferido para criar uma matriz de bytes a partir de um fluxo de entrada?
Aqui está minha solução atual com o .NET 3.5.
Stream s;
byte[] b;
using (BinaryReader br = new BinaryReader(s))
{
b = br.ReadBytes((int)s.Length);
}
Ainda é uma idéia melhor ler e gravar trechos do fluxo?
c#
.net-3.5
inputstream
Prumo
fonte
fonte
Respostas:
Realmente depende se você pode ou não confiar
s.Length
. Para muitos fluxos, você simplesmente não sabe quantos dados haverá. Nesses casos - e antes do .NET 4 - eu usaria código como este:Com o .NET 4 e superior, eu usaria
Stream.CopyTo
, que é basicamente equivalente ao loop no meu código - crie aMemoryStream
chamada,stream.CopyTo(ms)
e depois retornems.ToArray()
. Tarefa concluída.Talvez eu devesse explicar por que minha resposta é mais longa que as outras.
Stream.Read
não garante que ele leia tudo o que for solicitado. Se você estiver lendo de um fluxo de rede, por exemplo, ele poderá ler o valor de um pacote e retornar, mesmo que em breve haja mais dados.BinaryReader.Read
continuará até o final do fluxo ou o tamanho especificado, mas você ainda precisa saber o tamanho para começar.O método acima continuará lendo (e copiando em a
MemoryStream
) até ficar sem dados. Em seguida, solicitaMemoryStream
que você retorne uma cópia dos dados em uma matriz. Se você sabe o tamanho para começar - ou acha que sabe o tamanho, sem ter certeza -, você podeMemoryStream
criar o tamanho que seja para começar. Da mesma forma, você pode marcar no final e, se o comprimento do fluxo for do mesmo tamanho do buffer (retornado porMemoryStream.GetBuffer
), basta retornar o buffer. Portanto, o código acima não é totalmente otimizado, mas pelo menos estará correto. Ele não assume nenhuma responsabilidade por fechar o fluxo - o chamador deve fazer isso.Consulte este artigo para obter mais informações (e uma implementação alternativa).
fonte
16*1024
especificamente?Enquanto a resposta de Jon está correta, ele está reescrevendo o código que já existe
CopyTo
. Portanto, para o .Net 4, use a solução de Sandip, mas para a versão anterior do .Net, use a resposta de Jon. O código de Sandip seria aprimorado pelo uso de "using", pois as exceçõesCopyTo
são, em muitas situações, bastante prováveis e deixariam osMemoryStream
não descartados.fonte
input
já é umMemorySteam
curto-circuito. Eu sei que seria estúpido o chamador passar umMemoryStream
mas ...MemoryStream
, em seguida, se a otimização faz sentido em seu contexto é a comparação do tempo necessário para fazer milhões de conversões de tipo contra o tempo necessário para copiar o que é umMemoryStream
em outroMemoryStream
.Só quero salientar que, caso você tenha um MemoryStream, já o possui
memorystream.ToArray()
.Além disso, se você estiver lidando com fluxos de subtipos desconhecidos ou diferentes e puder receber um
MemoryStream
, poderá retransmitir o referido método para esses casos e ainda usar a resposta aceita para os outros, assim:fonte
MemoryStream
s. É claro que o exemplo também está obviamente incompleto, na forma como está usando uma variável não inicializada.stream.Seek(1L, SeekOrigin.Begin)
, antes de chamar prontamente, se o fluxo for um fluxo de memória, você receberá 1 byte a mais do que se fosse qualquer outro fluxo. Se o chamador espera ler de onde a posição atual está no final do fluxo, você não deve usarCopyTo
ouToArray()
; Na maioria dos casos, isso não será um problema, mas se o chamador não souber sobre esse comportamento peculiar, ele ficará confuso.fonte
apenas alguns centavos ... a prática que costumo usar é organizar os métodos como este como um auxiliar personalizado
adicione espaço para nome ao arquivo de configuração e use-o em qualquer lugar que desejar
fonte
CopyTo
não estava disponívelStream
até 4.0.Você pode simplesmente usar o método ToArray () da classe MemoryStream, por exemplo,
fonte
Você pode até torná-lo mais sofisticado com extensões:
E, em seguida, chame-o como um método regular:
fonte
Eu recebo um erro de tempo de compilação com o código de Bob (ou seja, o questionador). Stream.Length é longo, enquanto BinaryReader.ReadBytes usa um parâmetro inteiro. No meu caso, não espero lidar com Streams grandes o suficiente para exigir precisão longa, portanto, uso o seguinte:
fonte
Caso alguém goste, aqui está uma solução somente .NET 4+ formada como um método de extensão sem a chamada desnecessária Dispose no MemoryStream. Essa é uma otimização irremediavelmente trivial, mas vale a pena notar que falhar em Dispose a MemoryStream não é uma falha real.
fonte
O que está acima está ok ... mas você encontrará corrupção de dados quando enviar coisas pelo SMTP (se necessário). Alterei para outra coisa que ajudará a enviar corretamente byte por byte: '
fonte
Crie uma classe auxiliar e faça referência a ela em qualquer lugar que você deseja usá-la.
fonte
No espaço de nomes RestSharp.Extensions, existe o método ReadAsBytes. Dentro desse método, é usado o MemoryStream e existe o mesmo código, como em alguns exemplos desta página, mas quando você está usando o RestSharp, é a maneira mais fácil.
fonte
Você pode usar este método de extensão.
fonte
Esta é a função que estou usando, testada e funcionou bem. lembre-se de que 'input' não deve ser nulo e 'input.position' deve ser redefinido para '0' antes da leitura, caso contrário, ele interromperá o loop de leitura e nada será lido para converter em array.
fonte
fonte
Consegui fazê-lo funcionar em uma única linha:
conforme esclarecido por johnnyRose , o código acima funcionará apenas para o MemoryStream
fonte
localStream
não for umMemoryStream
? Este código falhará.localStream
a umMemoryStream
, maslocalStream
é não umMemoryStream
, ele irá falhar. Esse código será compilado corretamente, mas poderá falhar no tempo de execução, dependendo do tipo real delocalStream
. Você nem sempre pode converter arbitrariamente um tipo base para um tipo filho; leia mais aqui . Este é outro bom exemplo que explica por que você nem sempre pode fazer isso.