目录
- 异常机制和File类
- File类
- IO流
- 概念
- 分类
- 字符流
- FileWriter类
- FileReader类
- 字节流
- FileOutputStream类
- FileInputStream类
- 缓冲流
- BufferedOutputStream类
- BufferedInputStream类
- BufferedWriter类
- BufferedReader类
- 打印流
- PrintStream类
- PrintWriter类
- 转化流
- OutputStreamWriter类
- InputStreamReader类
- 字符编码
- 数据流
- DataOutputStream类
- DataInputStream类
- 对象流
- ObjectOutputStream类
- ObjectInputStream类
- 序列化版本号
- transient关键字
- 经验的分享
- RandomAccessFile类
异常机制和File类
1.异常机制
1. 基本概念
-
异常就是"不正常"的含义,在Java语言中主要指程序执行中发生的不正常情况。
-
java.lang.Throwable类是Java语言中错误(Error)和异常(Exception)的超类。
-
其中Error类主要用于描述Java虚拟机无法解决的严重错误,通常无法编码解决,如:JVM挂掉了等。
-
其中Exception类主要用于描述因编程错误或偶然外在因素导致的轻微错误,通常可以编码解决, 如:0作为除数等。
2. 异常的分类
- java.lang.Exception类是所有异常的超类,主要分为以下两种:
- RuntimeException - 运行时异常,也叫作非检测性异常
- IOException和其它异常 - 其它异常,也叫作检测性异常,所谓检测性异常就是指在编译阶段都能被编译器检测出来的异常。 异常抛出就是指将编译阶段的错误推迟到运行阶段
- 其中RuntimeException类的主要子类:
- ArithmeticException类 - 算术异常
- ArrayIndexOutOfBoundsException类 - 数组下标越界异常
- NullPointerException - 空指针异常
- ClassCastException - 类型转换异常
- NumberFormatException - 数字格式异常
- 注意: 当程序执行过程中发生异常但又没有手动处理时,则由Java虚拟机采用默认方式处理异常,而默认 处理方式就是:打印异常的名称、异常发生的原因、异常发生的位置以及终止程序。
3. 异常的捕获
语法格式
语法格式
try {
编写可能发生异常的代码;
}
catch(异常类型 引用变量名) {
编写针对该类异常的处理代码;
}
...
finally {
编写无论是否发生异常都要执行的代码;
}
-
注意事项
-
当需要编写多个catch分支时,切记小类型应该放在大类型的前面;
-
懒人的写法: catch(Exception e) {}
-
finally通常用于进行善后处理,如:关闭已经打开的文件等。
-
执行流程
try { a; b; - 可能发生异常的语句 c; }catch(Exception ex) { d; }finally { e; } 当没有发生异常时的执行流程:a b c e; 当发生异常时的执行流程:a b d e;
-
异常的抛出
-
基本概念
-
在某些特殊情况下有些异常不能处理或者不便于处理时,就可以将该异常转移给该方法的调用者, 这种方法就叫异常的抛出。当方法执行时出现异常,则底层生成一个异常类对象抛出,此时异常代码后续的代码就不再执行。
-
语法格式
访问权限 返回值类型 方法名称(形参列表) throws 异常类型1,异常类型2,...{ 方法体; } 如: public void show() throws IOException{}
-
方法重写的原则
- a.要求方法名相同、参数列表相同以及返回值类型相同,从jdk1.5开始支持返回子类类型;
- b.要求方法的访问权限不能变小,可以相同或者变大;
- c.要求方法不能抛出更大的异常;
-
注意: 子类重写的方法不能抛出更大的异常、不能抛出平级不一样的异常,但可以抛出一样的异常、更小的异常以及不抛出异常。
-
经验分享
- 若父类中被重写的方法没有抛出异常时,则子类中重写的方法只能进行异常的捕获处理。
- 若一个方法内部又以递进方式分别调用了好几个其它方法,则建议这些方法内可以使用抛出的方法处理到最后一层进行捕获方式处理。
-
自定义异常
- 当需要在程序中表达年龄不合理的情况时,而Java官方又没有提供这种针对性的异常,此时就需要 程序员自定义异常加以描述。
- 实现流程
- a.自定义xxxException异常类继承Exception类或者其子类。
- b.提供两个版本的构造方法,一个是无参构造方法,另外一个是字符串作为参数的构造方法。
- Java采用的异常处理机制是将异常处理的程序代码集中在一起,与正常的程序代码分开,使得程序 简洁、优雅,并易于维护。
public class AgeException extends Exception {
static final long serialVersionUID = 7818375828146090155L; // 序列化的版本号 与序列化操作有关系
public AgeException() {
}
public AgeException(String message) {
super(message);
}
}
File类
1. 基本概念
- java.io.File类主要用于描述文件或目录路径的抽象表示信息,可以获取文件或目录的特征信息, 如:大小等。
2. 常用方法
方法声明 | 方法介绍 |
---|---|
File(String pathname) | 根据参数指定的路径名来构造对象 |
File(String parent, String child) | 根据参数指定的父路径和子路径信息构造对象 |
File(File parent, String child) | 根据参数指定的父抽象路径和子路径信息构造对象 |
boolean exists() | 测试此抽象路径名表示的文件或目录是否存在 |
String getName() | 用于获取文件的名称 |
long length() | 返回由此抽象路径名表示的文件的长度 |
long lastModified() | 用于获取文件的最后一次修改时间 |
String getAbsolutePath() | 用于获取绝对路径信息 |
boolean delete() | 用于删除文件,当删除目录时要求是空目录 |
boolean createNewFile() | 用于创建新的空文件 |
boolean mkdir() | 用于创建目录 |
boolean mkdirs() | 用于创建多级目录 |
File[] listFiles() | 获取该目录下的所有内容 |
boolean isFile() | 判断是否为文件 |
boolean isDirectory() | 判断是否为目录 |
File[] listFiles(FileFilter filter) | 获取目录下满足筛选器的所有内容 |
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.Date;
public class FileTest {
// 自定义成员方法实现指定目录以及子目录中所有内容的打印
public static void show(File file) {
// 获取目录f3下的所有内容并记录到一维数组中
File[] filesArray = file.listFiles();
// 遍历数组
for (File tf: filesArray) {
String name = tf.getName();
// 判断是否为文件,若是则直接打印文件名称
if (tf.isFile()) {
System.out.println(name);
}
// 若是目录,则使用[]将目录名称括起来
if (tf.isDirectory()) {
System.out.println("[" + name + "]");
show(tf);
}
}
}
public static void main(String[] args) throws IOException {
// 1.构造File类型的对象与d:/a.txt文件关联
File f1 = new File("d:/a.txt");
// 2.若文件存在则获取文件的相关特征信息并打印后删除文件
if (f1.exists()) {
System.out.println("文件的名称是:" + f1.getName());
System.out.println("文件的大小是:" + f1.length());
Date d1 = new Date(f1.lastModified());
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("文件的最后一次修改时间:" + sdf.format(d1));
// 绝对路径: 主要指以根目录开始的路径信息,如:c:/ d:/ /..
// 相对路径: 主要指以当前目录所在位置开始的路径信息,如:./ ../ 相对路径
System.out.println("文件的绝对路径信息是:" + f1.getAbsolutePath());
System.out.println(f1.delete()? "文件删除成功": "文件删除失败");
} else {
// 3.若文件不存在则创建新的空文件
System.out.println(f1.createNewFile()? "文件创建成功": "文件创建失败!");
}
System.out.println("---------------------------------------------------------");
// 4.实现目录的删除和创建
File f2 = new File("d:/捣乱/猜猜我是谁/你猜我猜不猜/死鬼");
if (f2.exists()) {
System.out.println("目录名称是:" + f2.getName());
System.out.println(f2.delete()? "目录删除成功": "目录删除失败");
} else {
//System.out.println(f2.mkdir()? "目录创建成功": "目录创建失败"); // 创建单层目录
System.out.println(f2.mkdirs()? "目录创建成功": "目录创建失败"); // 创建多层目录
}
System.out.println("---------------------------------------------------------");
// 5.实现将指定目录中的所有内容打印出来
File f3 = new File("d:/捣乱");
// 获取目录f3下的所有内容并记录到一维数组中
File[] filesArray = f3.listFiles();
// 遍历数组
for (File tf: filesArray) {
String name = tf.getName();
// 判断是否为文件,若是则直接打印文件名称
if (tf.isFile()) {
System.out.println(name);
}
// 若是目录,则使用[]将目录名称括起来
if (tf.isDirectory()) {
System.out.println("[" + name + "]");
}
}
System.out.println("---------------------------------------------------------");
// 6.实现目录中所有内容获取的同时进行过滤
// 匿名内部类的语法格式:接口/父类类型 引用变量名 = new 接口/父类类型() { 方法的重写 };
/*FileFilter fileFilter = new FileFilter() {
@Override
public boolean accept(File pathname) {
// 若文件名是以.avi为结尾,则返回true表示保留 否则返回false就是表示丢弃
return pathname.getName().endsWith(".avi");
}
};*/
// Lambda表达式的格式:(参数列表) -> {方法体}
FileFilter fileFilter = (File pathname) -> {return pathname.getName().endsWith(".avi");};
File[] filesArray2 = f3.listFiles(fileFilter);
for (File tf : filesArray2) {
System.out.println(tf);
}
System.out.println("---------------------------------------------------------");
// 7.使用递归的思想获取目录以及子目录中的内容
show(new File("d:/捣乱"));
}
}
IO流
概念
- IO就是Input和Output的简写,也就是输入和输出的含义。
- IO流就是指读写数据时像流水一样从一端流到另外一端,因此得名为“流"。
分类
-
按照读写数据的基本单位不同,分为 字节流 和 字符流。
其中字节流主要指以字节为单位进行数据读写的流,可以读写任意类型的文件。
其中字符流主要指以字符(2个字节)为单位进行数据读写的流,只能读写文本文件。
-
按照读写数据的方向不同,分为 输入流 和 输出流(站在程序的角度)。
其中输入流主要指从文件中读取数据内容输入到程序中,也就是读文件。
其中输出流主要指将程序中的数据内容输出到文件中,也就是写文件。
-
按照流的角色不同分为节点流和处理流。
其中节点流主要指直接和输入输出源对接的流。
其中处理流主要指需要建立在节点流的基础之上的流。
字符流
FileWriter类
概念
- java.io.FileWriter类主要用于将文本内容写入到文本文件。
常用方法
方法声明 | 功能介绍 |
---|---|
FileWriter(String fileName) | 根据参数指定的文件名构造对象 |
FileWriter(String fileName, boolean append) | 以追加的方式根据参数指定的文件名来构造对象 |
void write(int c) | 写入单个字符 |
void write(char[] cbuf, int off, int len) | 将指定字符数组中从偏移量off开始的len个字符写入此 文件输出流 |
void write(char[] cbuf) | 将cbuf.length个字符从指定字符数组写入此文件输出 流中 |
void flush() | 刷新流 |
void close() | 关闭流对象并释放有关的资源 |
import java.io.FileWriter;
import java.io.IOException;
public class FileWriterTest {
public static void main(String[] args) {
// 选中代码后可以使用 ctrl+alt+t 来生成异常的捕获代码等
FileWriter fw = null;
try {
// 1.构造FileWrite类型的对象与d:/a.txt文件关联
// 若文件不存在,该流会自动创建新的空文件
// 若文件存在,该流会清空文件中的原有内容
fw = new FileWriter("d:/a.txt");
// 以追加的方式创建对象去关联文件
// 若文件不存在则自动创建新的空文件,若文件存在则保留原有数据内容
//fw = new FileWriter("d:/a.txt", true);
// 2.通过流对象写入数据内容 每当写入一个字符后则文件中的读写位置向后移动一位
fw.write('a');
// 准备一个字符数组
char[] cArr = new char[]{'h', 'e', 'l', 'l', 'o'};
// 将字符数组中的一部分内容写入进去
fw.write(cArr, 1, 3); // ell
// 将整个字符数组写进去
fw.write(cArr); // hello
// 刷新流
fw.flush();
System.out.println("写入数据成功!");
} catch (IOException e) {
e.printStackTrace();
} finally {
// 3.关闭流对象并释放有关的资源
if (null != fw) {
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
FileReader类
概念
- java.io.FileReader类主要用于从文本文件读取文本数据内容。
常用方法
方法声明 | 方法介绍 |
---|---|
FileReader(String fileName) | 根据参数指定的文件名构造对象 |
int read() | 读取单个字符的数据并返回,返回-1表示读取到末尾 |
int read(char[] cbuf, int offset, int length) | 从输入流中将最多len个字符的数据读入一个字符数组中,返回读取到的字符个数,返回-1表示读取到末尾 |
int read(char[] cbuf) | 从此输入流中将最多 cbuf.length 个字符的数据读入字符数组中,返回读取到的字符个数,返回-1表示读取到末尾 |
void close() | 关闭流对象并释放有关的资源 |
import java.io.FileReader;
import java.io.IOException;
public class FileReaderTest {
public static void main(String[] args) {
FileReader fr = null;
try {
// 1.构造FileReader类型的对象与d:/a.txt文件关联
//fr = new FileReader("d:/a.txt");
fr = new FileReader("d:/b.txt");
// 2.读取数据内容并打印
/*
int res = fr.read();
System.out.println("读取到的单个字符是:" + (char)res); // 'a'
*/
int res = 0;
while ((res = fr.read()) != -1) {
System.out.println("读取到的单个字符是:" + (char)res + ",对应的编号是:" + res);
}
// 准备一个字符数组来保存读取到的数据内容
// char[] cArr = new char[5];
// 期望读满字符数组中的一部分空间,也就是读取3个字符放入数组cArr中下标从1开始的位置上
/*int res = fr.read(cArr, 1, 3);
System.out.println("实际读取到的字符个数是:" + res); // 3
for (char cv : cArr) {
System.out.println("读取到的单个字符是:" + (char)cv); // 啥也没有 a e l 啥也没有
}*/
// 期望读满整个字符数组
/*int res = fr.read(cArr);
System.out.println("实际读取到的字符个数是:" + res); // 5
for (char cv : cArr) {
System.out.println("读取到的单个字符是:" + (char)cv); // a e l l h
}*/
} catch (IOException e) {
e.printStackTrace();
} finally {
// 3.关闭流对象并释放有关的资源
if (null != fr) {
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
字符流拷贝(FileReader,FileWriter)
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class FileCharCopyTest {
public static void main(String[] args) {
FileReader fr = null;
FileWriter fw = null;
try {
// 1.创建FileReader类型的对象与d:/a.txt文件关联
fr = new FileReader("d:/a.txt");
//fr = new FileReader("d:/03 IO流的框架图.png");
// 2.创建FileWriter类型的对象与d:/b.txt文件关联
fw = new FileWriter("d:/b.txt");
//fw = new FileWriter("d:/IO流的框架图.png"); 拷贝图片文件失败!!!
// 3.不断地从输入流中读取数据内容并写入到输出流中
System.out.println("正在玩命地拷贝...");
int res = 0;
while ((res = fr.read()) != -1) {
fw.write(res);
}
System.out.println("拷贝文件成功!");
} catch (IOException e) {
e.printStackTrace();
} finally {
// 4.关闭流对象并释放有关的资源
if (null != fw) {
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != fr) {
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
字节流
FileOutputStream类
概念
- java.io.FileOutputStream类主要用于将图像数据之类的原始字节流写入到输出流中。
常用方法
方法声明 | 方法介绍 |
---|---|
FileOutputStream(String name) | 根据参数指定的文件名来构造对象 |
FileOutputStream(String name, boolean append) | 以追加的方式根据参数指定的文件名来构造对象 |
void write(int b) | 将指定字节写入此文件输出流 |
oid write(byte[] b, int off, int len) | 将指定字节数组中从偏移量off开始的len个字节写入 此文件输出流 |
void write(byte[] b) | 将 b.length 个字节从指定字节数组写入此文件输出 流中 |
void flush() | 刷新此输出流并强制写出任何缓冲的输出字节 |
void close() | 关闭流对象并释放有关的资源 |
FileInputStream类
概念
- java.io.FileInputStream类主要用于从输入流中以字节流的方式读取图像数据等。
常用方法
方法声明 | 方法介绍 |
---|---|
FileInputStream(String name) | 根据参数指定的文件路径名来构造对象 |
int read() | 从输入流中读取单个字节的数据并返回,返回-1表示读取到末尾 |
int read(byte[] b, int off, int len) | 从此输入流中将最多len个字节的数据读入字节数组中,返回读取到的 字节个数,返回-1表示读取到末尾 |
int read(byte[] b) | 从此输入流中将最多 b.length 个字节的数据读入字节数组中,返回读 取到的字节个数,返回-1表示读取到末尾 |
void close() | 关闭流对象并释放有关的资源 |
int available() | 获取输入流所关联文件的大小 |
字节流拷贝(FileInputStream,FileOutputStream)
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileByteCopyTest {
public static void main(String[] args) {
// 获取当前系统时间距离1970年1月1日0时0分0秒的毫秒数
long g1 = System.currentTimeMillis();
FileInputStream fis = null;
FileOutputStream fos = null;
try {
// 1.创建FileInputStream类型的对象与d:/03 IO流的框架图.png文件关联
//fis = new FileInputStream("d:/03 IO流的框架图.png");
fis = new FileInputStream("d:/02_IO流的框架结构.mp4");
// 2.创建FileOutputStream类型的对象与d:/IO流的框架图.png文件关联
//fos = new FileOutputStream("d:/IO流的框架图.png");
fos = new FileOutputStream("d:/IO流的框架结构.mp4");
// 3.不断地从输入流中读取数据内容并写入到输出流中
System.out.println("正在玩命地拷贝...");
// 方式一:以单个字节为单位进行拷贝,也就是每次读取一个字节后再写入一个字节
// 缺点:文件稍大时,拷贝的效率很低
/*int res = 0;
while ((res = fis.read()) != -1) {
fos.write(res);
}*/
// 方式二:准备一个和文件大小一样的缓冲区,一次性将文件中的所有内容取出到缓冲区然后一次性写入进去
// 缺点:若文件过大时,无法申请和文件大小一样的缓冲区,真实物理内存不足
/*int len = fis.available();
System.out.println("获取到的文件大小是:" + len);
byte[] bArr = new byte[len];
int res = fis.read(bArr);
System.out.println("实际读取到的文件大小是:" + res);
fos.write(bArr);*/
// 方式三:准备一个相对适当的缓冲区,分多次将文件拷贝完成
byte[] bArr = new byte[1024];
int res = 0;
while ((res = fis.read(bArr)) != -1) {
fos.write(bArr, 0, res);
}
System.out.println("拷贝文件成功!");
} catch (IOException e) {
e.printStackTrace();
} finally {
// 4.关闭流对象并释放有关的资源
if (null != fos) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != fis) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
long g2 = System.currentTimeMillis();
System.out.println("使用文件流拷贝视频文件消耗的时间为:" + (g2-g1)); // 165
}
}
缓冲流
BufferedOutputStream类
概念
- java.io.BufferedOutputStream类主要用于描述缓冲输出流,此时不用为写入的每个字节调用底层 系统。
常用方法
方法声明 | 方法介绍 |
---|---|
BufferedOutputStream(OutputStream out) | 根据参数指定的引用来构造对象 |
BufferedOutputStream(OutputStream out, int size) | 根据参数指定的引用和缓冲区大小来构造 对象 |
void write(int b) | 写入单个字节 |
void write(byte[] b, int off, int len) | 写入字节数组中的一部分数据 |
void write(byte[] b) | 写入参数指定的整个字节数组 |
void flush() | 刷新流 |
void close() | 关闭流对象并释放有关的资源 |
BufferedInputStream类
概念
- java.io.BufferedInputStream类主要用于描述缓冲输入流。
常用方法
方法声明 | 方法介绍 |
---|---|
BufferedInputStream(InputStream in) | 根据参数指定的引用构造对象 |
BufferedInputStream(InputStream in, int size) | 根据参数指定的引用和缓冲区大小构造对象 |
int read() | 读取单个字节 |
int read(byte[] b, int off, int len) | 读取len个字节 |
int read(byte[] b) | 读取b.length个字节 |
void close() | 关闭流对象并释放有关的资源 |
缓冲字节流拷贝(BufferedInputStream,BufferedOutputStream)
import java.io.*;
public class BufferedByteCopyTest {
public static void main(String[] args) {
// 获取当前系统时间距离1970年1月1日0时0分0秒的毫秒数
long g1 = System.currentTimeMillis();
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
// 1.创建BufferedInputStream类型的对象与d:/02_IO流的框架结构.mp4文件关联
bis = new BufferedInputStream(new FileInputStream("d:/02_IO流的框架结构.mp4"));
// 2.创建BufferedOuputStream类型的对象与d:/IO流的框架结构.mp4文件关联
bos = new BufferedOutputStream(new FileOutputStream("d:/IO流的框架结构.mp4"));
// 3.不断地从输入流中读取数据并写入到输出流中
System.out.println("正在玩命地拷贝...");
byte[] bArr = new byte[1024];
int res = 0;
while ((res = bis.read(bArr)) != -1) {
bos.write(bArr, 0, res);
}
System.out.println("拷贝文件成功!");
} catch (IOException e) {
e.printStackTrace();
} finally {
// 4.关闭流对象并释放有关的资源
if (null != bos) {
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != bis) {
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
long g2 = System.currentTimeMillis();
System.out.println("使用缓冲区拷贝视频文件消耗的时间为:" + (g2-g1)); // 44
}
}
BufferedWriter类
概念
- java.io.BufferedWriter类主要用于写入单个字符、字符数组以及字符串到输出流中。
常用方法
方法介绍 | 方法说明 |
---|---|
BufferedWriter(Writer out) | 根据参数指定的引用来构造对象 |
BufferedWriter(Writer out, int sz) | 根据参数指定的引用和缓冲区大小来构造对象 |
void write(int c) | 写入单个字符到输出流中 |
void write(char[] cbuf, int off, int len) | 将字符数组cbuf中从下标off开始的len个字符写入输出流 中 |
void write(char[] cbuf) | 将字符串数组cbuf中所有内容写入输出流中 |
void write(String s, int off, int len) | 将参数s中下标从off开始的len个字符写入输出流中 |
void write(String str) | 将参数指定的字符串内容写入输出流中 |
void newLine() | 用于写入行分隔符到输出流中 |
void flush() | 刷新流 |
void close() | 关闭流对象并释放有关的资源 |
BufferedReader类
概念
- java.io.BufferedReader类用于从输入流中读取单个字符、字符数组以及字符串
常用方法
方法声明 | 方法介绍 |
---|---|
BufferedReader(Reader in) | 根据参数指定的引用来构造对象 |
BufferedReader(Reader in, int sz) | 根据参数指定的引用和缓冲区大小来构造对象 |
int read() | 从输入流读取单个字符,读取到末尾则返回-1,否则返回实际读取到 的字符内容 |
int read(char[] cbuf, int off, int len) | 从输入流中读取len个字符放入数组cbuf中下标从off开始的位置上, 若读取到末尾则返回-1,否则返回实际读取到的字符个数 |
int read(char[] cbuf) | 从输入流中读满整个数组cbuf |
String readLine() | 读取一行字符串并返回,返回null表示读取到末尾 |
void close() | 关闭流对象并释放有关的资源 |
缓冲字符流拷贝(BufferedReader,BufferedWriter)
import java.io.*;
public class BufferedCharCopyTest {
public static void main(String[] args) {
BufferedReader br = null;
BufferedWriter bw = null;
try {
// 1.创建BufferedReader类型的对象与d:/a.txt文件关联
br = new BufferedReader(new FileReader("d:/a.txt"));
// 2.创建BufferedWriter类型的对象与d:/b.txt文件关联
bw = new BufferedWriter(new FileWriter("d:/b.txt"));
// 3.不断地从输入流中读取一行字符串并写入到输出流中
System.out.println("正在玩命地拷贝...");
String str = null;
while ((str = br.readLine()) != null) {
bw.write(str);
bw.newLine(); // 当前系统中的行分隔符是:\r\n
}
System.out.println("拷贝文件成功!");
} catch (IOException e) {
e.printStackTrace();
} finally {
// 4.关闭流对象并释放有关的资源
if (null != bw) {
try {
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != br) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
打印流
PrintStream类
概念
- java.io.PrintStream类主要用于更加方便地打印各种数据内容。
常用方法
方法声明 | 方法介绍 |
---|---|
PrintStream(OutputStream out) | 根据参数指定的引用来构造对象 |
void print(String s) | 用于将参数指定的字符串内容打印出来 |
void println(String x) | 用于打印字符串后并终止该行 |
void flush() | 刷新流 |
void close() | 用于关闭输出流并释放有关的资源 |
PrintWriter类
概念
- java.io.PrintWriter类主要用于将对象的格式化形式打印到文本输出流
常用方法
方法声明 | 方法介绍 |
---|---|
PrintWriter(Writer out) | 根据参数指定的引用来构造对象 |
void print(String s) | 用于将参数指定的字符串内容打印出来 |
void println(String x) | 用于打印字符串后并终止该行 |
void flush() | 刷新流 |
void close() | 用于关闭输出流并释放有关的资源 |
转化流
OutputStreamWriter类
概念
- java.io.OutputStreamWriter类主要用于实现从字符流到字节流的转换。
常用方法
方法声明 | 方法介绍 |
---|---|
OutputStreamWriter(OutputStream out) | 根据参数指定的引用来构造对象 |
OutputStreamWriter(OutputStream out, String charsetName) | 根据参数指定的引用和编码构造 对象 |
void write(String str) | 将参数指定的字符串写入 |
void flush() | 刷新流 |
void close() | 用于关闭输出流并释放有关的资 源 |
InputStreamReader类
概念
- java.io.InputStreamReader类主要用于实现从字节流到字符流的转换。
常用方法
方法声明 | 方法介绍 |
---|---|
InputStreamReader(InputStream in) | 根据参数指定的引用来构造对象 |
InputStreamReader(InputStream in, String charsetName) | 根据参数指定的引用和编码来构造对 象 |
int read(char[] cbuf) | 读取字符数据到参数指定的数组 |
void close() | 用于关闭输出流并释放有关的资源 |
打印流(PrintStream)转换流(InputStreamReader)
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Date;
public class PrintStreamChatTest {
public static void main(String[] args) {
// 由手册可知:构造方法需要的是Reader类型的引用,但Reader类是个抽象类,实参只能传递子类的对象 字符流
// 由手册可知: System.in代表键盘输入, 而且是InputStream类型的 字节流
BufferedReader br = null;
PrintStream ps = null;
try {
br = new BufferedReader(new InputStreamReader(System.in));
ps = new PrintStream(new FileOutputStream("d:/a.txt", true));
// 声明一个boolean类型的变量作为发送方的代表
boolean flag = true;
while(true) {
// 1.提示用户输入要发送的聊天内容并使用变量记录
System.out.println("请" + (flag? "张三": "李四") + "输入要发送的聊天内容:");
String str = br.readLine();
// 2.判断用户输入的内容是否为"bye",若是则聊天结束
if ("bye".equals(str)) {
System.out.println("聊天结束!");
break;
}
// 3.若不是则将用户输入的内容写入到文件d:/a.txt中
//else {
// 获取当前系统时间并调整格式
Date d1 = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
ps.println(sdf.format(d1) + (flag?" 张三说:":" 李四说:") + str);
//}
flag = !flag;
}
ps.println(); // 写入空行 与之前的聊天记录隔开
ps.println();
ps.println();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 4.关闭流对象并释放有关的资源
if (null != ps) {
ps.close();
}
if (null != br) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
字符编码
编码表由来
- 计算机只能识别二进制数据,早期就是电信号。为了方便计算机可以识别各个国家的文字,就需要 将各个国家的文字采用数字编号的方式进行描述并建立对应的关系表,该表就叫做编码表。
常见的编码表
- ASCII:美国标准信息交换码, 使用一个字节的低7位二位进制进行表示。
- ISO8859-1:拉丁码表,欧洲码表,使用一个字节的8位二进制进行表示。
- GB2312:中国的中文编码表,最多使用两个字节16位二进制为进行表示。
- GBK:中国的中文编码表升级,融合了更多的中文文字符号,最多使用两个字节16位二进制位表 示。
- Unicode:国际标准码,融合了目前人类使用的所有字符,为每个字符分配唯一的字符码。所有的 文字都用两个字节16位二进制位来表示。
编码的发展
- 面向传输的众多 UTF(UCS Transfer Format)标准出现了,UTF-8就是每次8个位传输数据,而 UTF-16就是每次16个位。这是为传输而设计的编码并使编码无国界,这样就可以显示全世界上所 有文化的字符了。
- Unicode只是定义了一个庞大的、全球通用的字符集,并为每个字符规定了唯一确定的编号,具体 存储成什么样的字节流,取决于字符编码方案。推荐的Unicode编码是UTF-8和UTF-16。
- UTF-8:变长的编码方式,可用1-4个字节来表示一个字符
数据流
DataOutputStream类
概念
- java.io.DataOutputStream类主要用于以适当的方式将基本数据类型写入输出流中。
常用方法
方法声明 | 方法介绍 |
---|---|
DataOutputStream(OutputStream out) | 根据参数指定的引用构造对象 OutputStream类是个抽象 类,实参需要传递子类对象 |
void writeInt(int v) | 用于将参数指定的整数一次性写入输出流,优先写入高字 节 |
void close() | 用于关闭文件输出流并释放有关的资源 |
import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class DataOutputStreamTest {
public static void main(String[] args) {
DataOutputStream dos = null;
try {
// 1.创建DataOutputStream类型的对象与d:/a.txt文件关联
dos = new DataOutputStream(new FileOutputStream("d:/a.txt"));
// 2.准备一个整数数据66并写入输出流
// 66: 0000 0000 ... 0100 0010 => B
int num = 66;
//dos.writeInt(num); // 写入4个字节
dos.write(num); // 写入1个字节
System.out.println("写入数据成功!");
} catch (IOException e) {
e.printStackTrace();
} finally {
// 3.关闭流对象并释放有关的资源
if (null != dos) {
try {
dos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
DataInputStream类
概念
- java.io.DataInputStream类主要用于从输入流中读取基本数据类型的数据。
常用方法
方法声明 | 方法介绍 |
---|---|
DataInputStream(InputStream in) | 根据参数指定的引用来构造对象 InputStream类是抽象类, 实参需要传递子类对象 |
int readInt() | 用于从输入流中一次性读取一个整数数据并返回 |
void close() | 用于关闭文件输出流并释放有关的资源 |
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;
public class DataInputStreamTest {
public static void main(String[] args) {
DataInputStream dis = null;
try {
// 1.创建DataInputStream类型的对象与d:/a.txt文件关联
dis = new DataInputStream(new FileInputStream("d:/a.txt"));
// 2.从输入流中读取一个整数并打印
//int res = dis.readInt(); // 读取4个字节
int res = dis.read(); // 读取1个字节
System.out.println("读取到的整数数据是:" + res); // 66
} catch (IOException e) {
e.printStackTrace();
} finally {
// 3.关闭流对象并释放有关的资源
if (null != dis) {
try {
dis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
对象流
ObjectOutputStream类
概念
- java.io.ObjectOutputStream类主要用于将一个对象的所有内容整体写入到输出流中。
- 只能将支持 java.io.Serializable 接口的对象写入流中。
- 类通过实现 java.io.Serializable 接口以启用其序列化功能。
- 所谓序列化主要指将一个对象需要存储的相关信息有效组织成字节序列的转化过程。
常用方法
方法声明 | 方法介绍 |
---|---|
ObjectOutputStream(OutputStream out) | 根据参数指定的引用来构造对象 |
void writeObject(Object obj) | 用于将参数指定的对象整体写入到输出流中 |
void close() | 用于关闭输出流并释放有关的资源 |
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class ObjectOutputStreamTest {
public static void main(String[] args) {
ObjectOutputStream oos = null;
try {
// 1.创建ObjectOutputStream类型的对象与d:/a.txt文件关联
oos = new ObjectOutputStream(new FileOutputStream("d:/a.txt"));
// 2.准备一个User类型的对象并初始化
User user = new User("xiaoming", "123456", "13511258688");
// 3.将整个User类型的对象写入输出流
oos.writeObject(user);
System.out.println("写入对象成功!");
} catch (IOException e) {
e.printStackTrace();
} finally {
// 4.关闭流对象并释放有关的资源
if (null != oos) {
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
ObjectInputStream类
概念
- java.io.ObjectInputStream类主要用于从输入流中一次性将对象整体读取出来。
- 所谓反序列化主要指将有效组织的字节序列恢复为一个对象及相关信息的转化过程。
常用方法
方法声明 | 方法介绍 |
---|---|
ObjectInputStream(InputStream in) | 根据参数指定的引用来构造对象 |
Object readObject() | 主要用于从输入流中读取一个对象并返回 无法通过返回值 来判断是否读取到文件的末尾 |
void close() | 用于关闭输入流并释放有关的资源 |
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class ObjectOutputStreamTest {
public static void main(String[] args) {
ObjectOutputStream oos = null;
try {
// 1.创建ObjectOutputStream类型的对象与d:/a.txt文件关联
oos = new ObjectOutputStream(new FileOutputStream("d:/a.txt"));
// 2.准备一个User类型的对象并初始化
User user = new User("xiaoming", "123456", "13511258688");
// 3.将整个User类型的对象写入输出流
oos.writeObject(user);
System.out.println("写入对象成功!");
} catch (IOException e) {
e.printStackTrace();
} finally {
// 4.关闭流对象并释放有关的资源
if (null != oos) {
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
public class User implements java.io.Serializable {
//idea关于serialUID的提示要在setting->inspections->java->serialization issues->serializable class without 'serialVerison UID' 选上勾
private static final long serialVersionUID = -5814716593800822421L;
private String userName; // 用户名
private String password; // 密码
private transient String phoneNum; // 手机号 表示该成员变量不参与序列化操作
public User() {
}
public User(String userName, String password, String phoneNum) {
this.userName = userName;
this.password = password;
this.phoneNum = phoneNum;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getPhoneNum() {
return phoneNum;
}
public void setPhoneNum(String phoneNum) {
this.phoneNum = phoneNum;
}
@Override
public String toString() {
return "User{" +
"userName='" + userName + '\'' +
", password='" + password + '\'' +
", phoneNum='" + phoneNum + '\'' +
'}';
}
}
序列化版本号
- 序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时, JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较,如 果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常 (InvalidCastException)。
transient关键字
- transient是Java语言的关键字,用来表示一个域不是该对象串行化的一部分。当一个对象被串行 化的时候,transient型变量的值不包括在串行化的表示中,然而非transient型的变量是被包括进 去的。
经验的分享
- 当希望将多个对象写入文件时,通常建议将多个对象放入一个集合中,然后将集合这个整体看做一 个对象写入输出流中,此时只需要调用一次readObject方法就可以将整个集合的数据读取出来, 从而避免了通过返回值进行是否达到文件末尾的判断。
RandomAccessFile类
概念
- java.io.RandomAccessFile类主要支持对随机访问文件的读写操作,可从文件任意位置开始读
常用方法
方法声明 | 方法介绍 |
---|---|
RandomAccessFile(String name, String mode) | 根据参数指定的名称和模式构造对象 r: 以只读方式打开 rw:打开以便读取和写入 rwd:打开以便读取和写入,同步文件内容的更新 rws:打开以便读取和写入,同步文件内容和元数据 的更新 |
int read() | 读取单个字节的数据 |
void seek(long pos) | 用于设置从此文件的开头开始测量的文件指针偏移 量 |
void write(int b) | 将参数指定的单个字节写入 |
void close() | 用于关闭流并释放有关的资源 |
import java.io.IOException;
import java.io.RandomAccessFile;
public class RandomAccessFileTest {
public static void main(String[] args) {
RandomAccessFile raf = null;
try {
// 1.创建RandomAccessFile类型的对象与d:/a.txt文件关联
raf = new RandomAccessFile("d:/a.txt", "rw");
// 2.对文件内容进行随机读写操作
// 设置距离文件开头位置的偏移量,从文件开头位置向后偏移3个字节 aellhello
raf.seek(3);
int res = raf.read();
System.out.println("读取到的单个字符是:" + (char)res); // a l
res = raf.read();
System.out.println("读取到的单个字符是:" + (char)res); // h 指向了e
raf.write('2'); // 执行该行代码后覆盖了字符'e'
System.out.println("写入数据成功!");
} catch (IOException e) {
e.printStackTrace();
} finally {
// 3.关闭流对象并释放有关的资源
if (null != raf) {
try {
raf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
|
| void close() | 用于关闭流并释放有关的资源 |
```java
import java.io.IOException;
import java.io.RandomAccessFile;
public class RandomAccessFileTest {
public static void main(String[] args) {
RandomAccessFile raf = null;
try {
// 1.创建RandomAccessFile类型的对象与d:/a.txt文件关联
raf = new RandomAccessFile("d:/a.txt", "rw");
// 2.对文件内容进行随机读写操作
// 设置距离文件开头位置的偏移量,从文件开头位置向后偏移3个字节 aellhello
raf.seek(3);
int res = raf.read();
System.out.println("读取到的单个字符是:" + (char)res); // a l
res = raf.read();
System.out.println("读取到的单个字符是:" + (char)res); // h 指向了e
raf.write('2'); // 执行该行代码后覆盖了字符'e'
System.out.println("写入数据成功!");
} catch (IOException e) {
e.printStackTrace();
} finally {
// 3.关闭流对象并释放有关的资源
if (null != raf) {
try {
raf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}