Надійний спосіб перетворення файлу в байт []


84

Я знайшов такий код в Інтернеті:

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
}

Чи достатньо його надійно використовувати для перетворення файлу в байт [] в c #, чи є кращий спосіб це зробити?


3
Ви повинні вставити fs.Close()останню частину оператора try-konačno, яка включає решту коду, щоб переконатися, що Closeвона справді викликана
Йорен

Відповіді:


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

Це повинно зробити трюк. ReadAllBytes відкриває файл, зчитує його вміст у новий байтовий масив, а потім закриває. Ось сторінка MSDN для цього методу.


Це спричинить блокування файлу?
JL.

Я маю на увазі - як тільки байт [] буде заповнений, файл все одно не буде заблокований?
JL.

3
Ні, не буде - файл закривається, як тільки заповнюється масив байтів.
Ерік Форбс,

4
Єдиною другорядною проблемою є те, що якщо у вас великий файл (скажімо, 500 МБ або 1 Гб тощо), він виділить стільки пам'яті для вашого байтового масиву. Тому іноді варто викрутити .Read (..) і повільно дістати його. Звичайно, все залежить від розміру вашого файлу. :)
Джошуа

3
Це не вдасться, якщо файл відкрито іншим процесом, метод OP працюватиме з додаванням FileShare.ReadWriteafterFile.Read
Motes

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

або ...

var bytes = File.ReadAllBytes(filename) 

13
Серйозно? 'var' є цілком прийнятним у цьому випадку - тип повернення чітко вказаний в назві методу ...
Ерік Форбс

4
+1 для початкового використання var. Це моя особиста думка (і думка багатьох інших), що її слід використовувати якомога більше. :) Справа вже кілька разів обговорювалась на цьому сайті.
Noldorin

8
Також +1 за використання var ... @silky, я думаю, кожен може вільно мати думку щодо того, використовувати чи не використовувати нові мовні функції, коли вони вводяться, але голосування проти, оскільки це не відповідає вашій думці, не є про що я думав, про цей форум. це, звичайно, має мало спільного з питаннями JLs.
Чарльз Бретана

6
Думаю, під час голосування ви повинні враховувати не лише власні переваги. Це цілком вірна відповідь, з або без var. Я схильний думати, що будь-який програміст, якому потрібно вручну і чітко прописати типи, працює на занадто низькому рівні абстракції. Це не повинно важливо те , що точний тип змінної, тільки те , що змінна для . Якщо він зберігає байти з файлу, то це повинно бути важливим. Не те, чи це Список, чи Масив, чи MyCustomContainer.
jalf

8
Якби це varвзагалі мало відношення до фактичної відповіді, суперечка щодо його використання мала б сенс. Але тут важлива частина відповіді справедлива File.ReadAllBytes(filename). Те, як і якщо результат зберігається у змінній, не має значення, як іменування змінної або пробіл після =.
jalf

12

Щоб не повторювати те, що вже всі говорили, але зберігайте наступну шпаргалку для маніпуляцій з файлами:

  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

Всі ці відповіді з .ReadAllBytes(). Ще одне, подібне (я не скажу дублікат, оскільки вони намагалися реформувати свій код) тут було задано SO: Найкращий спосіб прочитати великий файл у байтовий масив у C #?

Був зроблений коментар до одного з дописів щодо .ReadAllBytes():

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

Для мене кращим підходом буде щось на зразок цього, з 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;
}

Але це тільки я ...

Звичайно, все це передбачає, що у вас є пам’ять для обробки byte[]після її читання, і я не поставив File.Existsчек, щоб переконатись, що файл є, перед тим, як продовжити, як ви це зробили б до виклику цього коду.


1
У вашому коді сталася помилка, вам не потрібно нове в операторі using, який він повинен використовувати (FileStream fs = File.OpenRead (fileName)
JoseR

Не стільки помилка (я вважаю, що код все одно скомпілюється), але я все одно видалив її. Хороший улов.
vapcguy,

3

виглядає досить добре як загальна версія. Ви можете змінити його відповідно до своїх потреб, якщо вони досить конкретні.

також перевірити на винятки та умови помилок, таких як файл не існує або його неможливо прочитати тощо.

Ви також можете зробити наступне, щоб заощадити трохи місця:

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

2

Інші відзначали, що ви можете використовувати вбудований File.ReadAllBytes. Вбудований метод чудовий, але варто зазначити, що код, який ви розміщуєте вище, є неміцним з двох причин:

  1. Streamє IDisposable- вам слід розмістити FileStream fs = new FileStream(filename, FileMode.Open,FileAccess.Read)ініціалізацію у фразі using, щоб переконатися, що файл закритий. Якщо цього не зробити, це може означати, що потік залишається відкритим, якщо сталася помилка, що означатиме, що файл залишається заблокованим - і це може спричинити інші проблеми пізніше.
  2. fs.Readможе прочитати менше байтів, ніж ви вимагаєте. Як правило, .Readметод Streamекземпляра буде читати принаймні один байт, але не обов’язково всі байти, про які ви просите. Вам потрібно буде написати цикл, який повторюватиме читання, поки не будуть прочитані всі байти. Ця сторінка пояснює це більш докладно.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.