Файл в байт [] в Java

757

Как я могу преобразовать java.io.Fileв byte[]?

Бен Ноланд
источник
Одно из возможных применений - чтение сериализованных объектов из файла.
Mahm00d
2
Другой - найти тип файла с помощью заголовка.
Джеймс П.
Попробуйте это byte [] bytes = null; BufferedInputStream fileInputStream = null; try {File file = новый файл (filePath); fileInputStream = новый BufferedInputStream (новый FileInputStream (файл)); // fileInputStream = Thread.currentThread (). getContextClassLoader (). getResourceAsStream (this.filePath); bytes = новый байт [(int) file.length ()]; fileInputStream.read (байт); } catch (FileNotFoundException ex) {throw ex; }
Рохит Чаурасия

Ответы:

486

Это зависит от того, что лучше для вас значит. Производительность мудрая, не изобретайте велосипед и используйте Apache Commons. Который здесь IOUtils.toByteArray(InputStream input).

svachon
источник
29
@ymajoros: так правда! Я предпочел бы иметь несколько дополнительных строк кода, чем еще одну зависимость. Зависимости имеют скрытые затраты. Вам нужно быть в курсе этой библиотеки, включать зависимости в свои скрипты сборки и т. Д., Сообщать об этом людям, использующим ваш код и т. Д. И т. Д. Если вы уже используете библиотеку, в которой есть код, чем ее используйте, в противном случае, я бы сказал, напиши это сам.
Стейн де Витт
11
Это отвечает на вопрос о том, как читать файл, но не на вопрос о том, как преобразовать объект типа java.IO.File в byte [].
Инго
5
Как это используется , чтобы читать , Fileчтобы byte[]? Я использую Java6, поэтому я не могу использовать методы NIO :(
PASTRY
4
@ymajoros, не могли бы вы поделиться с нами какими-либо «стандартными 3-строчными решениями», чтобы нам не приходилось полагаться на переосмысление зависимости?
Маттео
3
@matteo: любой? Смотрите другие ответы, например Files.readAllBytes (). Просто, без зависимости.
ymajoros
1293

С JDK 7 вы можете использовать Files.readAllBytes(Path).

Пример:

import java.io.File;
import java.nio.file.Files;

File file;
// ...(file is initialised)...
byte[] fileContent = Files.readAllBytes(file.toPath());
Michael Pollmeier
источник
10
У меня есть объект File, а не путь (из запроса HTTP http)
aldo.roman.nurena
82
@ aldo.roman.nurena JDK7 представил метод File.toPath (), который даст вам объект Path.
KevinL
7
Вы можете получить путь из файла. Попробуйте: Файл файл = новый файл ("/ путь"); Path path = Paths.get (file.getAbsolutePath ()); byte [] data = Files.readAllBytes (path);
gfelisberto
2
Как происходит закрытие файла в java.nio - другими словами, должен ли приведенный выше код что-то закрывать?
akauppi
4
@akauppi См. ссылку в ответе: «Метод обеспечивает закрытие файла ...»
Бернхард Баркер,
226

Начиная с JDK 7 - один лайнер:

byte[] array = Files.readAllBytes(Paths.get("/path/to/file"));

Внешние зависимости не нужны.

Паулюс Матулионис
источник
13
Теперь это лучший выбор, чем принятый ответ, который требует Apache Commons.
james.garriss
1
Спасибо :) Мне также был нужен этот: String text = new String (Files.readAllBytes (new File ("/ path / to / file"). ToPath ())); который первоначально от stackoverflow.com/a/26888713/1257959
cgl
5
В Android требуется минимальный уровень API, чтобы быть 26.
Ашутош Чамоли
2
Вам нужно будет добавить, import java.nio.file.Files;и import java.nio.file.Paths;если вы еще не сделали.
Сэм
164
import java.io.RandomAccessFile;
RandomAccessFile f = new RandomAccessFile(fileName, "r");
byte[] b = new byte[(int)f.length()];
f.readFully(b);

Документация для Java 8: http://docs.oracle.com/javase/8/docs/api/java/io/RandomAccessFile.html

Дмитрий Мицкевич
источник
2
Вы должны проверить возвращаемое значение f.read (). Иногда может случиться так, что вы не будете читать весь файл.
bugs_
8
Такая ситуация может возникнуть, только если файл меняется во время чтения. Во всех остальных случаях IOException выбрасывается. Для решения этой проблемы предлагаю открыть файл в режиме чтения-записи: RandomAccessFile (fileName, "rw")
Дмитрий Мицкевич
5
Я мог бы представить другие источники только для чтения части файла (Файл находится в общей сетевой папке ...) readFully () имеет контракт, который вы ищете.
Думал
3
Помните, что RandomAccessFile не является потокобезопасным. Поэтому в некоторых случаях может потребоваться синхронизация.
bancer
@DmitryMitskevich Есть и другие случаи на файловых системах, которые, возможно, не соответствуют. например, чтение «файлов» в / proc / on linux может вызвать короткие чтения (т. е. вам нужен цикл, чтобы прочитать все это)
nos
78

В основном вы должны прочитать это в памяти. Откройте файл, выделите массив и прочитайте содержимое файла в массив.

Самый простой способ - это что-то похожее на это:

public byte[] read(File file) throws IOException, FileTooBigException {
    if (file.length() > MAX_FILE_SIZE) {
        throw new FileTooBigException(file);
    }
    ByteArrayOutputStream ous = null;
    InputStream ios = null;
    try {
        byte[] buffer = new byte[4096];
        ous = new ByteArrayOutputStream();
        ios = new FileInputStream(file);
        int read = 0;
        while ((read = ios.read(buffer)) != -1) {
            ous.write(buffer, 0, read);
        }
    }finally {
        try {
            if (ous != null)
                ous.close();
        } catch (IOException e) {
        }

        try {
            if (ios != null)
                ios.close();
        } catch (IOException e) {
        }
    }
    return ous.toByteArray();
}

Это приводит к некоторому ненужному копированию содержимого файла (фактически данные копируются три раза: из файла в buffer, из, bufferв ByteArrayOutputStream, ByteArrayOutputStreamв реальный результирующий массив).

Вам также необходимо убедиться, что вы читаете в памяти только файлы определенного размера (обычно это зависит от приложения) :-).

Вы также должны относиться к IOExceptionвнешней функции.

Другой способ заключается в следующем:

public byte[] read(File file) throws IOException, FileTooBigException {
    if (file.length() > MAX_FILE_SIZE) {
        throw new FileTooBigException(file);
    }

    byte[] buffer = new byte[(int) file.length()];
    InputStream ios = null;
    try {
        ios = new FileInputStream(file);
        if (ios.read(buffer) == -1) {
            throw new IOException(
                    "EOF reached while trying to read the whole file");
        }
    } finally {
        try {
            if (ios != null)
                ios.close();
        } catch (IOException e) {
        }
    }
    return buffer;
}

Это не имеет ненужного копирования.

FileTooBigExceptionисключение пользовательского приложения. MAX_FILE_SIZEКонстанта AN параметры приложения.

Для больших файлов вы, вероятно, должны подумать об алгоритме обработки потока или использовать отображение памяти (см. java.nio).

Mihai Toader
источник
IOS должен быть объявлен вне попытки
Дэрил Спитцер
Оператор «ios.read (buffer)» во втором примере будет читать только первые 4096 байт файла (при условии, что используется тот же буфер 4 КБ, который использовался в первом примере). Чтобы второй пример работал, я думаю, что чтение должно быть внутри цикла while, который проверяет результат на -1 (достигнут конец файла).
Стейн де Витт
Извините, отклонил мое замечание выше, пропустил буфер настроек оператора по длине файла. Тем не менее, мне больше нравится первый пример. Чтение всего файла в буфер за один раз не масштабируется. Вы рискуете загорать из памяти, когда файл большой.
Стейн де Витт
«Самый простой» способ - использовать попытку с ресурсами.
Сина Мадани
Круто, но немного многословно.
Sapphire_Brick
77

Как кто-то сказал, Apache Commons File Utils может иметь то, что вы ищете

public static byte[] readFileToByteArray(File file) throws IOException

Пример использования ( Program.java):

import org.apache.commons.io.FileUtils;
public class Program {
    public static void main(String[] args) throws IOException {
        File file = new File(args[0]);  // assume args[0] is the path to file
        byte[] data = FileUtils.readFileToByteArray(file);
        ...
    }
}
Том
источник
23

Вы можете использовать API NIO, чтобы сделать это. Я мог бы сделать это с этим кодом до тех пор, пока общий размер файла (в байтах) поместится в int.

File f = new File("c:\\wscp.script");
FileInputStream fin = null;
FileChannel ch = null;
try {
    fin = new FileInputStream(f);
    ch = fin.getChannel();
    int size = (int) ch.size();
    MappedByteBuffer buf = ch.map(MapMode.READ_ONLY, 0, size);
    byte[] bytes = new byte[size];
    buf.get(bytes);

} catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
} finally {
    try {
        if (fin != null) {
            fin.close();
        }
        if (ch != null) {
            ch.close();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

Я думаю, что это очень быстро, так как использует MappedByteBuffer.

Amit
источник
2
абсолютно не нужно использовать отображение памяти, если вы собираетесь прочитать файл только один раз, и в итоге он будет использовать вдвое больше памяти, чем обычный FileInputStream.
Джеймс
1
К сожалению, MappedByteBuffer не выпускается автоматически.
Том Хотин - tackline
2
офигенно, новый пример включает printStackTrace, классическую обработку неработающих исключений.
Джеймс
Я согласен .. Это затмение по умолчанию, которое вставляет затмение. Я думаю, что я должен отбросить исключение!
Амит
Я тестировал nio, чтобы создать байт [] из файла. Помимо использования прямого буфера, он действительно занимает вдвое больше памяти. Хотя он работает быстрее для очень больших файлов (примерно в два раза быстрее, чем буферизованный ввод-вывод для 200M), он проигрывает в 5 раз для файлов около 5M.
Chaffers
22

Если у вас нет Java 8, и вы согласны со мной, что включение массивной библиотеки во избежание написания нескольких строк кода - плохая идея:

public static byte[] readBytes(InputStream inputStream) throws IOException {
    byte[] b = new byte[1024];
    ByteArrayOutputStream os = new ByteArrayOutputStream();
    int c;
    while ((c = inputStream.read(b)) != -1) {
        os.write(b, 0, c);
    }
    return os.toByteArray();
}

Абонент отвечает за закрытие потока.

Джеффри Блаттман
источник
21
// Returns the contents of the file in a byte array.
    public static byte[] getBytesFromFile(File file) throws IOException {        
        // Get the size of the file
        long length = file.length();

        // You cannot create an array using a long type.
        // It needs to be an int type.
        // Before converting to an int type, check
        // to ensure that file is not larger than Integer.MAX_VALUE.
        if (length > Integer.MAX_VALUE) {
            // File is too large
            throw new IOException("File is too large!");
        }

        // Create the byte array to hold the data
        byte[] bytes = new byte[(int)length];

        // Read in the bytes
        int offset = 0;
        int numRead = 0;

        InputStream is = new FileInputStream(file);
        try {
            while (offset < bytes.length
                   && (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
                offset += numRead;
            }
        } finally {
            is.close();
        }

        // Ensure all the bytes have been read in
        if (offset < bytes.length) {
            throw new IOException("Could not completely read file "+file.getName());
        }
        return bytes;
    }
Cuga
источник
Кроме того, поместите numRead внутри цикла. Объявите переменные в наименьшей допустимой области видимости. Помещение его вне цикла while необходимо только для включения этого сложного теста «while»; было бы лучше сделать тест на EOF внутри цикла (и выбросить EOFException, если это произойдет).
Эриксон
throw new IOException("File is too large!");что делать, если файл слишком большой? Есть ли еще пример?
Фер
21

Простой способ сделать это:

File fff = new File("/path/to/file");
FileInputStream fileInputStream = new FileInputStream(fff);

// int byteLength = fff.length(); 

// In android the result of file.length() is long
long byteLength = fff.length(); // byte count of the file-content

byte[] filecontent = new byte[(int) byteLength];
fileInputStream.read(filecontent, 0, (int) byteLength);
Судип Бхандари
источник
Есть более простые способы, такие как однострочники, которые уже упоминались.
Sapphire_Brick
@Sapphire_Brick Более простые способы да - но один лайнер не подходит для всех ситуаций. Таких как Android.
Бер
17

Самый простой способ чтения байтов из файла

import java.io.*;

class ReadBytesFromFile {
    public static void main(String args[]) throws Exception {
        // getBytes from anyWhere
        // I'm getting byte array from File
        File file = null;
        FileInputStream fileStream = new FileInputStream(file = new File("ByteArrayInputStreamClass.java"));

        // Instantiate array
        byte[] arr = new byte[(int) file.length()];

        // read All bytes of File stream
        fileStream.read(arr, 0, arr.length);

        for (int X : arr) {
            System.out.print((char) X);
        }
    }
}
Мухаммед Садик
источник
1
Я спорю о том, чтобы быть «самым простым путем» :)
BlondCode
Вы можете объяснить здесь? Почему вы спорите?
Мухаммед Садик
3
Ничего особенного, но вы говорите самое простое, и я вижу более простые решения -> на мой взгляд, это не самое простое. Может быть, это было пару лет назад, но мир меняется. Я бы не назвал свои собственные решения таким заявлением. ;) Если бы вы только написали: «На мой взгляд, самое простое - это ...» или «самое простое, что я нашел…». Не хочу вас беспокоить, просто подумайте, как приятно это донести.
BlondCode
@MuhammadSadiq: ничего не импортируйте .*, это считается плохой практикой.
Sapphire_Brick
13

У Guava есть Files.toByteArray (), чтобы предложить вам. У этого есть несколько преимуществ:

  1. Это покрывает угловой случай, когда файлы сообщают о длине 0, но все еще имеют содержание
  2. Он очень оптимизирован, вы получаете исключение OutOfMemoryException, если пытаетесь прочитать большой файл, даже не пытаясь загрузить файл. (Через умное использование file.length ())
  3. Вам не нужно изобретать велосипед.
jontejj
источник
12
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;

File file = getYourFile();
Path path = file.toPath();
byte[] data = Files.readAllBytes(path);
BlondCode
источник
Что это за уровень JDK?
Джонатан С. Фишер
11

Используя тот же подход, что и вики-ответ сообщества, но более чистый и компилируемый из коробки (предпочтительный подход, если вы не хотите импортировать библиотеки Apache Commons, например, на Android):

public static byte[] getFileBytes(File file) throws IOException {
    ByteArrayOutputStream ous = null;
    InputStream ios = null;
    try {
        byte[] buffer = new byte[4096];
        ous = new ByteArrayOutputStream();
        ios = new FileInputStream(file);
        int read = 0;
        while ((read = ios.read(buffer)) != -1)
            ous.write(buffer, 0, read);
    } finally {
        try {
            if (ous != null)
                ous.close();
        } catch (IOException e) {
            // swallow, since not that important
        }
        try {
            if (ios != null)
                ios.close();
        } catch (IOException e) {
            // swallow, since not that important
        }
    }
    return ous.toByteArray();
}
manmal
источник
8

Я считаю, что это самый простой способ:

org.apache.commons.io.FileUtils.readFileToByteArray(file);
Кристиан Тетик
источник
7
уже есть ответ с этим предложением от Тома в 2009 году
Кнут Херрманн
7

ReadFully Считывает байты b.length из этого файла в байтовый массив, начиная с текущего указателя файла. Этот метод читает несколько раз из файла, пока не будет прочитано запрошенное количество байтов. Этот метод блокируется до тех пор, пока не будет прочитано запрошенное количество байтов, не будет обнаружен конец потока или не сгенерировано исключение.

RandomAccessFile f = new RandomAccessFile(fileName, "r");
byte[] b = new byte[(int)f.length()];
f.readFully(b);
Тарун М
источник
5

Если вы хотите прочитать байты в заранее выделенный байтовый буфер, этот ответ может помочь.

Ваше первое предположение, вероятно, будет использовать InputStream read(byte[]). Однако этот метод имеет недостаток, который делает его неоправданно сложным: нет никакой гарантии, что массив будет фактически полностью заполнен, даже если EOF не обнаружен.

Вместо этого взгляните на DataInputStream readFully(byte[]). Это оболочка для входных потоков, которая не имеет вышеуказанной проблемы. Кроме того, этот метод выбрасывает при обнаружении EOF. Гораздо приятнее.

Лорен Хольст
источник
4

Мало того, что следующий способ преобразует файл java.io.File в байт [], я также обнаружил, что это самый быстрый способ чтения в файле при тестировании множества различных методов чтения Java-файлов. друг против друга:

java.nio.file.Files.readAllBytes ()

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;

public class ReadFile_Files_ReadAllBytes {
  public static void main(String [] pArgs) throws IOException {
    String fileName = "c:\\temp\\sample-10KB.txt";
    File file = new File(fileName);

    byte [] fileBytes = Files.readAllBytes(file.toPath());
    char singleChar;
    for(byte b : fileBytes) {
      singleChar = (char) b;
      System.out.print(singleChar);
    }
  }
}
gomisha
источник
3

Позвольте мне добавить другое решение без использования сторонних библиотек. Он повторно использует шаблон обработки исключений, который был предложен Скоттом ( ссылка ). И я переместил некрасивую часть в отдельное сообщение (я бы спрятался в каком-то классе FileUtils;))

public void someMethod() {
    final byte[] buffer = read(new File("test.txt"));
}

private byte[] read(final File file) {
    if (file.isDirectory())
        throw new RuntimeException("Unsupported operation, file "
                + file.getAbsolutePath() + " is a directory");
    if (file.length() > Integer.MAX_VALUE)
        throw new RuntimeException("Unsupported operation, file "
                + file.getAbsolutePath() + " is too big");

    Throwable pending = null;
    FileInputStream in = null;
    final byte buffer[] = new byte[(int) file.length()];
    try {
        in = new FileInputStream(file);
        in.read(buffer);
    } catch (Exception e) {
        pending = new RuntimeException("Exception occured on reading file "
                + file.getAbsolutePath(), e);
    } finally {
        if (in != null) {
            try {
                in.close();
            } catch (Exception e) {
                if (pending == null) {
                    pending = new RuntimeException(
                        "Exception occured on closing file" 
                             + file.getAbsolutePath(), e);
                }
            }
        }
        if (pending != null) {
            throw new RuntimeException(pending);
        }
    }
    return buffer;
}
Андреас Долк
источник
3
public static byte[] readBytes(InputStream inputStream) throws IOException {
    byte[] buffer = new byte[32 * 1024];
    int bufferSize = 0;
    for (;;) {
        int read = inputStream.read(buffer, bufferSize, buffer.length - bufferSize);
        if (read == -1) {
            return Arrays.copyOf(buffer, bufferSize);
        }
        bufferSize += read;
        if (bufferSize == buffer.length) {
            buffer = Arrays.copyOf(buffer, bufferSize * 2);
        }
    }
}
mazatwork
источник
1

Другой способ чтения байтов из файла

Reader reader = null;
    try {
        reader = new FileReader(file);
        char buf[] = new char[8192];
        int len;
        StringBuilder s = new StringBuilder();
        while ((len = reader.read(buf)) >= 0) {
            s.append(buf, 0, len);
            byte[] byteArray = s.toString().getBytes();
        }
    } catch(FileNotFoundException ex) {
    } catch(IOException e) {
    }
    finally {
        if (reader != null) {
            reader.close();
        }
    }
Мухаммед Амир Али
источник
не используйте пустотелые блоки это затрудняет отладку.
Sapphire_Brick
1
//The file that you wanna convert into byte[]
File file=new File("/storage/0CE2-EA3D/DCIM/Camera/VID_20190822_205931.mp4"); 

FileInputStream fileInputStream=new FileInputStream(file);
byte[] data=new byte[(int) file.length()];
BufferedInputStream bufferedInputStream=new BufferedInputStream(fileInputStream);
bufferedInputStream.read(data,0,data.length);

//Now the bytes of the file are contain in the "byte[] data"
Усама Мехмуд
источник
1
Хотя этот код может обеспечить решение вопроса, лучше добавить контекст относительно того, почему / как он работает. Это может помочь будущим пользователям учиться и применять эти знания в своем собственном коде. Вы также, вероятно, получите положительные отзывы от пользователей в виде откликов, когда код объясняется.
Борчвм
Ну, это важная часть, о которой я буду помнить в будущих постах. Спасибо за ваши полезные идеи.
Усама Мехмуд
0

Попробуй это :

import sun.misc.IOUtils;
import java.io.IOException;

try {
    String path="";
    InputStream inputStream=new FileInputStream(path);
    byte[] data=IOUtils.readFully(inputStream,-1,false);
}
catch (IOException e) {
    System.out.println(e);
}
Майфи Ул Асад
источник
Это требует определенной реализации JRE, которая сломает приложение, если оно будет запущено на другой JRE.
Ратаман
2
маленькая ошибка: это IOException, а не IOexception, но спасибо :)
Матан Марчиано
1
@MatanMarciano: мой плохой
Sapphire_Brick
-7

В JDK8

Stream<String> lines = Files.lines(path);
String data = lines.collect(Collectors.joining("\n"));
lines.close();
beaucequebec
источник
2
Прочитайте вопрос, мой франкоговорящий друг, он спрашивает о преобразовании в «байт []», а ваш ответ этого не дает.
Кайзер
2
Это не дает даже удаленной опции для ответа за преобразование в байт []!
Андо