In Java, we read a file to a byte array with Files.readAllBytes(path), which opens the file, reads all its bytes into a new byte[] and closes the file, also when an exception occurs. For an InputStream that is already open, readAllBytes() and readNBytes(n) do the same job.
We read a file into a byte array when the next step works with raw bytes, for example to attach a PDF to an email, send an image to a REST API as Base64, store a file in a database column, compute a checksum or check the first bytes of an upload to find its real type.
The following example writes a small file, reads it back as bytes and reads only its first four bytes.
Path logo = Files.write(Files.createTempFile("logo", ".png"), new byte[] {(byte) 0x89, 'P', 'N', 'G', 13, 10, 26, 10});
byte[] bytes = Files.readAllBytes(logo);
int size = bytes.length; // 8
byte[] header;
try (InputStream in = Files.newInputStream(logo)) {
header = in.readNBytes(4);
}
String type = new String(header, 1, 3, StandardCharsets.US_ASCII); // "PNG"
Notice that Files.readAllBytes() needs no try-with-resources, because it closes the file itself, whereas the stream version reads only what it needs. After this quick answer, we look at the size limit, the FileInputStream pitfall from older code, files too large for memory, classpath resources, and the Commons IO and Guava helpers.
1. Using Files.readAllBytes()
The method Files.readAllBytes(Path) asks the file system for the file size, allocates an array of that size and fills it. It closes the file on success and on failure, so it never leaks a file handle. We get a Path from Path.of(“invoices/2026-10.pdf”), or from file.toPath() when older code hands us a java.io.File.

Say an invoicing app attaches each monthly invoice PDF to an email, and the mail API wants the attachment as a byte[] or as a Base64 string. A PDF of a few hundred kilobytes fits in memory without any concern, so readAllBytes() is the right tool.
Path invoice = Files.write(Files.createTempFile("invoice", ".pdf"), "%PDF-1.7 sample".getBytes(StandardCharsets.US_ASCII));
byte[] pdf = Files.readAllBytes(invoice);
int pdfSize = pdf.length; // 15
String base64 = Base64.getEncoder().encodeToString(pdf);
String start = base64.substring(0, 8); // "JVBERi0x"
The Base64 encoding article explains the encoder variants. If the next step needs text instead of bytes, Files.readString(path) reads and decodes the file in one call.
The method readAllBytes() loads the whole file into the heap, so we use it only for files whose size we know to be small. A Java array holds at most about 2 GB, and for a larger file the method throws an OutOfMemoryError with the message Required array size too large before reading anything. On a normal heap, much smaller files already fail, which is why section 3 avoids the array altogether.
2. Using FileInputStream and InputStream
Older code reads a file into an array with a FileInputStream, sized from file.length(), and a single read(bytes) call. That code has a bug. The method read(byte[]) returns how many bytes it read, and it may return fewer than the array length, so the end of the array can stay filled with zeros.
File file = Files.write(Files.createTempFile("logo", ".png"), new byte[] {(byte) 0x89, 'P', 'N', 'G'}).toFile();
byte[] bytes = new byte[(int) file.length()];
int read;
try (FileInputStream fis = new FileInputStream(file)) {
read = fis.read(bytes); // not guaranteed to fill the array
}
int bytesRead = read; // 4 here, but a large file or a network drive can return fewer
The cast (int) file.length() also overflows for files over 2 GB. Since Java 9 and 11, InputStream has methods that loop internally until they have all requested bytes, so the fix is one line.
Path logo = Files.write(Files.createTempFile("logo", ".png"), new byte[] {(byte) 0x89, 'P', 'N', 'G', 13, 10, 26, 10});
byte[] all;
try (InputStream in = new FileInputStream(logo.toFile())) {
all = in.readAllBytes();
}
int allSize = all.length; // 8
byte[] firstFour;
try (InputStream in = Files.newInputStream(logo)) {
firstFour = in.readNBytes(4);
}
int firstByte = firstFour[0] & 0xFF; // 137
The method readAllBytes() (Java 9) reads to the end of the stream, and readNBytes(int) (Java 11) reads up to the given count and returns a shorter array only at the end of the stream. A file upload service uses readNBytes() to check the magic number at the start of a file, because a file named photo.png can contain anything. For new code, Files.newInputStream(path) replaces new FileInputStream(file).
3. Processing Large Files Without a Byte Array
For large files, the better question is whether we need all bytes at once at all. A checksum, a copy or an upload processes the bytes in order, so a buffer of a few kilobytes is enough, and memory use stays the same for a 1 KB file and a 10 GB backup.
The following example computes the SHA-256 checksum of a file with a DigestInputStream, which updates the digest as bytes pass through it. A backup tool does the same to verify each archive after the upload.
Path backup = Files.writeString(Files.createTempFile("backup", ".tar"), "abc");
MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
try (InputStream in = new DigestInputStream(Files.newInputStream(backup), sha256)) {
in.transferTo(OutputStream.nullOutputStream());
}
String checksum = HexFormat.of().formatHex(sha256.digest()).substring(0, 16); // "ba7816bf8f01cfea"
The call transferTo(OutputStream.nullOutputStream()) reads the stream to the end in 16 KB chunks and discards the bytes, so only the digest keeps a result. The class HexFormat (Java 17) turns the digest into a hex string. The article on file checksums covers other algorithms, and memory-mapped files give random access to large files without loading them.
4. Reading a Classpath Resource Into a Byte Array
A file inside a JAR has no Path on the default file system, so Files.readAllBytes() cannot read it. We open it as a stream with getResourceAsStream() and call readAllBytes() on the stream. The method returns null for a missing resource, so we check for it.
byte[] classBytes;
try (InputStream in = Objects.requireNonNull(Object.class.getResourceAsStream("Object.class"), "resource not found")) {
classBytes = in.readNBytes(4);
}
String magic = HexFormat.of().formatHex(classBytes); // "cafebabe"
Every compiled class file starts with the bytes CAFEBABE, which makes the JDK’s own Object.class a resource that exists everywhere. In an app, we call getResourceAsStream(“/templates/logo.png”) on one of our classes, as explained in reading a file from the resources folder.
5. Using Commons IO and Guava
Apache Commons IO and Guava both have one-line helpers that take a java.io.File. They do the same as Files.readAllBytes(file.toPath()), so they are worth it only in projects that already use the library.
File report = Files.writeString(Files.createTempFile("report", ".txt"), "total=42").toFile();
byte[] commons = FileUtils.readFileToByteArray(report);
int commonsSize = commons.length; // 8
byte[] guava = com.google.common.io.Files.toByteArray(report);
int guavaSize = guava.length; // 8
byte[] fromStream;
try (InputStream in = new FileInputStream(report)) {
fromStream = IOUtils.toByteArray(in);
}
int streamSize = fromStream.length; // 8
We write Guava’s class with its full name, because its simple name Files clashes with java.nio.file.Files. The Commons IO method FileUtils.readFileToByteArray() closes the file, whereas IOUtils.toByteArray(InputStream) leaves the stream open, so it needs try-with-resources. The examples use Commons IO 2.22.0 and Guava 33.7.2-jre.
6. Writing the Byte Array Back to a File
The counterpart of readAllBytes() is Files.write(path, bytes), which creates the file or overwrites an existing one. Together they copy a small file through memory, for example when the bytes are changed in between.
Path source = Files.writeString(Files.createTempFile("notes", ".txt"), "Buy milk");
Path copy = Files.createTempFile("notes-copy", ".txt");
byte[] content = Files.readAllBytes(source);
Files.write(copy, content);
boolean same = Arrays.equals(content, Files.readAllBytes(copy)); // true
For plain copies, Files.copy(source, target) is faster and does not load the file into memory. The article on writing a byte array to a file covers the open options for appending and creating files.
7. Reading Files to Byte Arrays FAQs
Byte arrays print and convert differently from strings, and they hit a size limit that strings hide, which leads to most of these questions.
7.1. What Is the Maximum File Size for Files.readAllBytes()?
The hard limit is about 2 GB, the maximum length of a Java array. A larger file fails at once with OutOfMemoryError: Required array size too large. The practical limit is lower, because the array must fit into the free heap, so for files that can grow we process them in chunks as in section 3.
7.2. Why Does My Byte Array Print as [B@6d06d69c?
Arrays do not override toString(), so printing one shows its type code [B and a hash. We print the content with Arrays.toString(bytes) or as hex with HexFormat.
byte[] bytes = {72, 105};
String asList = Arrays.toString(bytes); // "[72, 105]"
String asHex = HexFormat.of().formatHex(bytes); // "4869"
7.3. How Do I Convert the Byte Array to a String?
We decode it with the charset the file was written in, for example new String(bytes, StandardCharsets.UTF_8). For text files, Files.readString(path) does both steps and fails on invalid bytes instead of guessing. The article on converting a byte array to a String shows more variants.
7.4. Is Files.readAllBytes() Faster Than FileInputStream?
For reading a whole file, both end up reading the file in large blocks, and the difference is small compared with the disk time. Files.readAllBytes() wins on correctness, because it sizes the array from the file, loops until the array is full and closes the file. We measure with JMH before choosing a method for speed.
8. Conclusion
Reading a file to a byte array in Java takes one call to Files.readAllBytes(path), which handles opening, sizing, looping and closing. For streams that are already open, readAllBytes() and readNBytes() replace the old single read() call, which could leave part of the array empty.
A byte array holds the whole file in memory, so large files go through a buffer instead, for example with transferTo() into a digest or an upload. Classpath resources need a stream, and Commons IO and Guava offer the same one-liners for projects that already use them. More file tasks are grouped in the Java IO tutorial.
9. References
- Files.readAllBytes() Javadoc
- InputStream Javadoc
- DigestInputStream Javadoc
- HexFormat Javadoc
- Commons IO FileUtils Javadoc
Happy Learning !!