Java Notes
Complete guide to Byte Streams in Java — FileInputStream, FileOutputStream, reading and writing binary data, copying files, and understanding byte-level I/O operations.
What are Byte Streams?
Byte streams handle I/O of raw binary data — one byte (8 bits) at a time. They can read/write ANY type of data: text files, images, audio, video, PDFs, etc.
InputStream and OutputStream
These are the abstract parent classes for all byte streams:
| Class | Purpose | Key Methods |
|---|---|---|
InputStream | Read bytes | read(), read(byte[]), close() |
OutputStream | Write bytes | write(int), write(byte[]), flush(), close() |
FileOutputStream — Writing Bytes
Try it in WoHoCode
Edit the program, then run it here.
Run this example to see its output.
Output:
FileInputStream — Reading Bytes
Try it in WoHoCode
Edit the program, then run it here.
Run this example to see its output.
Output:
| Content | Hello, Java I/O! Welcome to byte streams. |
| Chunk (10 bytes) | 'Hello, Jav' |
| Chunk (10 bytes) | 'a I/O! Wel' |
| Chunk (10 bytes) | 'come to by' |
| Chunk (10 bytes) | 'te streams' |
| Chunk (1 bytes) | '.' |
| Total bytes read | 41 |
| All bytes (41) | Hello, Java I/O! Welcome to byte streams. |
| Available bytes | 41 |
| Remaining | Java I/O! Welcome to byte streams. |
Understanding read() Return Value
The read() method returns an int (not byte). Here's why:
Try it in WoHoCode
Edit the program, then run it here.
Run this example to see its output.
Output:
| int | 0 | byte: 0 | binary: 0 |
| int | 127 | byte: 127 | binary: 1111111 |
| int | 128 | byte: -128 | binary: 10000000 |
| int | 255 | byte: -1 | binary: 11111111 |
| - byte range | -128 to 127 |
| - int solves this | 0-255 for data, -1 for EOF |
File Copy Using Byte Streams
Try it in WoHoCode
Edit the program, then run it here.
Run this example to see its output.
Output (approximate):
| Source file size | 1,024,000 bytes |
| Byte-by-byte | 1856 ms |
| 1KB buffer | 12 ms |
| 8KB buffer | 4 ms |
| 64KB buffer | 3 ms |
| Speedup (byte vs 8KB) | ~464x faster |
Key Lesson: Always use a buffer when doing I/O! Reading byte-by-byte requires a system call for each byte, which is extremely slow.
Writing Binary Data (Non-Text)
Try it in WoHoCode
Edit the program, then run it here.
Run this example to see its output.
Output:
| Written | int 12345 + 5 raw bytes |
| Read integer | 12345 |
| Read bytes | 10 20 30 40 50 |
| Written | int, double, boolean, String |
| Read int | 12345 |
| Read double | 3.14159 |
| Read boolean | true |
| Read String | Hello! |
Common Mistakes
1. Not closing streams
// ❌ BAD: Resource leak if exception occurs
FileInputStream fis = new FileInputStream("file.txt");
int data = fis.read();
fis.close(); // Won't execute if read() throws!
// ✅ GOOD: Try-with-resources
try (FileInputStream fis = new FileInputStream("file.txt")) {
int data = fis.read();
} // Automatically closed even on exception2. Reading byte-by-byte for large files
3. Using byte streams for text (encoding issues)
// ❌ BAD: Byte streams don't handle Unicode properly
FileOutputStream fos = new FileOutputStream("text.txt");
fos.write("Hello 日本語".getBytes()); // Encoding depends on platform!
// ✅ GOOD: Use character streams for text
FileWriter writer = new FileWriter("text.txt", java.nio.charset.StandardCharsets.UTF_8);
writer.write("Hello 日本語");Interview Questions
Q1: What is the difference between byte stream and character stream?
Answer: Byte streams (InputStream/OutputStream) handle raw binary data 8 bits at a time — suitable for images, audio, any file type. Character streams (Reader/Writer) handle Unicode text 16 bits at a time — suitable for text with proper encoding handling.
Q2: Why does read() return int instead of byte?
Answer: Because byte values range from 0-255 for raw data, and we need a special value (-1) to indicate end-of-file. A byte type (-128 to 127) can't distinguish between data byte -1 (which is actually 255 unsigned) and the EOF signal. Using int solves this: 0-255 = valid data, -1 = EOF.
Q3: What happens if you don't close a FileOutputStream?
Answer: (1) Data in internal buffers may not be written to disk (data loss), (2) the file handle leaks (OS limits the number of open files), (3) other programs may not be able to access the file. Always close streams, preferably with try-with-resources.
Q4: What is the difference between flush() and close()?
Answer: flush() forces buffered data to be written to the destination but keeps the stream open for more writes. close() flushes the buffer AND releases the resource (file handle). After close(), you cannot write anymore.
Q5: How would you efficiently copy a large file (e.g., 2GB)?
Answer: Use a buffered read/write loop with an 8KB-64KB buffer. For the best performance in modern Java, use Files.copy(source, destination) from java.nio which uses OS-level optimizations. Never read byte-by-byte for large files.
Continue the lesson path