Unit 3: File I/O and JDBC
I. Orientation — Persistent Data in Java
File I/O and JDBC are Java mechanisms for working with persistent data. Java NIO.2, introduced in Java 7, provides path-based file-system operations through java.nio.file, while JDBC (Java Database Connectivity) provides a standard API for communicating with relational databases.
- Defining properties:
- Persistence: Files and databases retain data after a Java program terminates.
- Abstraction:
Pathabstracts a file-system location; JDBC interfaces abstract vendor-specific database communication. - Resource management: Streams, database connections, statements, and result sets must be closed, normally through
try-with-resources. - Exception handling: NIO.2 operations commonly throw
IOException; JDBC operations throwSQLException. - Separation of concerns: Application code uses standard Java APIs, while the operating system or JDBC driver performs platform-specific work.
- Security: File permissions, database credentials, prepared statements, and least-privilege access protect persistent data.
II. Java NIO.2 File and Directory Operations
NIO.2 represents locations as Path objects and performs operations through the utility class Files, providing more flexible and scalable file handling than the older java.io.File API.
A. Using the Path interface to operate on file and directory paths
The Path interface represents a hierarchical file-system path without requiring the referenced file or directory to exist.
- Creating paths:
Path.of()creates aPathfrom one or more strings; the older equivalent isPaths.get().
Path report = Path.of("data", "reports", "sales.txt");
Path absolute = Path.of("/var/log/app.log");-
Path components:
- Root:
report.getRoot()returns the root component, if present. - File name:
report.getFileName()returnssales.txt. - Parent:
report.getParent()returnsdata/reports. - Name count:
report.getNameCount()counts elements excluding the root. - Subpath:
report.subpath(0, 2)returns the first two name elements.
- Root:
-
Relative and absolute paths:
- A relative path, such as
data/input.txt, is interpreted from the current working directory. - An absolute path, such as
/home/user/input.txt, identifies a location from the file-system root.
- A relative path, such as
Path normalized = Path.of("data", ".", "temp", "..", "input.txt")
.normalize();
Path fullPath = normalized.toAbsolutePath();- Combining paths:
base.resolve("file.txt")appends a path, whilebase.relativize(target)calculates the path frombasetotarget. - Comparison:
startsWith(),endsWith(), andcompareTo()compare path structures;Files.isSameFile()determines whether two paths locate the same existing file. - Important distinction:
Pathis primarily a path representation. File-system access occurs when methods such astoRealPath()or operations inFilesare called. - Provider dependence: Separators and root conventions depend on the file system, so
Path.of("data", "file.txt")is preferable to manually inserting/or\.
B. Using the Files class to check, delete, copy, or move a file or directory
The Files class contains static methods for inspecting and modifying files and directories identified by Path.
- Checking existence and type:
Files.exists(path)checks whether an entry exists.Files.notExists(path)checks confirmed nonexistence.Files.isRegularFile(path)andFiles.isDirectory(path)inspect entry type.Files.isReadable(path),isWritable(path), andisExecutable(path)inspect accessibility.
Path source = Path.of("data", "input.txt");
if (Files.exists(source) && Files.isRegularFile(source)) {
System.out.println(Files.size(source));
}-
Creating entries:
createFile()creates a new empty file;createDirectory()creates one directory;createDirectories()creates missing parent directories. -
Deleting entries:
Files.delete(path)deletes an entry or throws an exception if deletion fails.Files.deleteIfExists(path)returnsfalseif the entry is absent.
A directory generally must be empty before deletion.
-
Copying:
Files.copy(source, target, options)copies a file or directory entry.
Files.copy(
source,
Path.of("backup", "input.txt"),
StandardCopyOption.REPLACE_EXISTING,
StandardCopyOption.COPY_ATTRIBUTES
);- Moving or renaming:
Files.move()changes an entry’s location; moving within one file system can serve as a rename.
Files.move(
Path.of("draft.txt"),
Path.of("final.txt"),
StandardCopyOption.REPLACE_EXISTING
);- Operation options:
REPLACE_EXISTINGpermits overwriting,COPY_ATTRIBUTESpreserves supported metadata during copying, andATOMIC_MOVErequests an indivisible move when supported. - Failure conditions: Permissions, nonempty directories, existing targets, locks, or unsupported options may produce subclasses of
IOException.
C. Using Stream API with NIO2
NIO.2 methods can expose file-system data as streams, allowing lazy filtering, mapping, and aggregation through the Stream API.
- Directory listing:
Files.list(directory)produces a nonrecursiveStream<Path>containing immediate entries. - Recursive traversal:
Files.walk(start)performs depth-first traversal, whileFiles.find()combines traversal with a predicate. - Line processing:
Files.lines(file)lazily produces aStream<String>using UTF-8 by default or a specifiedCharset.
Path logs = Path.of("logs");
try (Stream<Path> paths = Files.walk(logs)) {
List<Path> errorLogs = paths
.filter(Files::isRegularFile)
.filter(path -> path.toString().endsWith(".log"))
.toList();
}- Resource closure: Streams returned by
Files.list(),walk(),find(), andlines()hold file-system resources and therefore belong intry-with-resources. - Lazy execution: Intermediate operations such as
filter()do not run until a terminal operation such ascount(),forEach(), ortoList()is invoked. - Traversal control:
Files.walk(start, maxDepth)limits recursion;FileVisitOption.FOLLOW_LINKSfollows symbolic links but can expose cycles. - Error handling: Some traversal failures appear as
UncheckedIOExceptionduring stream processing because stream functional interfaces do not naturally propagate checkedIOException. - Suitability: Stream-based traversal is concise for selection and aggregation;
Files.walkFileTree()is preferable when fine-grained visit control or explicit failure handling is required.
III. JDBC Architecture and Database Connectivity
JDBC, primarily defined in java.sql and javax.sql, standardizes database access while delegating database-specific network protocols and SQL transmission to a JDBC driver.
A. Defining the layout of the JDBC API
The JDBC API is organized around interfaces representing a connection, SQL command, returned rows, metadata, and transaction boundaries.
-
Core components:
DriverManager: Selects a registered driver and requests a connection.Connection: Represents a database session and controls transactions.Statement: Executes fixed SQL strings.PreparedStatement: Executes parameterized, precompiled SQL.CallableStatement: Invokes stored procedures.ResultSet: Provides cursor-based access to query rows.SQLException: Reports database-access errors, SQL states, and vendor codes.
-
Typical execution flow:
Application
-> JDBC API
-> JDBC Driver
-> Database
-> ResultSet or update count- Data-source alternative:
javax.sql.DataSourcesupplies connections and supports connection pooling and centralized configuration, making it preferable in managed or production applications. - JDBC types:
java.sql.Typesidentifies SQL types; methods such assetInt(),setString(),getDate(), andgetBigDecimal()map Java values to database values. - Transactions: A
Connectionbegins in auto-commit mode by default. CallingsetAutoCommit(false)permits explicitcommit()orrollback().
B. Connecting to a database by using a JDBC driver
A JDBC driver implements the standard interfaces and translates JDBC operations into the database vendor’s protocol.
- Required information:
- Driver dependency: The vendor’s JDBC driver JAR must be on the classpath or module path.
- JDBC URL: A URL begins with
jdbc:and contains vendor-specific connection details. - Credentials: A database username and password identify and authenticate the client.
String url = "jdbc:mysql://localhost:3306/college";
try (Connection connection =
DriverManager.getConnection(url, "app_user", "secret")) {
System.out.println(connection.isValid(2));
}- Automatic registration: JDBC 4.0-compatible drivers are discovered automatically when their JAR is available. Explicit calls such as
Class.forName("com.mysql.cj.jdbc.Driver")are mainly needed for older drivers or unusual loading environments. - Connection lifecycle: Connections are expensive resources; production systems generally obtain them from a pool rather than opening a new physical connection for every operation.
- Failure diagnosis:
SQLExceptionexposesgetMessage(),getSQLState(), andgetErrorCode()for identifying authentication, network, syntax, or constraint failures.
C. Specifying JDBC driver information externally
External configuration separates deployment-specific connection data from compiled application code.
- Properties file: Values can be stored in a file such as
database.properties.
db.url=jdbc:postgresql://localhost:5432/college
db.user=app_user
db.password=secret- Loading configuration:
Properties config = new Properties();
try (InputStream input =
Files.newInputStream(Path.of("database.properties"))) {
config.load(input);
}
Connection connection = DriverManager.getConnection(
config.getProperty("db.url"),
config.getProperty("db.user"),
config.getProperty("db.password")
);- Deployment alternatives: Environment variables, command-line properties, JNDI, secret managers, and framework configuration systems can provide the same information.
- Benefits: Externalization allows development, testing, and production environments to use different URLs and credentials without recompilation.
- Security limitation: Plain-text passwords should not be committed to source control. Restrictive permissions or a dedicated secret-management service should protect credentials.
IV. Executing SQL and Processing Results
JDBC distinguishes SQL that returns tabular data from SQL that changes database state, and each form has a corresponding execution method.
A. Submitting queries and getting results from the database
A query is submitted through a statement object, and its returned rows are read sequentially from a ResultSet.
- Query execution:
executeQuery()is intended for SQL such asSELECTthat produces aResultSet. - Parameterized SQL: Placeholders marked by
?are assigned through one-based parameter indexes.
String sql =
"SELECT id, name, marks FROM student WHERE marks >= ?";
try (PreparedStatement statement =
connection.prepareStatement(sql)) {
statement.setInt(1, 60);
try (ResultSet results = statement.executeQuery()) {
while (results.next()) {
int id = results.getInt("id");
String name = results.getString("name");
int marks = results.getInt("marks");
System.out.println(id + " " + name + " " + marks);
}
}
}- Cursor behavior: A new
ResultSetcursor starts before the first row;next()advances it and returnsfalseafter the final row. - Column access: Values may be retrieved by column label or one-based position. Labels are clearer and less sensitive to changes in column order.
- SQL
NULL: Primitive getters may return default values, such as0;wasNull()checks whether the last retrieved database value wasNULL. - Security:
PreparedStatementbinds values separately from SQL syntax, preventing user input from changing query structure and reducing SQL-injection risk. - Metadata:
ResultSetMetaDatadescribes returned columns, whileDatabaseMetaDatadescribes database features, tables, and supported operations.
V. JDBC Data Modification
JDBC supports the complete CRUD model: creating, reading, updating, and deleting persistent database records.
A. Performing CRUD operations using the JDBC API
CRUD operations use parameterized SQL and appropriate execution methods to manipulate database rows reliably.
- Create:
INSERTadds a row andexecuteUpdate()returns the number of affected rows.
String sql = "INSERT INTO student(name, marks) VALUES (?, ?)";
try (PreparedStatement ps =
connection.prepareStatement(sql)) {
ps.setString(1, "Anita");
ps.setInt(2, 84);
int inserted = ps.executeUpdate();
}- Read:
SELECTusesexecuteQuery()and processes itsResultSet, as shown in the preceding section. - Update:
UPDATEchanges matching rows; a restrictiveWHEREclause prevents unintended modifications.
PreparedStatement ps = connection.prepareStatement(
"UPDATE student SET marks = ? WHERE id = ?"
);
ps.setInt(1, 91);
ps.setInt(2, 12);
int updated = ps.executeUpdate();- Delete:
DELETEremoves matching rows and also returns an update count.
PreparedStatement ps = connection.prepareStatement(
"DELETE FROM student WHERE id = ?"
);
ps.setInt(1, 12);
int deleted = ps.executeUpdate();- Transaction control: Related changes should succeed or fail together.
connection.setAutoCommit(false);
try {
// Execute related INSERT, UPDATE, or DELETE operations.
connection.commit();
} catch (SQLException exception) {
connection.rollback();
throw exception;
}- Generated keys: Passing
Statement.RETURN_GENERATED_KEYSwhen preparing anINSERTallows retrieval of database-generated identifiers. - Batch operations: Repeated commands can use
addBatch()andexecuteBatch()to reduce database round trips. - Integrity checks: Applications should inspect update counts, handle constraint violations, roll back failed transactions, and close
Connection,Statement, andResultSetobjects throughtry-with-resources.
Did this save you a night before the exam?
LPU Notes is free, and it stays free. Ads cover part of the server bill. The rest comes out of a student's own pocket: the domain, the storage, and keeping the site up through the weeks everyone needs it at once.
The payment button didn't load. An ad blocker or a filtered network is the usual reason. to try again.
Nothing here is ever locked, and nothing unlocks. Chip in only if it was worth it. What it pays for →