Файл у байт [] на 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.