Файл у байт [] на Java


757

Як конвертувати a java.io.Fileв a byte[]?


Одне використання, яке я можу придумати, - це читання серіалізованих об'єктів з файлу.
— Mahm00d

2
Інший - знайти тип файлу за допомогою заголовка.
— Джеймс П.

Спробуйте цей байт [] байт = null; BufferedInputStream fileInputStream = null; спробуйте {File file = new File (filePath); fileInputStream = новий BufferedInputStream (новий FileInputStream (файл)); // fileInputStream = Thread.currentThread (). getContextClassLoader (). getResourceAsStream (this.filePath); байти = новий байт [(int) file.length ()]; fileInputStream.read (байти); } спіймання (FileNotFoundException ex) {кидок екс; }
— Рохіт Чаурасія

Відповіді:


486

Це залежить від того, що найкраще означає для вас. Не продумайте колеса та не використовуйте Apache Commons. Який тут IOUtils.toByteArray(InputStream input).


29
@ymajoros: Так правда! Я вважаю за краще мати кілька додаткових рядків коду, ніж ще одна залежність. Залежності мають приховані витрати. Вам потрібно бути в курсі цієї бібліотеки, включати залежність у сценарії побудови тощо, повідомляти про це людям, використовуючи ваш код тощо тощо. Якщо ви вже використовуєте бібліотеку, яка має код для неї, ніж користуватися нею, інше, я б сказав напишіть самі.
— Штійн де Вітт

11
Це відповідає на питання про те, як прочитати файл, але не на питання про те, як перетворити об’єкт типу java.IO.File у байт [].
— Інго

5
Як це використовується для читання Fileдо byte[]? Я використовую Java6, тому я не можу використовувати методи NIO :(
— ПАСТЕР

4
@ymajoros Ви б люб'язно поділилися з нами будь-яким "стандартним 3-рядковим рішенням", тож нам не доведеться покладатися на залежність від винаходи колеса?
— Маттео

3
@matteo: будь-який? Див. Інші відповіді, наприклад, Files.readAllBytes (). Просто, без залежності.
— ymajoros

1292

З 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());

10
У мене є об'єкт File, а не шлях (від запиту на пост http)
— aldo.roman.nurena

81
@ aldo.roman.nurena JDK7 представив метод File.toPath (), який дасть вам об’єкт Шлях.
— KevinL

6
Ви можете отримати шлях з файлу. Спробуйте: Файл файлу = новий файл ("/ шлях"); Шлях шляху = Paths.get (file.getAbsolutePath ()); байт [] дані = Files.readAllBytes (шлях);
— gfelisberto

2
Як обробляється закриття файлу в java.nio - іншими словами, чи повинен вищезазначений код щось закрити?
— akauppi

4
@akauppi Дивіться посилання у відповіді: "Метод забезпечує закриття файлу ..."
— Bernhard Barker

226

Оскільки JDK 7 - один вкладиш:

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

Жодні зовнішні залежності не потрібні.


13
Зараз це кращий вибір, ніж прийнята відповідь, яка вимагає Apache Commons.
— james.garriss

1
Дякую :) мені також знадобився цей: String text = new String (Files.readAllBytes (новий файл ("/ path / to / file"). ToPath ())); який родом з stackoverflow.com/a/26888713/1257959
— ВКТ

5
В Android для нього потрібен мінімальний рівень API
— Ashutosh Chamoli

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 (). Іноді може статися так, що ви не прочитаєте цілий файл.
— помилки_

8
Така ситуація може статися лише в тому випадку, якщо файл змінюється під час його читання. У всіх інших випадках IOException кидається. Для вирішення цієї проблеми пропоную відкрити файл у режимі читання-запису: RandomAccessFile (fileName, "rw")
— Дмитро Міцкевич

5
Я міг би уявити інші джерела лише для того, щоб прочитати частину файлу (Файл знаходиться в мережі) ... readFully () має контракт, який ви шукаєте.
— DThought

3
Пам'ятайте, що RandomAccessFile не є безпечним для потоків. Отже, синхронізація може знадобитися в деяких випадках.
— bancer

@DmitryMitskevich Є й інші випадки, що стосуються файлових систем, які, можливо, є невідповідними. наприклад, читання "файлів" в / proc / в Linux може спричинити коротке читання (тобто вам потрібна петля, щоб прочитати все це)
— нос

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).


ios потрібно оголосити за межами спроби
— Даріл Спітцер

Оператор "ios.read (буфер)" у другому прикладі буде читати лише в перших 4096 байтах файлу (припускаючи той самий 4k буфер, як і в першому прикладі). Щоб другий приклад працював, я думаю, що читання повинно знаходитись у циклі, який перевіряє результат на -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

Ви також можете використовувати NIO api. Я міг би зробити це за допомогою цього коду до тих пір, поки загальний розмір файлу (у байтах) вмістився б у цілому.

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.


2
абсолютно не потрібно використовувати відображення пам'яті, якщо ви збираєтесь прочитати файл лише один раз, і в кінцевому підсумку буде використано вдвічі більше пам'яті, ніж звичайний FileInputStream.
— Джеймс

1
На жаль, MappedByteBuffer не випускається автоматично.
— Том Хотін - тайклін

2
дивним, новий приклад включає printStackTrace, класичну обробку винятків.
— Джеймс

Я погоджуюсь. Її за замовчуванням ставлять затемнення. Я думаю, що я повинен перекинути виняток!
— Аміт

Ive був бенчмаркінг nio, щоб створити байт [] з файлу. Крім використання прямого буфера, це дійсно займає вдвічі більше пам’яті. Хоча це швидше для дуже великих файлів (приблизно вдвічі швидше, ніж буферизований IO на 200M), схоже, він втрачається в 5 разів для файлів близько 5М.
— 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;
    }

Також помістіть 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.
— Behr

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. Вам не доведеться винаходити колесо.


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();
}


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);
    }
  }
}

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);
        }
    }
}

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
Хоча цей код може забезпечити вирішення питання, краще додати контекст, чому / як він працює. Це може допомогти майбутнім користувачам навчитися та застосувати ці знання до власного коду. Ви також, ймовірно, отримаєте позитивні відгуки користувачів у вигляді оновлень, коли пояснюється код.
— borchvm

Ну, це важлива частина, яку я буду пам’ятати в майбутніх посадах. Дякуємо за вашу корисну інформацію.
— Усама Мехмуд

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, але дякую :)
— Matan Marciano

1
@MatanMarciano: моя погана
— Sapphire_Brick

-7

У JDK8

Stream<String> lines = Files.lines(path);
String data = lines.collect(Collectors.joining("\n"));
lines.close();

2
Прочитайте запитання мого французькомовного друга, він запитує про перехід на "байт []", і ваша відповідь цього не передбачає.
— Кайзер

2
Це не забезпечує навіть віддаленого варіанту відповіді за перетворення в байт []!
— Анддо
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.