Lesson 12: File Input/Output (I/O)
Goals
- Learn how we read from and write to file.
Input & Output Stream
What is a Stream
, InputStream
& OutputStream
?
Geographically:
A stream is a body of water that flows on Earth’s surface i.e water flowing from one place to another.
In computer science:
_a stream is a sequence of data elements made available over time. A stream can be thought of as items on a conveyor belt being processed one at a time rather than in large batches.
A bytestream is a stream of bytes._
Data or information are stored in memory as a sequence of bits or bytes which is a sequence of 8 bits and in order to transfer this data from one place to another we need a bytestream.
Scenarios where bytestream are used:
- Uploading or sending data over a network
- Downloading or receiving data over a network
- Reading data or files from a file system e.g. a hard drive of a computer
- Writing data or files into a file system e.g. a hard drive of a computer
an
InputStream
is an abstract class representing an inflow of bytes. To read data from a bytestream, one uses anInputStream
System.in
is anInputStream
that can be used to read data from the standard input stream.
public abstract class InputStream implements Closeable {
//Reads the next byte of data from the input stream as an int between 0 and 255.
//Returns -1 if there is no data.
public abstract int read() throws IOException;
//Closes this input stream and releases any system resources associated with the stream.
public abstract void close() throws IOException;
}
Q: What is a FileInputStream
?
an
OutputStream
is an abstract class representing an outflow of bytes. To write data into a bytestream, one uses anOutputStream
.System.out
is anOutputStream
that can be used to read data from the standard output stream.
public abstract class OutputStream implements Closeable {
//Writes the specified byte to this output stream.
public abstract void write(int b) throws IOException;
//Closes this output stream and releases any system resources associated with the stream.
public abstract void close() throws IOException;
}
Q: What is a FileOutputStream
?
A bytestream is usually opened upon creation, however; one must close a bytestream after usage.
What is a Reader
& Writer
?
A String
is a sequence or stream of characters and because data is often exchanged in human-readable String
format, therefore we need both the Reader
and Writer
to easily read and write characters into bytestreams.
Q: How many bytes is a character?
A Reader
is an abstract class for reading characters to streams while a Writer
is an abstract class used for
writing characters to stream.
public abstract class Reader implements Closeable {
//Reads and returns a single character as in int and returns -1 if it is the end of the stream.
public abstract int read() throws IOException;
//Closes this reader and releases any system resources associated with the stream.
public abstract void close() throws IOException;
}
public abstract class Writer implements Readable, Closeable {
//Writes the specified character to the output stream.
public abstract void write(int b) throws IOException;
//Closes this writer stream and releases any system resources associated with the stream.
public abstract void close() throws IOException;
}
Q: What is an InputStreamReader
? Q: What is a OutputStreamWriter
? Q: What is a FileReader
? Q: What is
a FileWriter
?
A character encoding tells the system how to interpret raw bytes into real characters. In order to use a Reader
or
Writer
we must specify the character encoding.
The default character encoding in Java is UTF-8
.
Reading and Writing Files
- A
FileInputStream
is anInputStream
that reads input bytes from a file in a file system. - A
FileOutputStream
is anOutputStream
that writes bytes into a file in a file system. - A
FileReader
is anInputStreamReader
that reads characters from a file in a file system. - A
FileWriter
is anOutputStreamWriter
that writes characters into a file in a file system. - A file path is a string describing the location of a file in a file system.
To read from a file, we need the file path and a FileReader
. A FileInputStream
will be created and be used by the
FileReader
.
To write into a file, we need the file path and a FileWriter
. A FileOutputStream
will be created and be used by the
FileWriter
.
By default a FileWriter
or FileOutputStream
removes the existing content of the file and starts writing data into
it. However, both the FileWriter
and FileOutputStream
can be created and opened in append
mode; this implies that
whatever is written to the stream is appended to the existing file i.e. we do not delete the existing content of the
file.
Example: Read and write a text file character by character
The Hard Way
public class ReadFileCharByChar {
public static void main(String[] args) {
FileReader reader = null;
FileWriter writer = null;
try {
reader = new FileReader("input-file.txt");
writer = new FileWriter("output-file.txt");
int next = -1;
while ((next = reader.read()) != -1) {
writer.write(next);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
The Easier Way
public class ReadFileCharByChar {
public static void main(String[] args) {
try (FileReader reader = new FileReader("input-file.txt");
FileWriter writer = new FileWriter("output-file.txt")) {
int next;
while ((next = reader.read()) != -1) {
writer.write(next);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
BufferedReader
& BufferedWriter
BufferedReader
: Reads text from a character-input stream, buffering characters to provide for the efficient reading of characters, arrays, and lines.
BufferedWriter
: Writes text to a character-output stream, buffering characters to provide for the efficient writing of single characters, arrays, and strings.
This is what you often need because processing files are often done line by line and both the BufferedReader
and
BufferedWriter
allows us to do that. It is the responsibility of the programmer to be aware of the following
especially when reading a file.
- The encoding of the text files
- The size of the file
- The maximum line length of the file
- The number of lines of the file
This information allows the programmer to make an informed decision of how to process the file without any interruption and the biggest concerns are reading exactly what is expected and ensuring that it fits into memory.
The Hard Way
public class ReadFileLineByLine {
public static void main(String[] args) {
BufferedReader reader = null;
BufferedWriter writer = null;
try {
reader = new BufferedReader(new FileReader("input-file.txt"));
writer = new BufferedWriter(new FileWriter("output-file.txt"));
String next = null;
while ((next = reader.readLine()) != null) {
writer.write(next);
writer.newLine();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
The Easier Way
public class ReadFileLineByLine {
public static void main(String[] args) {
try (BufferedReader reader = new BufferedReader(new FileReader("input-file.txt"));
BufferedWriter writer = new BufferedWriter(new FileWriter("output-file.txt"))) {
String next;
while ((next = reader.readLine()) != null) {
writer.write(next);
writer.newLine();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Java 11 tricks
- Read the entire file into string:
String Files.readString(Path path)
Files.readString(Path.of("input-file.txt"));
- Read a file line by line:
List<String> Files.readAllLines(Path path)
List<String> lines = Files.readAllLines(Path.of("input-file.txt"));
- Write lines into a file:
Path Files.write(Path path, List<String> lines)
List<String> lines = List.of("one", "two"); Files.write(Path.of("output-file.txt"), lines);
- Write string into a file:
Path Files.writeString(Path path, String string, OpenOption...options)
String string = "one\ntwo\n"; Files.writeString(Path.of("output-file.txt"), string);
Be careful using these methods since you lose control over the underlying resources or risk reading a huge file into memory which can lead to the application running out of memory and crashing.
Please use the above methods only if necessary for the assignment exercise.
Github Classroom Exercises
Github Classroom Assignment
Follow the link, accept and download the assignment from GitHub Classroom
Materials
- http://www.c-jump.com/bcc/c257c/Week10/Week10.html``