Fichier à octet [] en Java

757

Comment convertir un java.io.Fileen un byte[]?

Ben Noland
la source
Une utilisation à laquelle je peux penser est la lecture d'objets sérialisés à partir d'un fichier.
Mahm00d
2
Une autre consiste à trouver le type de fichier à l'aide de l'en-tête.
James P.
Essayez cet octet [] octets = null; BufferedInputStream fileInputStream = null; essayez {File file = new File (filePath); fileInputStream = new BufferedInputStream (nouveau FileInputStream (fichier)); // fileInputStream = Thread.currentThread (). getContextClassLoader (). getResourceAsStream (this.filePath); octets = nouvel octet [(int) file.length ()]; fileInputStream.read (octets); } catch (FileNotFoundException ex) {throw ex; }
Rohit Chaurasiya

Réponses:

486

Cela dépend de ce que signifie le mieux pour vous. Côté productivité, ne réinventez pas la roue et utilisez Apache Commons. C'est ici IOUtils.toByteArray(InputStream input).

svachon
la source
29
@ymajoros: Tellement vrai! Je préfère avoir quelques lignes de code supplémentaires qu'une autre dépendance. Les dépendances ont des coûts cachés. Vous devez rester à jour avec cette bibliothèque, inclure la dépendance dans votre script de construction, etc., la communiquer aux personnes utilisant votre code, etc. Si vous utilisez déjà une bibliothèque qui a du code pour l'utiliser, utilisez-la, autrement je dirais écris-le toi-même.
Stijn de Witt
11
Cela répond à la question de savoir comment lire un fichier, mais pas à la question de savoir comment convertir un objet de type java.IO.File en octet [].
Ingo
5
Comment est-ce utilisé pour lire un Fileà byte[]? J'utilise Java6, je ne peux donc pas utiliser les méthodes NIO :(
PASTRY
4
@ymajoros aimeriez-vous partager avec nous toute "solution standard à 3 lignes", afin que nous n'ayons pas à compter sur une dépendance réinventant la roue?
matteo
3
@matteo: tout? Voir d'autres réponses, par exemple Files.readAllBytes (). Simple, pas de dépendance.
ymajoros
1293

Depuis JDK 7, vous pouvez utiliser Files.readAllBytes(Path).

Exemple:

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

File file;
// ...(file is initialised)...
byte[] fileContent = Files.readAllBytes(file.toPath());
Michael Pollmeier
la source
10
J'ai un objet File, pas un chemin (à partir de la demande de publication http)
aldo.roman.nurena
81
@ aldo.roman.nurena JDK7 a introduit une méthode File.toPath () qui vous donnera un objet Path.
KevinL
6
Vous pouvez obtenir un chemin d'accès à partir d'un fichier. Essayez: File file = new File ("/ path"); Path path = Paths.get (file.getAbsolutePath ()); byte [] data = Files.readAllBytes (chemin);
gfelisberto
2
Comment la fermeture de fichiers est-elle gérée dans java.nio - en d'autres termes, le code ci-dessus devrait-il fermer quelque chose?
akauppi
4
@akauppi Voir le lien dans la réponse: "La méthode garantit la fermeture du dossier ..."
Bernhard Barker
226

Depuis JDK 7 - une doublure:

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

Aucune dépendance externe requise.

Paulius Matulionis
la source
13
C'est maintenant un meilleur choix que la réponse acceptée, qui nécessite Apache Commons.
james.garriss
1
Merci :) J'avais aussi besoin de celui-ci: String text = new String (Files.readAllBytes (new File ("/ path / to / file"). ToPath ())); qui est originaire de stackoverflow.com/a/26888713/1257959
cgl
5
Sous Android, le niveau d'API minimum doit être de 26.
Ashutosh Chamoli
2
Vous devrez ajouter import java.nio.file.Files;et import java.nio.file.Paths;si vous ne l'avez pas déjà fait.
Sam
164
import java.io.RandomAccessFile;
RandomAccessFile f = new RandomAccessFile(fileName, "r");
byte[] b = new byte[(int)f.length()];
f.readFully(b);

Documentation pour Java 8: http://docs.oracle.com/javase/8/docs/api/java/io/RandomAccessFile.html

Dmitry Mitskevich
la source
2
Vous devez vérifier la valeur de retour de f.read (). Cela peut parfois arriver, que vous ne lirez pas le fichier entier.
bugs_
8
Une telle situation ne peut se produire que si le fichier change pendant que vous le lisez. Dans tous les autres cas, IOException est levée. Pour résoudre ce problème, je suggère d'ouvrir le fichier en mode lecture-écriture: RandomAccessFile (fileName, "rw")
Dmitry Mitskevich
5
Je pourrais imaginer d'autres sources pour ne lire qu'une partie du fichier (le fichier est sur un partage réseau ...) readFully () a le contrat que vous recherchez.
DThought
3
N'oubliez pas que RandomAccessFile n'est pas sûr pour les threads. Ainsi, la synchronisation peut être nécessaire dans certains cas.
danseur
@DmitryMitskevich Il existe également d'autres cas, sur des systèmes de fichiers qui sont peut-être non conformes. Par exemple, la lecture de "fichiers" dans / proc / sous linux peut provoquer de courtes lectures (c'est-à-dire que vous avez besoin d'une boucle pour tout lire)
nos
78

Fondamentalement, vous devez le lire en mémoire. Ouvrez le fichier, allouez le tableau et lisez le contenu du fichier dans le tableau.

La manière la plus simple est similaire à ceci:

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

Cela a une copie inutile du contenu du fichier (en fait, les données sont copiées trois fois: du fichier à buffer, de bufferà ByteArrayOutputStream, de ByteArrayOutputStreamau tableau résultant réel).

Vous devez également vous assurer de ne lire en mémoire que les fichiers jusqu'à une certaine taille (cela dépend généralement de l'application) :-).

Vous devez également traiter l' IOExceptionextérieur de la fonction.

Une autre façon est la suivante:

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

Cela n'a pas de copie inutile.

FileTooBigExceptionest une exception d'application personnalisée. La MAX_FILE_SIZEconstante est un paramètre d'application.

Pour les gros fichiers, vous devriez probablement penser à un algorithme de traitement de flux ou utiliser le mappage de mémoire (voir java.nio).

Mihai Toader
la source
ios doit être déclaré en dehors de l'essai
Daryl Spitzer
L'instruction "ios.read (buffer)" dans le deuxième exemple ne lira que dans les 4096 premiers octets du fichier (en supposant le même tampon 4k que celui utilisé dans le premier exemple). Pour que le deuxième exemple fonctionne, je pense que la lecture doit être à l'intérieur d'une boucle while qui vérifie le résultat pour -1 (fin de fichier atteinte).
Stijn de Witt
Désolé, rejetez ma remarque ci-dessus, vous avez manqué le tampon de définition de la déclaration pour la longueur du fichier. Pourtant, j'aime davantage le premier exemple. La lecture d'un fichier entier dans un tampon en une seule fois n'est pas évolutive. Vous risquez de manquer de mémoire lorsque le fichier est volumineux.
Stijn de Witt
La manière "la plus simple" consisterait à essayer avec des ressources.
Sina Madani
Cool, mais un peu bavard.
Sapphire_Brick
77

Comme quelqu'un l'a dit, Apache Commons File Utils pourrait avoir ce que vous cherchez

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

Exemple d'utilisation ( 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);
        ...
    }
}
À M
la source
23

Vous pouvez également utiliser l'API NIO pour le faire. Je pourrais faire cela avec ce code tant que la taille totale du fichier (en octets) tiendrait dans 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();
    }
}

Je pense que c'est très rapide depuis son utilisation de MappedByteBuffer.

Amit
la source
2
il n'est absolument pas nécessaire d'utiliser le mappage de mémoire si vous ne lisez le fichier qu'une seule fois, et il finira par utiliser deux fois plus de mémoire que l'utilisation d'un FileInputStream normal.
james
1
Malheureusement, MappedByteBuffer n'est pas automatiquement publié.
Tom Hawtin - tackline
2
génial, le nouvel exemple inclut printStackTrace, la gestion classique des exceptions cassées.
james
Je suis d'accord .. C'est le truc par défaut qu'éclipse met. Je pense que je devrais repousser l'exception!
Amit
J'ai comparé nio afin de créer un octet [] à partir d'un fichier. Outre l'utilisation d'un tampon direct, il prend en effet deux fois plus de mémoire. Bien qu'il soit plus rapide pour les très gros fichiers (environ deux fois plus rapide qu'un IO tamponné pour 200M), il semble perdre par un facteur de 5 pour les fichiers autour de 5M.
Chaffers
22

Si vous n'avez pas Java 8, et convenez avec moi qu'inclure une bibliothèque massive pour éviter d'écrire quelques lignes de code est une mauvaise idée:

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

L'appelant est responsable de la fermeture du flux.

Jeffrey Blattman
la source
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
la source
Mettez également numRead dans la boucle. Déclarez les variables dans la plus petite étendue valide possible. Le placer en dehors de la boucle while n'est nécessaire que pour activer ce test "while" compliqué; il serait préférable de faire le test d'EOF à l'intérieur de la boucle (et de lancer une EOFException si cela se produit).
erickson
throw new IOException("File is too large!");que devons-nous faire lorsque le fichier est trop volumineux? Y a-t-il également un exemple à ce sujet?
Fer
21

Un moyen simple de le faire:

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);
Sudip Bhandari
la source
Il existe des moyens plus simples, tels que les monolignes qui ont déjà été mentionnés.
Sapphire_Brick
@Sapphire_Brick Des moyens plus simples oui - mais les doublures ne conviennent pas à toutes les situations. Comme Android.
Behr
17

Manière la plus simple de lire des octets à partir d'un fichier

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);
        }
    }
}
Muhammad Sadiq
la source
1
Je
prétends
Pouvez-vous expliquer ici? Pourquoi avez-vous une dispute?
Muhammad Sadiq
3
Rien de spécial, mais vous dites le plus simple et je vois des solutions plus simples -> à mon avis, ce n'est pas le plus simple. C'était peut-être il y a quelques années, mais le monde change. Je ne voudrais pas étiqueter mes propres solutions avec une telle déclaration. ;) Si seulement vous écriviez "À mon avis, le plus simple est .." ou "le plus simple que j'ai trouvé .." Je ne veux pas vous déranger, je vous ai juste fait plaisir de communiquer cela.
BlondCode
@MuhammadSadiq: n'importez rien .*, c'est considéré comme une mauvaise pratique.
Sapphire_Brick
13

Guava a Files.toByteArray () à vous offrir. Il présente plusieurs avantages:

  1. Il couvre le cas du coin où les fichiers signalent une longueur de 0 mais ont toujours du contenu
  2. Il est hautement optimisé, vous obtenez une OutOfMemoryException si vous essayez de lire un gros fichier avant même d'essayer de charger le fichier. (Grâce à une utilisation intelligente de file.length ())
  3. Vous n'avez pas à réinventer la roue.
jontejj
la source
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
la source
De quel niveau JDK s'agit-il?
Jonathan S. Fisher
11

En utilisant la même approche que la réponse du wiki de la communauté, mais plus propre et compilant hors de la boîte (approche préférée si vous ne voulez pas importer des bibliothèques Apache Commons, par exemple sur 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
la source
8

Je crois que c'est la manière la plus simple:

org.apache.commons.io.FileUtils.readFileToByteArray(file);
Cristian Tetic
la source
7
il y a déjà une réponse avec cette suggestion de Tom en 2009
Knut Herrmann
7

ReadFully Lit les octets b.length de ce fichier dans le tableau d'octets, en commençant par le pointeur de fichier actuel. Cette méthode lit à plusieurs reprises à partir du fichier jusqu'à ce que le nombre d'octets demandé soit lu. Cette méthode se bloque jusqu'à ce que le nombre d'octets demandé soit lu, que la fin du flux soit détectée ou qu'une exception soit levée.

RandomAccessFile f = new RandomAccessFile(fileName, "r");
byte[] b = new byte[(int)f.length()];
f.readFully(b);
Tarun M
la source
5

Si vous souhaitez lire des octets dans un tampon d'octets pré-alloué, cette réponse peut vous aider.

Votre première supposition serait probablement d'utiliser InputStream read(byte[]). Cependant, cette méthode a un défaut qui la rend excessivement difficile à utiliser: il n'y a aucune garantie que la baie sera réellement complètement remplie, même si aucun EOF n'est rencontré.

Jetez plutôt un œil à DataInputStream readFully(byte[]). Ceci est un wrapper pour les flux d'entrée et n'a pas le problème mentionné ci-dessus. En outre, cette méthode se déclenche lorsque EOF est rencontré. Beaucoup mieux.

Laurens Holst
la source
4

Non seulement la manière suivante convertit un fichier java.io.File en octet [], mais je l'ai également trouvé comme le moyen le plus rapide de lire un fichier, lors du test de nombreuses méthodes de lecture de fichiers Java les unes contre les autres:

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
la source
3

Permettez-moi d'ajouter une autre solution sans utiliser de bibliothèques tierces. Il réutilise un modèle de gestion des exceptions qui a été proposé par Scott ( lien ). Et j'ai déplacé la partie laide dans un message séparé (je me cacherais dans une 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;
}
Andreas Dolk
la source
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
la source
1

Une autre façon de lire les octets du fichier

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();
        }
    }
Muhammad Aamir Ali
la source
n'utilisez pas de blocs d'accrochage creux. cela rend le débogage difficile.
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"
Usama Mehmood
la source
1
Bien que ce code puisse fournir une solution à la question, il est préférable d'ajouter du contexte pour expliquer pourquoi / comment cela fonctionne. Cela peut aider les futurs utilisateurs à apprendre et à appliquer ces connaissances à leur propre code. Vous êtes également susceptible d'avoir des commentaires positifs des utilisateurs sous la forme de votes positifs, lorsque le code est expliqué.
borchvm
Eh bien, c'est la partie importante que je garderai à l'esprit dans les prochains articles. Merci pour vos informations utiles.
Usama Mehmood
0

Essaye ça :

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);
}
Maifee Ul Asad
la source
Cela nécessite une implémentation JRE particulière qui cassera l'application si elle est exécutée sur un autre JRE.
rattaman
2
petite erreur: est IOException et non IOexception, mais merci :)
Matan Marciano
1
@MatanMarciano: my bad
Sapphire_Brick
-7

Dans JDK8

Stream<String> lines = Files.lines(path);
String data = lines.collect(Collectors.joining("\n"));
lines.close();
beaucequebec
la source
2
Lisez la question, mon ami francophone, il s'agit de convertir en "octet []" et votre réponse ne le fournit pas.
Kaiser Keister
2
Cela ne fournit pas une option à distance pour répondre à la conversion en octets []!
Anddo