Skip to content
thesarfo

Concept

Streams & I/O

Byte and character streams in Java — reading/writing files, copying between streams, and working with in-memory byte arrays.

views 0

Java provides classes for data streaming in two forms — the byte stream and the character stream.

  • Input stream means reading from a resource into a program.
  • Output stream means writing from a program to a resource.
  1. Byte stream (1 byte) — InputStream, OutputStream
  2. Character stream (2 bytes) — Reader, Writer

Input stream methods

  1. int read() — reads one byte of data from the input stream, consuming it from the stream. Once the stream is out of bytes, it returns -1.
  2. int read(byte[] b) — reads up to b.length bytes from the input stream. If b is a 5-element byte array, this reads only 5 bytes/chars from the stream.
  3. int read(byte[] b, int off, int len) — like the above, but you can specify the exact offset to start reading from.
  4. int available() — returns the number of bytes available in the input stream. Useful to check before reading.
  5. long skip(long n) — skips over and discards n bytes of data from the input stream.
  6. void mark(int limit) — if you don’t want bytes removed from the stream after reading them, you can mark them and continue reading; limit is how long the mark stays valid.
  7. void reset() — returns to the starting point of the stream (where you marked it).
  8. boolean markSupported() — not every input stream supports mark (only buffered streams do). Call this before marking to check.
  9. void close() — closes the stream once you’re done with it.

Output stream methods

  1. void write(int b) — writes the specified byte (just 1) onto the output stream.
  2. void write(byte[] b) — writes b.length bytes from the byte array to the output stream.
  3. void write(byte[] ary, int off, int len) — like the above, but with a specific offset.
  4. void flush() — only works on a buffered output stream; forces data to move from the buffer onto the output stream/resource.
  5. void close() — closes the output stream once you’re done with it.

Writing examples

Create a file and write a string of text into it:

public class FileExample {
public static void main(String[] args) {
try {
FileOutputStream fos = new FileOutputStream("Test.txt");
String str = "Learn Java programming";
fos.write(str.getBytes()); // convert the string into an array of bytes
fos.close();
} catch (IOException e) {
throw new RuntimeException(e); // handle any errors
}
}
}

One byte at a time, with a loop:

public class FileExample {
public static void main(String[] args) {
try {
FileOutputStream fos = new FileOutputStream("Test.txt");
String str = "Learn Java programming";
byte b[] = str.getBytes();
for (byte x : b)
fos.write(str.getBytes());
fos.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

Using an offset:

public class FileExample {
public static void main(String[] args) {
try {
FileOutputStream fos = new FileOutputStream("Test.txt");
String str = "Learn Java programming";
byte b[] = str.getBytes();
fos.write(b, 6, str.length() - 6);
fos.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

Reading examples

public class FileExample {
public static void main(String[] args) {
try {
FileInputStream fis = new FileInputStream("Test.txt");
byte b[] = new byte[fis.available()]; // array sized to the length of the stream
fis.read(b); // read from the file
String str = new String(b); // create a string from the bytes
System.out.println(str);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

One byte at a time, with a do-while loop:

public class FileExample {
public static void main(String[] args) {
try {
FileInputStream fis = new FileInputStream("Test.txt");
int x;
do {
x = fis.read();
if (x != -1)
System.out.print((char) x); // print each byte until end of file
} while (x != -1);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

Or with a while loop:

public class FileExample {
public static void main(String[] args) {
try {
FileInputStream fis = new FileInputStream("Test.txt");
int x;
while ((x = fis.read()) != -1) {
System.out.println((char) x);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

Reading from a file and copying its contents into another file

Say source1.txt contains the text "JAVA TEST FILE", and we want to copy its contents into source2.txt, converting all uppercase letters to lowercase along the way.

import java.io.FileInputStream;
import java.io.FileOutputStream;
public class SC101 {
public static void main(String[] args) throws Exception {
FileInputStream fis = new FileInputStream("source1.txt");
FileOutputStream fos = new FileOutputStream("source2.txt");
int b;
while ((b = fis.read()) != -1) {
if (b >= 65 && b <= 90) fos.write(b + 32); // uppercase ASCII range -> lowercase
else fos.write(b);
}
fis.close();
fos.close();
}
}

This reads the file one byte at a time; each byte represents a character. If the byte corresponds to an uppercase letter (A-Z, ASCII 65-90), adding 32 converts it to lowercase (a-z); numbers, symbols, and already-lowercase letters are copied unchanged. The converted bytes are written straight to source2.txt.

With FileInputStream, the source file must already exist or you’ll get a FileNotFoundException. With FileOutputStream, if the destination file doesn’t exist, it will be created.

Challenge: copy the contents of both source files into one destination file

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.SequenceInputStream;
public class SC102 {
public static void main(String[] args) throws Exception {
FileInputStream fis1 = new FileInputStream("source1.txt");
FileInputStream fis2 = new FileInputStream("source2.txt");
FileOutputStream fos = new FileOutputStream("destination.txt");
SequenceInputStream sis = new SequenceInputStream(fis1, fis2);
int b;
while ((b = sis.read()) != -1) {
fos.write(b);
}
sis.close();
fis1.close();
fis2.close();
fos.close();
}
}

Reading from an array

So far we’ve read data from files, but what if it’s already in an array? ByteArrayInputStream lets us treat an in-memory array like a stream.

class HelloWorld {
public static void main(String[] args) throws Exception {
byte b[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v'};
ByteArrayInputStream bis = new ByteArrayInputStream(b);
int x;
while ((x = bis.read()) != -1) {
System.out.println((char) x);
}
bis.close();
}
}

That reads the bytes one at a time. To read them all at once, use .readAllBytes():

class HelloWorld {
public static void main(String[] args) throws Exception {
byte b[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v'};
ByteArrayInputStream bis = new ByteArrayInputStream(b);
String str = new String(bis.readAllBytes());
System.out.println(str);
bis.close();
}
}

You can also write onto a byte array output stream:

class HelloWorld {
public static void main(String[] args) throws Exception {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bos.write('a');
bos.write('b');
bos.write('c');
bos.write('d');
byte b[] = bos.toByteArray();
for (byte x : b) {
System.out.println((char) x);
}
bos.close();
}
}