This section covers the most frequently asked theory questions. Test your knowledge by trying to answer
the question first, then click "Show Answer" to reveal the correct response.
1. What is a stream? Differentiate between byte streams and
character streams.
A stream is an abstraction that represents a sequence of data moving from a
source to a destination. In Java, streams are used to perform all I/O operations.
Byte Streams (java.io.*Stream):
Used to read and write binary data (raw bytes), such as images, audio, or executable
files.
Operate on data 8 bits at a time.
Base abstract classes are InputStream and
OutputStream.
2. What is the difference between a text file and a binary
file?
Text File:
Stores data as human-readable characters (e.g., ASCII, UTF-8).
Can be opened and read by simple text editors (like Notepad).
Typically handled using Character Streams (FileReader,
FileWriter, PrintWriter).
Uses special characters for newlines (e.g., \n, \r\n).
Binary File:
Stores data in the same raw binary format as it is stored in computer memory (0s and
1s).
Not human-readable; appears as gibberish in a text editor.
Used for images, audio, executables, or structured data (like saving a
double or int directly).
Typically handled using Byte Streams (FileInputStream,
FileOutputStream, DataInputStream).
More compact and faster to read/write for non-textual data.
3. What is the purpose of buffered streams like
`BufferedReader` and `BufferedWriter`?
Buffered streams add a memory buffer to other streams (like
FileReader or FileWriter) to improve I/O performance.
Instead of making a system call for every single byte or character read/written (which is
very slow), buffered streams read/write large chunks of data into/from the buffer at once.
Subsequent read/write operations are then performed on this fast memory buffer.
BufferedReader reads large chunks from a file into its
buffer. When you call read() or readLine(), it just gives you
data from the buffer. It only reads from the (slow) disk again when the buffer is empty.
It also provides the very useful readLine() method.
BufferedWriter stores data you write in its buffer. It
only writes the data to the (slow) disk when the buffer is full or when you explicitly
call the flush() method.
This "wrapper" pattern significantly reduces the number of disk accesses and speeds up I/O
operations.
4. Differentiate between `FileWriter` and `PrintWriter`.
FileWriter:
A simple character stream class for writing to text files.
Provides basic write() methods to write single characters, character
arrays, or strings.
Does not have methods to directly write primitive data types (like int,
double) in their text form.
Does not have a method to automatically add a newline, like println(). You
must manually write \n.
Throws IOException which must be handled.
PrintWriter:
A more advanced, "wrapper" stream that adds functionality.
Provides the very convenient print() and
println() methods, which can write any primitive data type
(int, double, boolean, etc.) as a human-readable
string.
The println() method automatically adds a newline character.
It can "wrap" other streams, like a FileWriter (often wrapped in a
BufferedWriter for efficiency).
It has an "auto-flush" capability (optional).
In summary: You almost always want to use PrintWriter (wrapped
around a BufferedWriter(new FileWriter(...))) because println() is
much easier to use than FileWriter's basic write().
5. What is the `File` class used for? Name 4 methods.
The File class (from java.io.File) is not a
stream. It does not read or write data.
Instead, it is used to represent the metadata of a file or directory path.
It allows you to manipulate the file or directory itself.
Common Methods:
exists(): (boolean) Returns true if the file
or directory exists.
isFile(): (boolean) Returns true if it's a
file (not a directory).
isDirectory(): (boolean) Returns true if it's
a directory.
length(): (long) Returns the size of the file in bytes.
getName(): (String) Returns the name of the file or
directory.
delete(): (boolean) Deletes the file or directory.
createNewFile(): (boolean) Creates a new, empty file.
mkdir(): (boolean) Creates a new directory.
6. How is the end of a file (EOF) detected in Java?
The method for detecting EOF depends on the stream and method being used:
BufferedReader.readLine(): Returns
null when it tries to read past the end of the file. This
is the most common way for text files.
FileReader.read() (or
FileInputStream.read()): These character/byte-level read methods return
-1 when the end of the stream is reached.
DataInputStream.read...(): When reading primitive data
types (e.g., readInt(), readDouble()), if the stream ends
before the data type is fully read, it throws an
EOFException (End of File Exception). This is typically
caught in a try-catch block.
7. What is `RandomAccessFile` and how is it different?
RandomAccessFile is a special class that is not part of the
InputStream/OutputStream hierarchy. It combines features of both
reading and writing to a file.
Key Differences:
Non-Sequential Access: Unlike streams, which read/write data
sequentially from start to finish, RandomAccessFile allows you to move a
file pointer (or "seek") to any byte position in the file and
read/write from that exact location.
Read/Write: It can both read and write to the same file, depending on
the "mode" it's opened in.
"r": Read-only mode.
"rw": Read-write mode.
File Pointer: It uses a file pointer (a long integer) to track the
current location. Methods like seek(long pos) move the pointer, and
getFilePointer() returns its current position.
Data Types: It has methods similar to DataInputStream and
DataOutputStream (e.g., readInt(), writeDouble(),
readLine()) for handling binary data.
It is very useful for database-like operations, such as updating a specific record in the
middle of a file without rewriting the entire file.
This section provides common programming problems. Analyze the problem, try to write the solution
yourself, and then click "Show Solution" to compare your code.
1. Write a program to read text from the user until they type
"STOP", and write each line to a text file named "story.txt".
import java.io.*;
import java.util.Scanner;
public class WriteStory {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
FileWriter fw = null;
BufferedWriter bw = null;
PrintWriter pw = null;
try {
// Setup the writers
fw = new FileWriter("story.txt"); // Can set append mode: new FileWriter("story.txt", true)
bw = new BufferedWriter(fw);
pw = new PrintWriter(bw);
System.out.println("Enter your story (type 'STOP' on a new line to finish):");
String line = "";
while (true) {
line = sc.nextLine();
if (line.equalsIgnoreCase("STOP")) {
break;
}
pw.println(line); // Write the line to the file
}
System.out.println("Story saved successfully to story.txt");
} catch (IOException e) {
System.err.println("An error occurred while writing to the file: " + e.getMessage());
} finally {
// Always close streams in the finally block, in reverse order of creation
try {
if (pw != null) pw.close();
if (bw != null) bw.close();
if (fw != null) fw.close();
if (sc != null) sc.close();
} catch (IOException e) {
System.err.println("Error closing streams: " + e.getMessage());
}
}
}
}
2. Write a program to read the contents of "story.txt" and
display them on the console, along with a count of the total number of lines.
import java.io.*;
public class ReadStory {
public static void main(String[] args) {
FileReader fr = null;
BufferedReader br = null;
int lineCount = 0;
try {
fr = new FileReader("story.txt");
br = new BufferedReader(fr);
String line;
System.out.println("Contents of story.txt:");
System.out.println("-------------------------");
// Loop continues as long as readLine() does not return null
while ((line = br.readLine()) != null) {
System.out.println(line);
lineCount++;
}
System.out.println("-------------------------");
System.out.println("Total number of lines: " + lineCount);
} catch (FileNotFoundException e) {
System.err.println("Error: The file 'story.txt' was not found.");
} catch (IOException e) {
System.err.println("An error occurred while reading the file: " + e.getMessage());
} finally {
try {
if (br != null) br.close();
if (fr != null) fr.close();
} catch (IOException e) {
System.err.println("Error closing streams: " + e.getMessage());
}
}
}
}
3. Write a program to store student records (int roll, String
name, double marks) into a binary file named "students.dat".
import java.io.*;
import java.util.Scanner;
public class WriteBinaryData {
public static void main(String[] args) {
FileOutputStream fos = null;
DataOutputStream dos = null;
Scanner sc = new Scanner(System.in);
try {
fos = new FileOutputStream("students.dat");
dos = new DataOutputStream(fos);
char choice;
do {
System.out.print("Enter Roll Number: ");
int roll = sc.nextInt();
sc.nextLine(); // Consume newline
System.out.print("Enter Name: ");
String name = sc.nextLine();
System.out.print("Enter Marks: ");
double marks = sc.nextDouble();
// Write data in binary format
dos.writeInt(roll);
dos.writeUTF(name); // writeUTF is good for Strings
dos.writeDouble(marks);
System.out.print("Do you want to add another record? (y/n): ");
choice = sc.next().charAt(0);
} while (choice == 'y' || choice == 'Y');
System.out.println("Student records saved to students.dat");
} catch (IOException e) {
System.err.println("Error writing to binary file: " + e.getMessage());
} finally {
try {
if (dos != null) dos.close();
if (fos != null) fos.close();
if (sc != null) sc.close();
} catch (IOException e) {
System.err.println("Error closing streams: " + e.getMessage());
}
}
}
}
4. Write a program to read all student records from
"students.dat" and display them.
import java.io.*;
public class ReadBinaryData {
public static void main(String[] args) {
FileInputStream fis = null;
DataInputStream dis = null;
boolean eof = false; // End-of-file flag
try {
fis = new FileInputStream("students.dat");
dis = new DataInputStream(fis);
System.out.println("Reading student records from students.dat:");
System.out.println("----------------------------------------");
System.out.printf("%-10s %-20s %-10s\n", "Roll No", "Name", "Marks");
System.out.println("----------------------------------------");
// We must read data in the *exact* same order and format it was written
while (!eof) {
try {
int roll = dis.readInt();
String name = dis.readUTF();
double marks = dis.readDouble();
System.out.printf("%-10d %-20s %-10.2f\n", roll, name, marks);
} catch (EOFException e) {
// This exception signals the end of the file
eof = true;
}
}
System.out.println("----------------------------------------");
System.out.println("End of file reached.");
} catch (FileNotFoundException e) {
System.err.println("Error: The file 'students.dat' was not found.");
} catch (IOException e) {
System.err.println("An error occurred while reading the file: " + e.getMessage());
} finally {
try {
if (dis != null) dis.close();
if (fis != null) fis.close();
} catch (IOException e) {
System.err.println("Error closing streams: " + e.getMessage());
}
}
}
}
5. Write a program to copy the contents of "source.txt" to
"destination.txt" using character streams.
import java.io.*;
public class CopyFile {
public static void main(String[] args) {
FileReader fr = null;
FileWriter fw = null;
try {
fr = new FileReader("source.txt");
fw = new FileWriter("destination.txt");
int ch; // Variable to hold one character (as an int)
// Read one character at a time
// read() returns -1 at the end of the file
while ((ch = fr.read()) != -1) {
fw.write(ch); // Write that character to the destination
}
System.out.println("File copied successfully.");
} catch (FileNotFoundException e) {
System.err.println("Error: source.txt not found.");
} catch (IOException e) {
System.err.println("Error during file copy: " + e.getMessage());
} finally {
try {
if (fr != null) fr.close();
if (fw != null) fw.close();
} catch (IOException e) {
System.err.println("Error closing streams: " + e.getMessage());
}
}
}
}
This section provides a quick reference for the most important classes in java.io. Click on
any class to see its purpose and common methods.
Purpose: Represents a file or directory path. Used for metadata and
manipulation (create, delete, rename, check existence), not for reading/writing data.
Common Methods:
boolean exists(): Checks if the file/directory exists.
boolean isFile(): Checks if it's a file.
boolean isDirectory(): Checks if it's a directory.
long length(): Returns file size in bytes.
String getName(): Returns the file/directory name.
boolean createNewFile(): Creates an empty file.
boolean delete(): Deletes the file/directory.
Purpose: A character stream for reading from text files. Reads character by
character.
Common Methods:
int read(): Reads a single character and returns it as an int.
Returns -1 at EOF.
int read(char[] cbuf): Reads characters into a buffer array.
void close(): Closes the stream.
Note: Almost always wrapped in a BufferedReader for
efficiency.
Purpose: A character stream for writing to text files. Writes character by
character.
Common Methods:
void write(int c): Writes a single character.
void write(String str): Writes a string.
void close(): Closes the stream.
Note: Almost always wrapped in a BufferedWriter
and/or PrintWriter for efficiency and better methods.
Purpose: A "wrapper" stream that adds a buffer to another
Reader (like FileReader) for efficient reading. Provides
line-by-line reading.
Common Methods:
String readLine(): Reads a full line of text, excluding the newline
character. Returns null at EOF.
int read(): Reads a single character (from the buffer).
void close(): Closes the stream.
Purpose: A "wrapper" stream that adds convenient print() and
println() methods for writing formatted text. This is the preferred class for
writing to text files.
Common Methods:
void println(String s): Prints a string followed by a newline.
void println(int i): Prints an integer (as text) followed by a newline.
void println(double d): Prints a double (as text) followed by a newline.
void print(...): Same as above, but without the newline.
void close(): Closes the stream.
Purpose: A byte stream "wrapper" (for FileInputStream) that
lets you read primitive Java data types from a binary file.
Common Methods:
int readInt(): Reads 4 bytes and returns an int.
double readDouble(): Reads 8 bytes and returns a double.
boolean readBoolean(): Reads 1 byte and returns a boolean.
String readUTF(): Reads a string encoded in UTF format.
void close(): Closes the stream.
Note: Throws EOFException if end-of-file is reached
while reading.
Purpose: A byte stream "wrapper" (for FileOutputStream) that
lets you write primitive Java data types to a binary file.
Common Methods:
void writeInt(int v): Writes an int as 4 bytes.
void writeDouble(double v): Writes a double as 8 bytes.
void writeBoolean(boolean v): Writes a boolean as 1 byte.
void writeUTF(String s): Writes a string in UTF format.
void close(): Closes the stream.
Purpose: A special class for reading AND writing to a file, with
non-sequential (random) access using a file pointer.
Common Methods:
Constructor(String name, String mode): Mode is "r" (read) or "rw"
(read-write).
void seek(long pos): Moves the file pointer to a specific byte position.
long getFilePointer(): Returns the current byte position.
int readInt(), void writeInt(int v): (And other data types).