Niezawodny sposób konwersji pliku na bajt []


84

Znalazłem następujący kod w sieci:

private byte [] StreamFile(string filename)
{
   FileStream fs = new FileStream(filename, FileMode.Open,FileAccess.Read);

   // Create a byte array of file stream length
   byte[] ImageData = new byte[fs.Length];

   //Read block of bytes from stream into the byte array
   fs.Read(ImageData,0,System.Convert.ToInt32(fs.Length));

   //Close the File Stream
   fs.Close();
   return ImageData; //return the byte data
}

Czy jest wystarczająco wiarygodne, aby przekonwertować plik na bajt [] w języku C #, czy jest lepszy sposób, aby to zrobić?


3
Powinieneś umieścić fs.Close()ostatnią część instrukcji try-last, która obejmuje resztę kodu, aby upewnić się, że Closejest faktycznie wywołana.
Joren

Odpowiedzi:


219
byte[] bytes = System.IO.File.ReadAllBytes(filename);

To powinno załatwić sprawę. ReadAllBytes otwiera plik, wczytuje jego zawartość do nowej tablicy bajtów, a następnie zamyka go. Oto strona MSDN dla tej metody.


Czy spowodowałoby to blokadę pliku?
JL.

Mam na myśli - czy po zapełnieniu bajtu [] plik nadal nie będzie zablokowany?
JL.

3
Nie, nie byłoby - plik jest zamykany, gdy tylko tablica bajtów zostanie zapełniona.
Erik Forbes

4
Jedynym drobnym problemem jest to, że jeśli masz duży plik (powiedzmy 500 MB lub 1 GB itp.), Przydzieli on tyle pamięci dla twojej tablicy bajtów. Dlatego czasami opłaca się zapętlić wokół .Read (..) i powoli je wyciągać. Oczywiście wszystko zależy od rozmiaru pliku. :)
Joshua

3
To się nie powiedzie, jeśli plik zostanie otwarty przez inny proces, metoda OP będzie działać z dodatkiem FileShare.ReadWriteafterFile.Read
Motes

28
byte[] bytes = File.ReadAllBytes(filename) 

lub ...

var bytes = File.ReadAllBytes(filename) 

13
Poważnie? „var” jest w tym przypadku jak najbardziej akceptowalny - typ zwrotu jest wyraźnie określony w nazwie metody ...
Erik Forbes

4
+1 za pierwotne użycie var. Osobiście uważam (i wielu innych), że należy go używać jak najczęściej. :) Faktycznie, sprawa była już kilkakrotnie omawiana na tej stronie.
Noldorin

8
Również +1 za używanie var ... @silky, myślę, że każdy może mieć opinię na temat tego, czy używać nowych funkcji językowych po ich wprowadzeniu, ale odrzucanie odpowiedzi, ponieważ nie jest ona zgodna z twoją opinią, nie jest o czym myślałem, że jest to forum. z pewnością ma to niewiele wspólnego z pytaniem JL.
Charles Bretana,

6
Myślę, że podczas głosowania w dół należy wziąć pod uwagę coś więcej niż osobiste preferencje. To jest całkowicie poprawna odpowiedź, z którą lub bez var. Wydaje mi się, że każdy programista, który musi ręcznie i jawnie przeliterować typy, pracuje na zbyt niskim poziomie abstrakcji. Nie powinno mieć znaczenia, jaki jest dokładny typ zmiennej, tylko do czego ona służy . Jeśli przechowuje bajty z pliku, to powinno mieć znaczenie. Nie czy jest to lista, czy tablica, czy MyCustomContainer.
jalf

8
Gdyby varw ogóle było istotne dla rzeczywistej odpowiedzi, spór o jego użycie miałby sens. Ale tutaj ważna część odpowiedzi jest sprawiedliwa File.ReadAllBytes(filename). To, jak i czy wynik jest przechowywany w zmiennej, jest tak samo nieistotne, jak nazewnictwo zmiennej lub spacja po =.
jalf

12

Nie powtarzać tego, co wszyscy już powiedzieli, ale trzymaj pod ręką następującą ściągawkę do manipulacji plikami:

  1. System.IO.File.ReadAllBytes(filename);
  2. File.Exists(filename)
  3. Path.Combine(folderName, resOfThePath);
  4. Path.GetFullPath(path); // converts a relative path to absolute one
  5. Path.GetExtension(path);

6

Wszystkie te odpowiedzi z .ReadAllBytes(). Kolejne, podobne (nie powiem duplikat, ponieważ próbowali refaktoryzować swój kod) zostało zadane na SO tutaj: Najlepszy sposób na odczytanie dużego pliku do tablicy bajtów w C #?

Do jednego z postów dodano komentarz dotyczący .ReadAllBytes():

File.ReadAllBytes throws OutOfMemoryException with big files (tested with 630 MB file 
and it failed) – juanjo.arana Mar 13 '13 at 1:31

Dla mnie lepszym podejściem byłoby coś takiego BinaryReader:

public static byte[] FileToByteArray(string fileName)
{
    byte[] fileData = null;

    using (FileStream fs = File.OpenRead(fileName)) 
    { 
        var binaryReader = new BinaryReader(fs); 
        fileData = binaryReader.ReadBytes((int)fs.Length); 
    }
    return fileData;
}

Ale to tylko ja ...

Oczywiście, wszystko to zakłada, że ​​masz pamięć do obsługi byte[]po wczytaniu, a nie File.Existssprawdziłem, czy plik istnieje przed kontynuowaniem, tak jak zrobiłbyś to przed wywołaniem tego kodu.


1
W twoim kodzie jest błąd, nie potrzebujesz nowego w instrukcji using, której musi używać (FileStream fs = File.OpenRead (fileName)
JoseR

Nie tyle błąd (wydaje mi się, że kod nadal by się kompilował), ale mimo to usunąłem go. Dobry chwyt.
vapcguy

3

wygląda wystarczająco dobrze jako wersja ogólna. Możesz go zmodyfikować, aby spełniał swoje potrzeby, jeśli są wystarczająco szczegółowe.

testuj również pod kątem wyjątków i warunków błędów, takich jak plik nie istnieje lub nie można go odczytać itp.

możesz także wykonać następujące czynności, aby zaoszczędzić miejsce:

 byte[] bytes = System.IO.File.ReadAllBytes(filename);

2

Inni zauważyli, że możesz użyć wbudowanego File.ReadAllBytes. Wbudowana metoda jest w porządku, ale warto zauważyć, że kod, który opublikujesz powyżej, jest delikatny z dwóch powodów:

  1. Streamis IDisposable- powinieneś umieścić FileStream fs = new FileStream(filename, FileMode.Open,FileAccess.Read)inicjalizację w klauzuli using, aby upewnić się, że plik jest zamknięty. Niezastosowanie się do tego może oznaczać, że strumień pozostanie otwarty, jeśli wystąpi awaria, co będzie oznaczać, że plik pozostanie zablokowany - a to może spowodować później inne problemy.
  2. fs.Readmoże czytać mniej bajtów niż żądasz. Ogólnie .Readmetoda Streaminstancji odczyta co najmniej jeden bajt, ale niekoniecznie wszystkie żądane bajty. Będziesz musiał napisać pętlę, która ponowi próbę odczytu do momentu odczytania wszystkich bajtów. Ta strona wyjaśnia to bardziej szczegółowo.
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.