Java 二进制流读写与数据库基础入门
1. 二进制流读取
在 Java 中,读取二进制流比读取字符流稍难,但也并非难以掌握。读取二进制流时,最大的障碍在于你必须确切知道写入文件的每个数据项的类型。若文件中存在任何错误数据,程序将无法正常工作。所以,你需要确保文件包含程序所期望的数据。
1.1 涉及的类
为了读取二进制文件,通常会使用以下几个类:
-
File
:用于表示文件本身。
-
FileInputStream
:将输入流连接到文件。
-
BufferedInputStream
:为基本的
FileInputStream
添加缓冲功能,提高流的效率。
-
DataInputStream
:实际用于从流中读取各种数据类型的类。
这些类的重要构造函数和方法如下表所示:
| 类/方法 | 构造函数/方法签名 | 描述 |
| — | — | — |
| BufferedInputStream |
BufferedInputStream(InputStream in)
| 从任何扩展
InputStream
类的对象创建一个带缓冲的输入流,通常传入
FileInputStream
对象。 |
| DataInputStream |
DataInputStream(InputStream in)
| 从任何扩展
InputStream
类的对象创建一个数据输入流,通常传入
BufferedInputStream
对象。 |
| FileInputStream |
FileInputStream(File file)
| 从指定的
File
对象创建一个文件输入流,若文件不存在或为目录,抛出
FileNotFoundException
。 |
| FileInputStream |
FileInputStream(String path)
| 从指定的路径名创建一个文件输入流,若文件不存在或为目录,抛出
FileNotFoundException
。 |
| DataInputStream 方法 |
boolean readBoolean()
| 从输入流读取一个布尔值,抛出
EOFException
和
IOException
。 |
| DataInputStream 方法 |
byte readByte()
| 从输入流读取一个字节值,抛出
EOFException
和
IOException
。 |
| DataInputStream 方法 |
char readChar()
| 从输入流读取一个字符值,抛出
EOFException
和
IOException
。 |
| DataInputStream 方法 |
double readDouble()
| 从输入流读取一个双精度浮点值,抛出
EOFException
和
IOException
。 |
| DataInputStream 方法 |
float readFloat()
| 从输入流读取一个单精度浮点值,抛出
EOFException
和
IOException
。 |
| DataInputStream 方法 |
int readInt()
| 从输入流读取一个整数值,抛出
EOFException
和
IOException
。 |
| DataInputStream 方法 |
long readLong()
| 从输入流读取一个长整数值,抛出
EOFException
和
IOException
。 |
| DataInputStream 方法 |
short readShort()
| 从输入流读取一个短整数值,抛出
EOFException
和
IOException
。 |
| DataInputStream 方法 |
String readUTF()
| 从输入流读取一个以 UTF 格式存储的字符串,抛出
EOFException
、
IOException
和
UTFDataFormatException
。 |
1.2 创建 DataInputStream
要从二进制文件读取数据,需要将
DataInputStream
对象连接到输入文件。可以使用以下嵌套构造函数的方式:
File file = new File("movies.dat");
DataInputStream in = new DataInputStream(
new BufferedInputStream(
new FileInputStream(file) ) );
若嵌套让你感到不适,也可以分步进行:
File file = new File("movies.dat");
FileInputStream fs = new FileInputStream(file);
BufferedInputStream bs = new BufferedInputStream(fs);
DataInputStream in = new DataInputStream(bs);
这两种方式的效果是相同的。
1.3 从数据输入流读取数据
对于二进制文件,不是将整行数据读入程序并解析为各个字段,而是使用
DataInputStream
类的各种
read
方法逐个读取字段。例如,以下代码片段读取单个电影的信息并将数据存储在变量中:
String title = in.readUTF();
int year = in.readInt();
double price = in.readDouble();
需要注意的是,这些
read
方法在文件结束时会抛出
EOFException
,在发生 I/O 错误时会抛出
IOException
。因此,需要在
try/catch
块中调用这些方法。
readUTF
方法还会抛出
UTFDataFormatException
,但该异常是
IOException
的一种,通常不需要单独捕获。
通常会使用
while
循环来读取文件中的所有数据。当文件结束时,会抛出
EOFException
,可以捕获该异常并停止循环。示例代码如下:
boolean eof = false;
while (!eof)
{
try
{
String title = in.readUTF();
int year = in.readInt();
double price = in.readDouble();
// 在这里对数据进行处理
}
catch (EOFException e)
{
eof = true;
}
catch (IOException e)
{
System.out.println("An I/O error has occurred!");
System.exit(0);
}
}
读取完文件后,可以调用
close
方法关闭流:
in.close();
此方法也会抛出
IOException
,因此需要放在
try/catch
块中。
1.4 读取
movies.dat
文件示例
以下是一个完整的程序,用于读取
movies.dat
文件,为每个电影信息创建一个
Movie
对象,并在控制台打印电影信息:
import java.io.*;
import java.text.NumberFormat;
public class ReadBinaryFile
{
public static void main(String[] args)
{
NumberFormat cf = NumberFormat.getCurrencyInstance();
DataInputStream in = getStream("movies.dat");
boolean eof = false;
while (!eof)
{
Movie movie = readMovie(in);
if (movie == null)
eof = true;
else
{
String msg = Integer.toString(movie.year);
msg += ": " + movie.title;
msg += " (" + cf.format(movie.price) + ")";
System.out.println(msg);
}
}
closeFile(in);
}
private static DataInputStream getStream(String name)
{
DataInputStream in = null;
try
{
File file = new File(name);
in = new DataInputStream(
new BufferedInputStream(
new FileInputStream(file) ) );
}
catch (FileNotFoundException e)
{
System.out.println("The file doesn't exist.");
System.exit(0);
}
catch (IOException e)
{
System.out.println("I/O Error creating file.");
System.exit(0);
}
return in;
}
private static Movie readMovie(DataInputStream in)
{
String title = "";
int year = 0;
double price = 0.0;
try
{
title = in.readUTF();
year = in.readInt();
price = in.readDouble();
}
catch (EOFException e)
{
return null;
}
catch (IOException e)
{
System.out.println("I/O Error");
System.exit(0);
}
return new Movie(title, year, price);
}
private static void closeFile(DataInputStream in)
{
try
{
in.close();
}
catch(IOException e)
{
System.out.println("I/O Error closing file.");
System.out.println();
}
}
private static class Movie
{
public String title;
public int year;
public double price;
public Movie(String title, int year, double price)
{
this.title = title;
this.year = year;
this.price = price;
}
}
}
该程序各方法的功能如下:
-
main 方法
:调用
getStream
方法获取数据输入流对象,使用
while
循环调用
readMovie
方法获取电影对象,若电影对象不为空,则打印电影数据,最后调用
closeFile
方法关闭文件。
-
getStream 方法
:为传入的文件名创建
DataInputStream
对象,若抛出异常,程序退出。
-
readMovie 方法
:读取单个电影的数据并创建
Movie
对象,若到达文件末尾,返回
null
。
-
closeFile 方法
:关闭输入流。
-
Movie 类
:作为私有内部类定义,用于存储电影的标题、年份和价格信息。
下面是读取二进制文件的流程 mermaid 图:
graph LR
A[开始] --> B[创建 DataInputStream]
B --> C[进入 while 循环]
C --> D{是否到达文件末尾}
D -- 否 --> E[读取电影信息]
E --> F[处理电影信息]
F --> C
D -- 是 --> G[关闭输入流]
G --> H[结束]
2. 二进制流写入
在 Java 中,若要将数据写入二进制文件,需要使用几个特定的类来实现这一功能。
2.1 涉及的类
以下是写入二进制文件时常用的类:
-
FileOutputStream
:该类与
File
对象连接,创建一个可向文件写入数据的输出流。不过,它的功能有限,只能向文件写入原始字节,即它不具备写入
int
、
double
或字符串等值的能力。
-
BufferedOutputStream
:此类连接到
FileOutputStream
并添加输出缓冲功能。
-
DataOutputStream
:这个类为流添加了写入基本数据类型和字符串的能力。
这些类的重要构造函数和方法如下表所示:
| 类/方法 | 构造函数/方法签名 | 描述 |
| — | — | — |
| DataOutputStream |
DataOutputStream(OutputStream out)
| 为指定的输出流创建一个数据输出流。 |
| BufferedOutputStream |
BufferedOutputStream(OutputStream out)
| 为指定的流创建一个带缓冲的输出流,通常传入
FileOutputStream
对象。 |
| FileOutputStream |
FileOutputStream(File file)
| 从文件创建一个文件写入器,若发生错误,抛出
FileNotFoundException
。 |
| FileOutputStream |
FileOutputStream(File file, boolean append)
| 从文件创建一个文件写入器,若发生错误,抛出
FileNotFoundException
。若第二个参数为
true
,且文件已存在,则将数据添加到文件末尾。 |
| FileOutputStream |
FileOutputStream(String path)
| 从指定的路径名创建一个文件写入器,若发生错误,抛出
FileNotFoundException
。 |
| FileOutputStream |
FileOutputStream(String path, boolean append)
| 从指定的路径名创建一个文件写入器,若发生错误,抛出
FileNotFoundException
。若第二个参数为
true
,且文件已存在,则将数据添加到文件末尾。 |
| DataOutputStream 方法 |
void close()
| 关闭文件。 |
| DataOutputStream 方法 |
void flush()
| 将缓冲区的内容写入磁盘。 |
| DataOutputStream 方法 |
int size()
| 返回写入文件的字节数。 |
| DataOutputStream 方法 |
void writeBoolean(boolean value)
| 向输出流写入一个布尔值,抛出
IOException
。 |
| DataOutputStream 方法 |
void writeByte(byte value)
| 向输出流写入一个字节值,抛出
IOException
。 |
| DataOutputStream 方法 |
void writeChar(char value)
| 向输出流写入一个字符值,抛出
IOException
。 |
| DataOutputStream 方法 |
void writeDouble(double value)
| 向输出流写入一个双精度浮点值,抛出
IOException
。 |
| DataOutputStream 方法 |
void writeFloat(float value)
| 向输出流写入一个单精度浮点值,抛出
IOException
。 |
| DataOutputStream 方法 |
void writeInt(int value)
| 向输出流写入一个整数值,抛出
IOException
。 |
| DataOutputStream 方法 |
void writeLong(long value)
| 向输出流写入一个长整数值,抛出
IOException
。 |
| DataOutputStream 方法 |
void writeShort(short value)
| 向输出流写入一个短整数值,抛出
IOException
。 |
| DataOutputStream 方法 |
void writeUTF(String value)
| 向输出流写入一个以 UTF 格式存储的字符串,抛出
EOFException
、
IOException
和
UTFDataFormatException
。 |
2.2 创建 DataOutputStream
创建
DataOutputStream
对象时,可以使用嵌套构造函数的方式,示例如下:
File file = new File(name);
DataOutputStream out = new DataOutputStream(
new BufferedOutputStream(
new FileOutputStream(file) ) );
若你不喜欢嵌套构造的方式,也可以将其展开:
File file = new File(name);
FileOutputStream fos = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(fos);
DataOutputStream out = new DataOutputStream(bos);
FileOutputStream
类有一个可选的布尔参数,可用于指示若文件已存在是否应追加数据。若要使用此功能,可按如下方式调用构造函数:
File file = new File(name);
DataOutputStream out = new DataOutputStream(
new BufferedOutputStream(
new FileOutputStream(file, true) ) );
若指定
false
或完全省略该参数,现有文件将被删除,其数据也会丢失。
2.3 向二进制流写入数据
成功将
DataOutputStream
连接到文件后,向文件写入不同数据类型的数据只需调用各种
write
方法即可。例如,以下代码将
Movie
对象的数据写入文件:
out.writeUTF(movie.title);
out.writeInt(movie.year);
out.writeDouble(movie.price);
当然,这些方法会抛出
IOException
,因此必须将它们包含在
try/catch
块中。
若在流中包含了
BufferedOutputStream
类,它会在缓冲区中累积数据,直到决定将数据写入磁盘。若你想强制将缓冲区的数据写入磁盘,可以调用
flush
方法,示例如下:
out.flush();
另外,当完成向文件写入数据后,可通过调用
close
方法关闭文件:
out.close();
flush
和
close
方法也会抛出
IOException
,因此需要使用
try/catch
块来捕获异常。
2.4 写入
movies.dat
文件示例
以下是一个程序,用于从硬编码的
Movie
对象数组写入
movies.dat
文件:
import java.io.*;
public class WriteBinaryFile
{
public static void main(String[] args)
{
Movie[] movies = getMovies();
DataOutputStream out = openOutputStream("movies.dat");
for (Movie m : movies)
writeMovie(m, out);
closeFile(out);
}
private static Movie[] getMovies()
{
Movie[] movies = new Movie[10];
movies[0] = new Movie("It’s a Wonderful Life", 1946, 14.95);
movies[1] = new Movie("The Great Race", 1965, 12.95);
movies[2] = new Movie("Young Frankenstein", 1974, 16.95);
movies[3] = new Movie("The Return of the Pink Panther", 1975, 11.95);
movies[4] = new Movie("Star Wars", 1977, 17.95);
movies[5] = new Movie("The Princess Bride", 1987, 16.95);
movies[6] = new Movie("Glory", 1989, 14.95);
movies[7] = new Movie("Apollo 13", 1995, 19.95);
movies[8] = new Movie("The Game", 1997, 14.95);
movies[9] = new Movie("The Lord of the Rings: The Fellowship of the Ring", 2001, 19.95);
return movies;
}
private static DataOutputStream openOutputStream(String name)
{
DataOutputStream out = null;
try
{
File file = new File(name);
out = new DataOutputStream(
new BufferedOutputStream(
new FileOutputStream(file) ) );
return out;
}
catch (IOException e)
{
System.out.println(
"I/O Exception opening file.");
System.exit(0);
}
return out;
}
private static void writeMovie(Movie m, DataOutputStream out)
{
try
{
out.writeUTF(m.title);
out.writeInt(m.year);
out.writeDouble(m.price);
}
catch (IOException e)
{
System.out.println(
"I/O Exception writing data.");
System.exit(0);
}
}
private static void closeFile(DataOutputStream out)
{
try
{
out.close();
}
catch (IOException e)
{
System.out.println("I/O Exception closing file.");
System.exit(0);
}
}
private static class Movie
{
public String title;
public int year;
public double price;
public Movie(String title, int year, double price)
{
this.title = title;
this.year = year;
this.price = price;
}
}
}
该程序各方法的功能如下:
-
main 方法
:调用
getMovies
方法获取
Movie
对象数组,调用
openOutputStream
方法获取用于向文件写入数据的输出流,使用增强
for
循环调用
writeMovie
方法将电影数据写入文件,最后调用
closeFile
方法关闭文件。
-
getMovies 方法
:创建要写入文件的电影数组。
-
openOutputStream 方法
:为程序创建
DataOutputStream
对象,以便向文件写入数据。
-
writeMovie 方法
:接受两个参数,即要写入的电影和用于写入数据的输出流。
-
closeFile 方法
:关闭文件。
-
Movie 类
:作为内部类包含在内,用于存储电影的标题、年份和价格信息。
下面是写入二进制文件的流程 mermaid 图:
graph LR
A[开始] --> B[创建 DataOutputStream]
B --> C[获取 Movie 对象数组]
C --> D[遍历 Movie 对象数组]
D --> E[向文件写入电影信息]
E --> F{是否遍历完所有电影}
F -- 否 --> D
F -- 是 --> G[刷新缓冲区]
G --> H[关闭输出流]
H --> I[结束]
3. 数据库基础入门
SQL(Structured Query Language)即结构化查询语言,它是关系型数据库的通用语言,也是 Java 中数据库处理的基础。需要注意的是,Java 本身并未提供 SQL 的具体实现,而是提供了 JDBC(Java DataBase Connectivity),它允许你制定 SQL 语句,将其发送到数据库服务器并处理结果。为了使用 JDBC,你需要了解一些 SQL 数据库的基本概念以及足够的 SQL 知识来制定合理的 SQL 语句。
3.1 什么是关系型数据库
关系型数据库是计算机领域中被广泛使用和滥用的术语之一。关系型数据库可以是:
- 一种将数据存储在表中的数据库,表之间可以基于共同信息建立关系。例如,客户表和发票表可能都包含客户编号列,该列可作为表之间关系的基础。
虽然本章不会让你成为数据库专家或 SQL 高手,但它涵盖了足够的 SQL 知识,能让你开始使用 JDBC。后续将介绍更多关于数据库操作的内容,如创建表、选择数据、连接数据以及更新和删除数据等。
超级会员免费看
4595

被折叠的 条评论
为什么被折叠?



