Mam serwer WWW, który odczytuje duże pliki binarne (kilka megabajtów) do tablic bajtów. Serwer może odczytywać kilka plików jednocześnie (różne żądania stron), więc szukam najbardziej zoptymalizowanego sposobu na zrobienie tego bez nadmiernego obciążania procesora. Czy poniższy kod jest wystarczająco dobry?
public byte[] FileToByteArray(string fileName)
{
byte[] buff = null;
FileStream fs = new FileStream(fileName,
FileMode.Open,
FileAccess.Read);
BinaryReader br = new BinaryReader(fs);
long numBytes = new FileInfo(fileName).Length;
buff = br.ReadBytes((int) numBytes);
return buff;
}
c#
.net
bytearray
binary-data
Tony_Henrich
źródło
źródło
byte[] buff = File.ReadAllBytes(fileName)
.Odpowiedzi:
Po prostu zamień całość na:
Jednakże, jeśli jesteś zaniepokojony zużycie pamięci, należy nie przeczytać cały plik do pamięci wszystkie naraz w ogóle. Powinieneś to zrobić w kawałkach.
źródło
Mógłbym argumentować, że odpowiedź tutaj ogólnie jest „nie”. O ile absolutnie nie potrzebujesz wszystkich danych naraz, rozważ użycie
Stream
opartego na interfejsie API (lub innego wariantu czytnika / iteratora). Jest to szczególnie ważne, gdy masz wiele równoległych operacji (jak sugeruje pytanie), aby zminimalizować obciążenie systemu i zmaksymalizować przepustowość.Na przykład, jeśli przesyłasz strumieniowo dane do dzwoniącego:
źródło
byte[]
, sugeruję, aby unikać korzystania ze strumieni lub czegokolwiek innego, a jedynie użyć interfejsu API dostarczonego przez system.File.ReadAllBytes
.Pomyślałbym tak:
źródło
Twój kod może być uwzględniony w tym (zamiast File.ReadAllBytes):
Zwróć uwagę na Integer.MaxValue - ograniczenie wielkości pliku wprowadzone metodą Read. Innymi słowy, możesz odczytać tylko 2 GB fragmentu jednocześnie.
Zauważ również, że ostatnim argumentem FileStream jest rozmiar bufora.
Sugerowałbym również przeczytanie o FileStream i BufferedStream .
Jak zawsze najkorzystniejszy będzie prosty przykładowy program do profilowania, który jest najszybszy.
Również podstawowy sprzęt będzie miał duży wpływ na wydajność. Czy używasz dysków twardych opartych na serwerze z dużymi pamięciami podręcznymi i kartą RAID z wbudowaną pamięcią podręczną? A może używasz standardowego napędu podłączonego do portu IDE?
źródło
var binaryReader = new BinaryReader(fs); fileData = binaryReader.ReadBytes((int)fs.Length);
w tymusing
oświadczeniu. Ale to faktycznie tak jak OP, po prostu wyciąłem wiersz kodu, rzutującfs.Length
naint
zamiast zamiastlong
wartościFileInfo
długości i konwertując to.W zależności od częstotliwości operacji, wielkości plików i liczby plików, które przeglądasz, należy wziąć pod uwagę inne problemy z wydajnością. Jedną rzeczą do zapamiętania jest to, że każda z twoich tablic bajtów zostanie zwolniona na łaskę śmieciarza. Jeśli nie buforujesz żadnych z tych danych, możesz stworzyć dużo śmieci i stracić większość wydajności na % Time w GC. Jeśli porcje są większe niż 85 KB, alokujesz do sterty dużych obiektów (LOH), która będzie wymagała kolekcji wszystkich pokoleń, aby się zwolnić (jest to bardzo kosztowne, a na serwerze przestanie się wykonywać podczas pracy ). Dodatkowo, jeśli masz mnóstwo obiektów na LOH, możesz skończyć z fragmentacją LOH (LOH nigdy nie jest kompaktowany), co prowadzi do niskiej wydajności i wyjątków braku pamięci. Możesz odzyskać ten proces, gdy osiągniesz określony punkt, ale nie wiem, czy to najlepsza praktyka.
Chodzi o to, że powinieneś wziąć pod uwagę pełny cykl życia aplikacji, zanim koniecznie po prostu wczytasz wszystkie bajty do pamięci najszybciej, jak to możliwe, lub możesz handlować wydajnością krótkoterminową dla ogólnej wydajności.
źródło
garbage collector
,chunks
, wydajność, liczniki zdarzeń ...Powiedziałbym, że
BinaryReader
jest w porządku, ale można to zmienić, zamiast tych wszystkich wierszy kodu służących do uzyskania długości bufora:Powinno być lepsze niż używanie
.ReadAllBytes()
, ponieważ widziałem w komentarzach na górze odpowiedzi, która zawiera,.ReadAllBytes()
że jeden z komentujących miał problemy z plikami> 600 MB, ponieważBinaryReader
jest przeznaczony do tego rodzaju rzeczy. Ponadto, wprowadzenie go wusing
oświadczeniu zapewnia, żeFileStream
iBinaryReader
są zamykane i usuwane.źródło
new
nie był tam potrzebny. Oddalony.W przypadku, gdy „duży plik” ma przekraczać limit 4 GB, moja następująca logika kodu jest odpowiednia. Kluczową kwestią, na którą należy zwrócić uwagę, jest typ danych LONG używany w metodzie SEEK. Jako LONG może wskazywać poza 2 ^ 32 granice danych. W tym przykładzie kod przetwarza najpierw przetwarzanie dużego pliku w porcjach 1 GB, po przetworzeniu dużych całych porcji 1 GB przetwarzane są pozostałe (<1 GB) bajty. Używam tego kodu do obliczania CRC plików przekraczających rozmiar 4 GB. (używając https://crc32c.machinezoo.com/ do obliczeń crc32c w tym przykładzie)
źródło
Użyj klasy BufferedStream w języku C #, aby poprawić wydajność. Bufor to blok bajtów w pamięci używany do buforowania danych, co zmniejsza liczbę wywołań systemu operacyjnego. Bufory poprawiają wydajność odczytu i zapisu.
Poniżej znajduje się przykład kodu i dodatkowe wyjaśnienie: http://msdn.microsoft.com/en-us/library/system.io.bufferedstream.aspx
źródło
BufferedStream
gdy czytasz całą rzecz na raz?Użyj tego:
źródło
Polecam wypróbować
Response.TransferFile()
metodę a następnieResponse.Flush()
iResponse.End()
do obsługi dużych plików.źródło
Jeśli masz do czynienia z plikami powyżej 2 GB, przekonasz się, że powyższe metody zawiodły.
O wiele łatwiej jest po prostu przekazać strumień do MD5 i pozwolić ci na podzielenie pliku za ciebie:
źródło