File su byte [] in Java


757

Come faccio a convertire a java.io.Filein a byte[]?


Un uso che mi viene in mente è la lettura di oggetti serializzati da file.
Mahm00d

2
Un altro è trovare il tipo di file usando l'intestazione.
James P.

Prova questo byte [] bytes = null; BufferedInputStream fileInputStream = null; provare {File file = new File (filePath); fileInputStream = new BufferedInputStream (new FileInputStream (file)); // fileInputStream = Thread.currentThread (). getContextClassLoader (). getResourceAsStream (this.filePath); bytes = new byte [(int) file.length ()]; fileInputStream.read (bytes); } catch (FileNotFoundException ex) {throw ex; }
Rohit Chaurasiya il

Risposte:


486

Dipende da cosa significa meglio per te. Per quanto riguarda la produttività, non reinventare la ruota e utilizzare Apache Commons. Che è qui IOUtils.toByteArray(InputStream input).


29
@ymajoros: così vero! Preferirei avere alcune righe di codice aggiuntive rispetto a un'altra dipendenza. Le dipendenze hanno costi nascosti. Devi rimanere aggiornato con quella libreria, includere la dipendenza nel tuo script di compilazione, ecc., Comunicarlo alle persone che usano il tuo codice, ecc. Se stai già utilizzando una libreria che ha un codice per esso, piuttosto che usarlo, direi altro scrivilo tu stesso.
Stijn de Witt,

11
Questo risponde alla domanda su come leggere un file, ma non alla domanda su come convertire un oggetto di tipo java.IO.File in byte [].
Ingo,

5
Come si usa questo per leggere un Filea byte[]? Sto usando Java6 quindi non posso usare i metodi NIO :(
PASTRY

4
@ymajoros condivideresti gentilmente qualsiasi "soluzione standard a 3 linee" con noi, quindi non dobbiamo fare affidamento su una dipendenza da reinventare la ruota?
matteo,

3
@matteo: any? Vedi altre risposte, ad esempio Files.readAllBytes (). Semplice, nessuna dipendenza.
ymajoros,

1293

Da JDK 7 puoi usare Files.readAllBytes(Path).

Esempio:

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

File file;
// ...(file is initialised)...
byte[] fileContent = Files.readAllBytes(file.toPath());

10
Ho un oggetto File, non un percorso (da richiesta post http)
aldo.roman.nurena,

81
@ aldo.roman.nurena JDK7 ha introdotto un metodo File.toPath () che ti darà un oggetto Path.
KevinL

6
È possibile ottenere un percorso da un file. Prova: File file = new File ("/ path"); Path path = Paths.get (file.getAbsolutePath ()); byte [] data = Files.readAllBytes (percorso);
gfelisberto,

2
Come viene gestita la chiusura del file in java.nio - in altre parole, il codice sopra dovrebbe chiudere qualcosa?
akauppi,

4
@akauppi Vedi il link nella risposta: "Il metodo assicura che il file sia chiuso ..."
Bernhard Barker

226

Dal JDK 7 - una fodera:

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

Non sono necessarie dipendenze esterne.


13
Questa è ora una scelta migliore rispetto alla risposta accettata, che richiede Apache Commons.
james.garriss,

1
Grazie :) Ne avevo anche bisogno: String text = new String (Files.readAllBytes (new File ("/ path / to / file"). ToPath ())); che è originario di stackoverflow.com/a/26888713/1257959
CGL

5
In Android, il livello minimo dell'API deve essere 26.
Ashutosh Chamoli

2
Dovrai aggiungere import java.nio.file.Files;e import java.nio.file.Paths;se non l'hai già fatto.
Sam,

164
import java.io.RandomAccessFile;
RandomAccessFile f = new RandomAccessFile(fileName, "r");
byte[] b = new byte[(int)f.length()];
f.readFully(b);

Documentazione per Java 8: http://docs.oracle.com/javase/8/docs/api/java/io/RandomAccessFile.html


2
Devi controllare il valore di ritorno di f.read (). Qui a volte può succedere che non leggerai l'intero file.
bugs_

8
Tale situazione può verificarsi solo se il file cambia mentre lo stai leggendo. In tutti gli altri casi viene generata IOException. Per risolvere questo problema, suggerisco di aprire il file in modalità lettura-scrittura: RandomAccessFile (fileName, "rw")
Dmitry Mitskevich,

5
Potrei immaginare altre fonti per la sola lettura di una parte del file (il file è su una condivisione di rete ...) readFully () ha il contratto che stai cercando.
DT Pensato

3
Ricorda che RandomAccessFile non è thread-safe. Pertanto, in alcuni casi potrebbe essere necessaria la sincronizzazione.
bancer

@DmitryMitskevich Esistono anche altri casi, su filesystem che potrebbero non essere conformi. es. la lettura di "file" in / proc / su linux può causare brevi letture (cioè è necessario un ciclo per leggere tutto)
nn

78

Fondamentalmente devi leggerlo in memoria. Aprire il file, allocare l'array e leggere i contenuti dal file nell'array.

Il modo più semplice è qualcosa di simile a questo:

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

Questo ha una copia non necessaria del contenuto del file (in realtà i dati vengono copiati tre volte: dal file al buffer, dal bufferal ByteArrayOutputStream, ByteArrayOutputStreamdall'array risultante effettivo).

Devi anche assicurarti di leggere in memoria solo i file fino a una certa dimensione (di solito dipende dall'applicazione) :-).

È inoltre necessario trattare l' IOExceptionesterno della funzione.

Un altro modo è questo:

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

Non ci sono copie non necessarie.

FileTooBigExceptionè un'eccezione dell'applicazione personalizzata. La MAX_FILE_SIZEcostante è un parametro dell'applicazione.

Per i file di grandi dimensioni dovresti probabilmente pensare a un algoritmo di elaborazione del flusso o utilizzare la mappatura della memoria (vedi java.nio).


iOS deve essere dichiarato al di fuori del tentativo
Daryl Spitzer l'

L'istruzione "ios.read (buffer)" nel secondo esempio leggerà solo nei primi 4096 byte del file (assumendo lo stesso buffer 4k usato nel primo esempio). Perché il secondo esempio funzioni, penso che la lettura debba essere all'interno di un ciclo while che controlla il risultato per -1 (fine del file raggiunta).
Stijn de Witt,

Spiacenti, elimina la mia osservazione sopra, manca il buffer di impostazione dell'istruzione per la lunghezza del file. Tuttavia, mi piace di più il primo esempio. La lettura di un intero file in un buffer in una volta sola non è scalabile. Rischerai di esplodere dalla memoria quando il file è grande.
Stijn de Witt,

Il modo "più semplice" farebbe uso di risorse di prova.
Sina Madani,

Bello, ma un po 'prolisso.
Sapphire_Brick,

77

Come qualcuno ha detto, Apache Commons File Utils potrebbe avere quello che stai cercando

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

Esempio di utilizzo ( 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

Puoi usare anche l'API NIO per farlo. Potrei farlo con questo codice purché la dimensione totale del file (in byte) si adatterà a un 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();
    }
}

Penso che sia molto veloce dal momento che utilizza MappedByteBuffer.


2
non è assolutamente necessario utilizzare la mappatura della memoria se si intende leggere il file solo una volta e finirà per utilizzare il doppio della memoria rispetto a un normale FileInputStream.
James,

1
Sfortunatamente MappedByteBuffer non viene rilasciato automaticamente.
Tom Hawtin - tackline

2
fantastico, il nuovo esempio include printStackTrace, la classica gestione delle eccezioni interrotte.
James,

Sono d'accordo .. È la roba di default che inserisce eclipse. Penso che dovrei riproporre l'eccezione!
Entro

Ho testato il benchmark nio per creare un byte [] da un file. Oltre all'utilizzo di un buffer diretto, occupa effettivamente il doppio della memoria. Anche se è più veloce per file molto grandi (circa due volte più veloce di un IO bufferizzato per 200M) sembra perdere un fattore 5 per i file intorno a 5M.
Chaffers,

22

Se non hai Java 8, e sei d'accordo con me sul fatto che includere una libreria enorme per evitare di scrivere alcune righe di codice è una cattiva idea:

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

Il chiamante è responsabile della chiusura del flusso.


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

Inoltre, inserisci numRead all'interno del loop. Dichiarare le variabili nel più piccolo ambito valido possibile. Metterlo al di fuori del ciclo while è necessario solo per abilitare quel complicato test "while"; sarebbe meglio fare il test per EOF all'interno del loop (e lanciare una EOFException se si verifica).
Erickson,

throw new IOException("File is too large!");cosa dovremmo fare quando il file è troppo grande? C'è anche qualche esempio al riguardo?
Fer,

21

Modo semplice per farlo:

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

Esistono modi più semplici, come quelli a linea singola che sono già stati menzionati.
Sapphire_Brick,

@Sapphire_Brick Modi più semplici sì, ma i liner non si adattano a tutte le situazioni. Come Android.
Behr,

17

Modo più semplice per leggere byte dal file

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
Sostengo di essere il "modo più semplice" :)
BlondCode

Puoi spiegare qui? Perché hai una discussione?
Muhammad Sadiq,

3
Niente di speciale, ma tu dici più semplice e vedo soluzioni più semplici -> secondo me non è la più semplice. Forse è stato un paio d'anni fa, ma il mondo sta cambiando. Non eticherei le mie soluzioni con una simile affermazione. ;) Se solo tu scrivessi "Secondo me il più semplice è .." o "il più semplice che ho trovato .." Non voglio disturbarti, ho solo pensato di comunicarlo.
BlondCode,

@MuhammadSadiq: non importare nulla .*, è considerata una cattiva pratica.
Sapphire_Brick,

13

Guava ha Files.toByteArray () da offrirti. Ha diversi vantaggi:

  1. Copre il caso d'angolo in cui i file riportano una lunghezza di 0 ma hanno ancora contenuto
  2. È altamente ottimizzato, ottieni OutOfMemoryException se provi a leggere in un file di grandi dimensioni prima ancora di provare a caricare il file. (Attraverso un uso intelligente di file.length ())
  3. Non è necessario reinventare la ruota.

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

Che livello di JDK è questo?
Jonathan S. Fisher,

11

Utilizzando lo stesso approccio della risposta wiki della community, ma più pulito e compilato immediatamente (approccio preferito se non si desidera importare le librerie di Apache Commons, ad esempio su 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();
}

8

Credo che questo sia il modo più semplice:

org.apache.commons.io.FileUtils.readFileToByteArray(file);

7
c'è già una risposta con questo suggerimento di Tom nel 2009
Knut Herrmann,

7

ReadFully Legge i byte b.length da questo file nell'array di byte, a partire dal puntatore del file corrente. Questo metodo legge ripetutamente dal file fino a quando non viene letto il numero richiesto di byte. Questo metodo si blocca finché non viene letto il numero richiesto di byte, viene rilevata la fine del flusso o viene generata un'eccezione.

RandomAccessFile f = new RandomAccessFile(fileName, "r");
byte[] b = new byte[(int)f.length()];
f.readFully(b);

5

Se si desidera leggere byte in un buffer di byte pre-allocato, questa risposta può essere d'aiuto.

La tua prima ipotesi sarebbe probabilmente da usare InputStream read(byte[]). Tuttavia, questo metodo ha un difetto che lo rende irragionevolmente difficile da usare: non vi è alcuna garanzia che l'array sarà effettivamente riempito completamente, anche se non si incontra EOF.

Invece, dai un'occhiata DataInputStream readFully(byte[]). Questo è un wrapper per flussi di input e non presenta il problema sopra menzionato. Inoltre, questo metodo viene generato quando viene rilevato EOF. Molto più bello.


4

Non solo il modo seguente converte un file java.io.File in un byte [], ma ho anche trovato il modo più veloce di leggere in un file, quando testavo molti metodi di lettura di file Java uno contro l'altro:

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

Consentitemi di aggiungere un'altra soluzione senza utilizzare librerie di terze parti. Riutilizza un modello di gestione delle eccezioni proposto da Scott ( link ). E ho spostato la parte brutta in un messaggio separato (mi nasconderei in qualche classe 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

Un altro modo per leggere byte dal file

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

non usare blocchi di cattura cavi. rende difficile il debug.
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
Mentre questo codice può fornire una soluzione alla domanda, è meglio aggiungere un contesto sul perché / come funziona. Questo può aiutare gli utenti futuri a imparare e applicare tali conoscenze al proprio codice. È inoltre probabile che tu riceva un feedback positivo dagli utenti sotto forma di valutazioni, quando viene spiegato il codice.
Borchvm

Bene, questa è la parte importante che terrò a mente nei post futuri. Grazie per i tuoi utili approfondimenti.
Usama Mehmood,

0

Prova questo :

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

Ciò richiede una particolare implementazione di JRE che interromperà l'app se eseguita su un altro JRE.
rattaman,

2
piccolo errore: è IOException e non IOexception, ma grazie :)
Matan Marciano

1
@MatanMarciano: my bad
Sapphire_Brick

-7

In JDK8

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

2
Leggi la domanda, amico mio di lingua francese, chiede della conversione in "byte []" e la tua risposta non lo fornisce.
Kaiser Keister

2
Questo non fornisce un'opzione anche remota per rispondere per la conversione in byte []!
Anddo,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.