Jaka jest preferowana metoda tworzenia tablicy bajtów ze strumienia wejściowego?
Oto moje obecne rozwiązanie z .NET 3.5.
Stream s;
byte[] b;
using (BinaryReader br = new BinaryReader(s))
{
b = br.ReadBytes((int)s.Length);
}
Czy nadal lepiej jest czytać i pisać fragmenty strumienia?
c#
.net-3.5
inputstream
Kok
źródło
źródło
Odpowiedzi:
To naprawdę zależy od tego, czy możesz zaufać
s.Length
. W przypadku wielu strumieni po prostu nie wiesz, ile będzie danych. W takich przypadkach - i wcześniej .NET 4 - użyłbym takiego kodu:W .NET 4 i nowszych użyłbym
Stream.CopyTo
, co w zasadzie jest równoważne pętli w moim kodzie - utwórzMemoryStream
, wywołaj,stream.CopyTo(ms)
a następnie zwróćms.ToArray()
. Zadanie wykonane.Być może powinienem wyjaśnić, dlaczego moja odpowiedź jest dłuższa niż inne.
Stream.Read
nie gwarantuje, że przeczyta wszystko, o co prosi. Jeśli na przykład czytasz ze strumienia sieciowego, może on odczytać wartość jednego pakietu, a następnie powrócić, nawet jeśli wkrótce będzie więcej danych.BinaryReader.Read
będzie działać do końca strumienia lub określonego rozmiaru, ale nadal musisz znać rozmiar, aby zacząć.Powyższa metoda będzie odczytywać (i kopiować do a
MemoryStream
), dopóki nie zabraknie danych. Następnie prosiMemoryStream
o zwrócenie kopii danych w tablicy. Jeśli znasz rozmiar na początek - lub uważasz, że znasz rozmiar, bez pewności - możesz skonstruowaćMemoryStream
taki rozmiar, aby zacząć. Podobnie możesz umieścić czek na końcu, a jeśli długość strumienia jest tego samego rozmiaru co bufor (zwracany przezMemoryStream.GetBuffer
), możesz po prostu zwrócić bufor. Tak więc powyższy kod nie jest do końca zoptymalizowany, ale przynajmniej będzie poprawny. Nie ponosi żadnej odpowiedzialności za zamknięcie strumienia - dzwoniący powinien to zrobić.Zobacz ten artykuł, aby uzyskać więcej informacji (i alternatywną implementację).
źródło
16*1024
konkretnie?Chociaż odpowiedź Jona jest poprawna, przepisuje on kod, który już istnieje
CopyTo
. Tak więc dla .Net 4 użyj rozwiązania Sandip, ale dla poprzedniej wersji .Net użyj odpowiedzi Jona. Kod Sandip zostałby ulepszony poprzez użycie „using”, ponieważ w wyjątkowych sytuacjach wyjątkiCopyTo
są w wielu przypadkach dość prawdopodobne i pozostawiłbyMemoryStream
niezbywalne.źródło
input
jest jużMemorySteam
zwarty. Wiem, że głupio byłoby, gdyby osoba dzwoniąca zdałaMemoryStream
ale ...MemoryStream
to, czy optymalizacja ma sens w twoim kontekście, to porównanie czasu potrzebnego do wykonania milionów konwersji typów z czasem potrzebnym na skopiowanie tego, który jestMemoryStream
w innyMemoryStream
.Chcę tylko zaznaczyć, że w przypadku, gdy masz MemoryStream, już to masz
memorystream.ToArray()
.Ponadto, jeśli masz do czynienia ze strumieniami nieznanych lub różnych podtypów i możesz otrzymać a
MemoryStream
, możesz polegać na tej metodzie w tych przypadkach i nadal używać przyjętej odpowiedzi dla innych, takich jak:źródło
MemoryStream
. Oczywiście przykład jest oczywiście niekompletny, ponieważ używa niezainicjowanej zmiennej.stream.Seek(1L, SeekOrigin.Begin)
, zanim zechcesz wywołać, jeśli strumień jest strumieniem pamięci, otrzymasz 1 bajt więcej niż w przypadku jakiegokolwiek innego strumienia. Jeśli dzwoniący spodziewa się odczytać z miejsca, w którym znajduje się bieżąca pozycja, do końca strumienia, nie wolno używaćCopyTo
lubToArray()
; W większości przypadków nie będzie to stanowić problemu, ale jeśli dzwoniący nie będzie wiedział o tym dziwnym zachowaniu, będzie zdezorientowany.źródło
tylko moja para centów ... praktyką, której często używam jest organizowanie takich metod jako niestandardowego pomocnika
dodaj przestrzeń nazw do pliku konfiguracyjnego i używaj go w dowolnym miejscu
źródło
CopyTo
wersjach, ponieważ nie było dostępneStream
do 4.0.Możesz po prostu użyć metody ToArray () klasy MemoryStream, np.
źródło
Możesz nawet uczynić go bardziej eleganckim dzięki rozszerzeniom:
A następnie nazwij to jako zwykłą metodę:
źródło
Dostaję błąd czasu kompilacji z kodem Boba (tj. Pytającego). Stream.Length jest długi, natomiast BinaryReader.ReadBytes przyjmuje parametr w postaci liczby całkowitej. W moim przypadku nie oczekuję, że będę mieć do czynienia ze strumieniami wystarczająco dużymi, aby wymagać długiej precyzji, dlatego używam następujących elementów:
źródło
Jeśli komuś się spodoba, oto rozwiązanie oparte wyłącznie na .NET 4+ utworzone jako metoda rozszerzenia bez niepotrzebnego wywołania Dispose w MemoryStream. Jest to beznadziejnie trywialna optymalizacja, ale warto zauważyć, że nieusunięcie MemoryStream nie jest prawdziwą porażką.
źródło
Powyższe jest w porządku ... ale podczas wysyłania danych przez SMTP (jeśli to konieczne) napotkasz uszkodzenie danych. Zmieniłem na coś innego, co pomoże poprawnie przesłać bajt po bajcie: '
źródło
Utwórz klasę pomocnika i odwołaj się do niej w dowolnym miejscu, w którym chcesz jej użyć.
źródło
W przestrzeni nazw RestSharp.Extensions znajduje się metoda ReadAsBytes. Wewnątrz tej metody zastosowano MemoryStream i jest taki sam kod jak w niektórych przykładach na tej stronie, ale gdy używasz RestSharp, jest to najłatwiejszy sposób.
źródło
Możesz użyć tej metody rozszerzenia.
źródło
Jest to funkcja, której używam, przetestowałem i działałem dobrze. pamiętaj, że „wejście” nie powinno mieć wartości zerowej, a „wejście.pozycjonowanie” powinno zostać zresetowane do „0” przed odczytem, w przeciwnym razie przerwie to pętlę odczytu i nic nie będzie czytać w celu konwersji na tablicę.
źródło
źródło
udało mi się sprawić, że będzie działać na jednej linii:
jak wyjaśnił johnnyRose , powyższy kod będzie działał tylko dla MemoryStream
źródło
localStream
nie jestMemoryStream
? Ten kod zawiedzie.localStream
do AMemoryStream
, alelocalStream
to nieMemoryStream
, to będzie zawieść. Ten kod kompiluje się dobrze, ale może się nie powieść w czasie wykonywania, w zależności od faktycznego typulocalStream
. Nie zawsze możesz arbitralnie rzutować typ podstawowy na typ potomny; czytaj więcej tutaj . To kolejny dobry przykład, który wyjaśnia, dlaczego nie zawsze możesz to zrobić.