Arquivo para byte [] em Java


757

Como faço para converter um java.io.Filepara um byte[]?


Um uso em que consigo pensar é ler objetos serializados do arquivo.
precisa saber é o seguinte

2
Outra é encontrar o tipo de arquivo usando o cabeçalho.
James P.

Tente este byte [] bytes = nulo; BufferedInputStream fileInputStream = null; tente {File file = new File (filePath); fileInputStream = novo BufferedInputStream (novo FileInputStream (arquivo)); // fileInputStream = Thread.currentThread (). getContextClassLoader (). getResourceAsStream (this.filePath); bytes = novo byte [(int) file.length ()]; fileInputStream.read (bytes); } catch (FileNotFoundException ex) {throw ex; }
Rohit Chaurasiya

Respostas:


486

Depende do que melhor significa para você. Em termos de produtividade, não reinvente a roda e use o Apache Commons. Qual é aqui IOUtils.toByteArray(InputStream input).


29
@ymajoros: Tão verdade! Prefiro ter algumas linhas extras de código do que outra dependência. Dependências têm custos ocultos. Você precisa manter-se atualizado com essa biblioteca, incluir a dependência nos scripts de construção, etc., comunicá-la às pessoas que usam seu código, etc. escreva você mesmo.
Stijn de Witt

11
Isso responde à questão de como ler um arquivo, mas não à questão de como converter um objeto do tipo java.IO.File em byte [].
Ingo

5
Como isso é usado para ler um Filepara byte[]? Estou usando Java6 então não posso usar os métodos NIO :(
PASTELARIA

4
@ymajoros, você poderia compartilhar conosco qualquer "solução padrão de 3 linhas", para que não tenhamos que confiar em uma dependência de reinventar a roda?
Matteo

3
@matteo: algum? Veja outras respostas, por exemplo, Files.readAllBytes (). Simples, sem dependência.
ymajoros

1292

No JDK 7 você pode usar Files.readAllBytes(Path).

Exemplo:

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

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

10
Eu tenho um objeto File, não um caminho (da solicitação de postagem http)
aldo.roman.nurena 28/10

81
@ aldo.roman.nurena O JDK7 introduziu um método File.toPath () que fornecerá um Path Object.
KevinL

6
Você pode obter um caminho de um arquivo. Tente: Arquivo file = new File ("/ path"); Caminho path = Paths.get (file.getAbsolutePath ()); byte [] data = Files.readAllBytes (caminho);
Gfelisberto

2
Como o fechamento do arquivo é tratado no java.nio - em outras palavras, o código acima deve fechar alguma coisa?
akauppi

4
@akauppi Veja o link na resposta: "O método garante que o arquivo seja fechado ..."
Bernhard Barker

226

Desde o JDK 7 - um liner:

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

Nenhuma dependência externa necessária.


13
Agora é uma escolha melhor do que a resposta aceita, que requer o Apache Commons.
James.garriss 15/09/2015

1
Obrigado :) Eu também precisava deste: String text = new String (Files.readAllBytes (new File ("/ path / to / file"). ToPath ())); que é originalmente de stackoverflow.com/a/26888713/1257959
cgl

5
Em Android, que exige nível API min para ser 26.
Ashutosh Chamoli

2
Você precisará adicionar import java.nio.file.Files;e import java.nio.file.Paths;se ainda não o tiver.
Sam

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

Documentação para Java 8: http://docs.oracle.com/javase/8/docs/api/java/io/RandomAccessFile.html


2
Você deve verificar o valor de retorno de f.read (). Às vezes, aqui pode acontecer que você não leia o arquivo inteiro.
bugs_

8
Essa situação pode ocorrer apenas se o arquivo estiver sendo alterado enquanto você o estiver lendo. Em todos os outros casos, a IOException é lançada. Para resolver este problema, sugiro ao arquivo aberto em modo de leitura e escrita: RandomAccessFile (fileName, "rw")
Dmitry Mitskevich

5
Eu poderia imaginar outras fontes para ler apenas uma parte do arquivo (o arquivo está em um compartilhamento de rede ...) readFully () tem o contrato que você está procurando.
precisa

3
Lembre-se de que o RandomAccessFile não é seguro para threads. Portanto, a sincronização pode ser necessária em alguns casos.
bancer

@DmitryMitskevich Também existem outros casos, em sistemas de arquivos que possivelmente não estão em conformidade. por exemplo, ler "arquivos" em / proc / on linux pode causar leituras curtas (ou seja, você precisa de um loop para ler tudo)
nos

78

Basicamente, você tem que ler na memória. Abra o arquivo, aloque a matriz e leia o conteúdo do arquivo na matriz.

A maneira mais simples é algo semelhante a isto:

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

Isto tem alguma cópia desnecessária do conteúdo do arquivo (na verdade, os dados são copiados três vezes: de arquivo para buffer, a partir bufferde ByteArrayOutputStream, a partir ByteArrayOutputStreamda matriz resultante real).

Você também precisa ter certeza de ler apenas na memória arquivos de até um determinado tamanho (isso geralmente depende do aplicativo) :-).

Você também precisa tratar a parte IOExceptionexterna da função.

Outra maneira é esta:

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

Isso não tem cópia desnecessária.

FileTooBigExceptioné uma exceção de aplicativo personalizado. A MAX_FILE_SIZEconstante é um parâmetro de aplicação.

Para arquivos grandes, você provavelmente deve pensar em um algoritmo de processamento de fluxo ou usar o mapeamento de memória (consulte java.nio).


ios precisa ser declarado fora da tentativa
Daryl Spitzer

A instrução "ios.read (buffer)" no segundo exemplo será lida apenas nos primeiros 4096 bytes do arquivo (assumindo o mesmo buffer de 4k usado no primeiro exemplo). Para o segundo exemplo funcionar, acho que a leitura precisa estar dentro de um loop while que verifica o resultado em -1 (final do arquivo atingido).
Stijn de Witt

Desculpe, ignore minha observação acima, perdi o buffer de configuração da instrução para o tamanho do arquivo. Ainda assim, gosto mais do primeiro exemplo. A leitura de um arquivo inteiro em um buffer de uma só vez não é escalável. Você corre o risco de ficar sem memória quando o arquivo for grande.
Stijn de Witt

A maneira "mais simples" usaria o try-with-resources.
Sina Madani 29/03

Legal, mas um pouco detalhado.
Sapphire_Brick

77

Como alguém disse, o Apache Commons File Utils pode ter o que você está procurando

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

Exemplo de uso ( 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

Você também pode usar a API do NIO para fazê-lo. Eu poderia fazer isso com esse código, desde que o tamanho total do arquivo (em bytes) cabesse em um 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();
    }
}

Eu acho que é muito rápido, já que está usando o MappedByteBuffer.


2
não há absolutamente nenhuma necessidade de usar o mapeamento de memória se você quiser ler o arquivo apenas uma vez e ele acabará usando o dobro da memória que o FileInputStream normal.
james

1
Infelizmente, MappedByteBuffer não é lançado automaticamente.
Tom Hawtin - tackline

2
impressionante, o novo exemplo inclui o printStackTrace, tratamento clássico de exceções quebradas.
james

Eu concordo .. É o material padrão que o eclipse coloca. Acho que devo repetir a exceção!
Amit

Estive comparando o nio para criar um byte [] a partir de um arquivo. Além de usar um buffer direto, ele realmente leva o dobro da memória. Embora seja mais rápido para arquivos muito grandes (cerca de duas vezes mais rápido que um IO em buffer para 200M), parece perder por um fator de 5 para arquivos em torno de 5M.
Chaffers

22

Se você não possui o Java 8, e concorda comigo que é uma má idéia incluir uma enorme biblioteca para evitar a escrita de algumas linhas de código:

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

O chamador é responsável por fechar o fluxo.


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

Além disso, coloque numRead dentro do loop. Declare as variáveis ​​no menor escopo válido possível. Colocá-lo fora do loop while é necessário apenas para permitir esse teste complicado "while"; seria melhor fazer o teste para o EOF dentro do loop (e lançar uma EOFException, se ocorrer).
Erickson

throw new IOException("File is too large!");o que devemos fazer quando o arquivo é muito grande? Existe também algum exemplo sobre isso?
Fer

21

Maneira simples de fazer isso:

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

Existem maneiras mais simples, como as one-liners que já foram mencionadas.
Sapphire_Brick

@Sapphire_Brick Maneiras mais simples sim - mas os liners únicos não servem para todas as situações. Como o Android.
Behr

17

Maneira mais simples para ler bytes do arquivo

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
Eu argumento de ser a "maneira mais simples" :)
BlondCode

Você pode explicar aqui? Por que você tem uma discussão?
Muhammad Sadiq

3
Nada de especial, mas você diz mais simples e vejo soluções mais simples -> na minha opinião, não é a mais simples. Talvez tenha sido alguns anos atrás, mas o mundo está mudando. Eu não rotularia minhas próprias soluções com essa afirmação. ;) Se você escreveu "Na minha opinião, o mais simples é .." ou "o mais simples que encontrei .." Não quero incomodá-lo, achei legal comunicar isso.
BlondCode

@ MuhammadSadiq: não importe nada .*, é considerado uma prática ruim.
Sapphire_Brick

13

A Goiaba tem o Files.toByteArray () para lhe oferecer. Tem várias vantagens:

  1. Ele cobre a caixa de canto em que os arquivos relatam um comprimento de 0, mas ainda têm conteúdo
  2. É altamente otimizado, você obtém uma OutOfMemoryException se tentar ler um arquivo grande antes de tentar carregar o arquivo. (Através do uso inteligente de file.length ())
  3. Você não precisa reinventar a roda.

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

Que nível do JDK é esse?
91318 Jonathan S. Fisher

11

Usando a mesma abordagem que a resposta do wiki da comunidade, mas mais limpa e compilada imediatamente (abordagem preferida se você não deseja importar as bibliotecas do Apache Commons, por exemplo, no 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

Eu acredito que esta é a maneira mais fácil:

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

7
já existe uma resposta com esta sugestão de Tom em 2009
Knut Herrmann

7

ReadFully Lê b.length bytes deste arquivo na matriz de bytes, iniciando no ponteiro do arquivo atual. Este método lê repetidamente do arquivo até que o número solicitado de bytes seja lido. Esse método bloqueia até que o número solicitado de bytes seja lido, o final do fluxo seja detectado ou uma exceção seja lançada.

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

5

Se você deseja ler bytes em um buffer de bytes pré-alocado, esta resposta pode ajudar.

Seu primeiro palpite provavelmente seria usar InputStream read(byte[]) . No entanto, esse método possui uma falha que o torna irracionalmente difícil de usar: não há garantia de que a matriz seja realmente completamente preenchida, mesmo que nenhum EOF seja encontrado.

Em vez disso, dê uma olhada DataInputStream readFully(byte[]). Este é um invólucro para fluxos de entrada e não possui o problema mencionado acima. Além disso, esse método lança quando o EOF é encontrado. Muito melhor.


4

A maneira a seguir não apenas converte um arquivo java.io.File para um byte [], como também achei a maneira mais rápida de ler em um arquivo, ao testar muitos métodos diferentes de leitura de arquivos 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

Deixe-me adicionar outra solução sem usar bibliotecas de terceiros. Ele reutiliza um padrão de manipulação de exceção proposto por Scott ( link ). E mudei a parte feia para uma mensagem separada (eu me esconderia em alguma 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

Outra maneira de ler bytes do arquivo

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

não use blocos ocos de captura. torna a depuração difícil.
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
Embora esse código possa fornecer uma solução para a pergunta, é melhor adicionar contexto ao porquê / como ele funciona. Isso pode ajudar os usuários futuros a aprender e aplicar esse conhecimento ao seu próprio código. Também é provável que você tenha um feedback positivo dos usuários na forma de upvotes, quando o código for explicado.
borchvm

Bem, essa é a parte importante que lembrarei nas próximas postagens. Obrigado por suas informações úteis.
Usama Mehmood

0

Tente o seguinte:

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

Isso requer uma implementação específica do JRE, que interromperá o aplicativo se for executada em outro JRE.
Rattaman

2
pequeno erro: é IOException e não IOException, mas graças :)
Matan Marciano

1
@MatanMarciano: my bad
Sapphire_Brick

-7

No JDK8

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

2
Leia a pergunta, meu amigo que fala francês, pergunta sobre a conversão para um "byte []" e sua resposta não fornece isso.
Kaiser Keister

2
Isso não fornece uma opção remota uniforme para responder pela conversão para byte []!
Anddo 7/04
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.