目录如下
本章主要内容
- 流的分类
- 字节流与字符流
- 流的装配与串行化
- 文件操作
第一题:Java中流的分类有哪些?
Java中流的分类有3种,分别可以按照读取类型、流动方向与流的源头来分类。
按读取类型分类,可以分为字节流与字符流
- 字节流:字节流以字节(byte)作为处理单位,一次仅读入或输出一个字节;在Java中,字节流是由
InputStream
与OutputStream
两个抽象类所衍生的一系列子类所组成的; - 字符流:与字节流不同,字符流以字符作为处理单位;在Java中,字符流是由
Reader
与Writer
两个抽象类所衍生的一系列子类所组成的。
注意:字节流与字符流不能混用,即字节流的对象引用不能指向字符流的对象,反正亦然。
按照流动方向分类,可以分为输入流与输出流:
- 输入流:即用来读取数据的流,可以将数据从外部设备读入内存中;
- 输出流:即将数据输出到指定的地方去,可以输出到终端、文件,也可以通过网络通信发送给对方。
按照流的源头分类
- 节点流:即从特定的数据源头读取数据,这些数据源可以是文件、终端、网络设备等;
- 过滤流:过滤流不从特定的数据源读取数据,而是通过连接节点流来对数据进行更加复杂强大的操作,比如
BufferedInputStream
和BufferedOutputStream
两个过滤流就提供了缓存的功能,使得读取更加地高效;
第二题:字节流InputStream和OutputStream的子类分别有哪些?请举例说明其使用场景。与其对应的字符流分别有哪些?
下图是Java中I/O的整体轮廓,对于InputStream
类的子类作了介绍,OutputStream
的子类名称与InputStream
子类名称类似,仅需要将InputStream
改为OutputStream
即可。
常用字节流与字符流与它们的对应关系如下:
第三题:字节流与字符流的转化是怎样的?Java对此提供了哪些支持?
字节流与字符流的转化概括
Java对于两种流的转化提供了两个类来支持,但转化的方向是固定的,仅可以按照以下两种转化方向进行:
- 输入字节流转为字符流:使用
InputStreamReader
类,该类的名字也很好理解,就是将输入流(InputStream
)转为字符流(Reader
);
其构造函数为:InputStreamReader(InputStream in)
,可以理解为从一个InputStream字节流读入后转为字符流。 - 输出字符流转为字节流:一个是
OutputStreamWriter
类,该类的名字倒不太好理解,但记住就行了;另一种方法是使用PrintWriter
类将字符流转为字节流,这个类可以输出不同类型(整型、浮点型、String类等)的数据,而OutputStreamWriter
类仅可以输出字符类型的数据。
两个类的构造函数为:OutputStreamWriter(OutputStream out)
,PrintWriter(OutputStream out)
,可以理解为将字符流通过OutputStreamWriter
或PrintWriter
转为字节流,然后向out
进行输出;
字节流与字符流的转化–代码示例
以下面两题为例,在其中运用字节流与字符流的转化。
loadFile函数:
public static String loadFile(String filename){
StringBuffer contents = new StringBuffer();
String tmp;
try{
BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(filename))); /** 将字节流转成了字符流 */
while((tmp=reader.readLine()) != null){
contents.append(tmp+"\n");
}
reader.close();
} catch (IOException e){
System.out.println("Error!");
e.printStackTrace();
}
return contents.toString();
}
saveFile函数:
public static boolean saveFile(String filename, String contents){
try{
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(filename))); /** 输出字符流转为字节流 */
writer.write(contents, 0, contents.length());
writer.close();
} catch (Exception e){
System.out.println("Error");
e.printStackTrace();
return false;
}
return true;
}
主函数中对这两个函数的调用代码如下:
public static void main(String[] args){
String contents = loadFile("./test.txt");
System.out.print(contents);
saveFile("./test2.txt", contents);
}
第四题:Java中的过滤流(流的装配)有什么作用?请举例说明常用的过滤流。
过滤流的作用:
普通的流读取或写入时没有缓冲功能,只能读取或写入字节或字符,而过滤流的作用就是为普通的流添加一些复杂的功能,如缓冲功能、操作(读取)各种数据类型等功能。
常用的过滤流:
字节流中常用的过滤流:
-
BufferedInputStream
与BufferedOutputStream
:提供缓冲功能,代码示例如下:public static void main(String[] args){ try{ BufferedInputStream reader = new BufferedInputStream(new FileInputStream("./test.txt")); BufferedOutputStream writer = new BufferedOutputStream(new FileOutputStream("./test2.txt")); int n=512, s=0; byte[] buffer = new byte[n]; while((s=reader.read(buffer, 0, n)) != -1){ writer.write(buffer, 0, s); System.out.println("writting contents..."); } reader.close(); writer.close(); } catch (Exception e){ System.out.println("Error"); e.printStackTrace(); } }
-
DataInputStream
与DataOutputStream
:提供对多种数据类型的读写功能,代码示例如下:try{ DataOutputStream writer = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("./test_DataStream.txt"))); writer.writeInt(234); // 写入整型 writer.writeDouble(3.244); // 写入双精度浮点数 writer.writeUTF("hahaha"); // 写入字符串 writer.close(); DataInputStream reader = new DataInputStream(new BufferedInputStream(new FileInputStream("./test_DataStream.txt"))); System.out.println(reader.readInt()); System.out.println(reader.readDouble()); System.out.println(reader.readUTF()); reader.close(); } catch (Exception e){ System.out.println("Error"); e.printStackTrace(); }
字符流中常用的过滤流:
-
BufferedReader
与BufferedWriter
try{ String file = "./test_reader.txt"; BufferedWriter writer = new BufferedWriter(new FileWriter(file)); String contents = "Hello, I like programming."; writer.write(contents, 0, contents.length()); writer.close(); BufferedReader reader = new BufferedReader(new FileReader(file)); System.out.println(reader.readLine()); reader.close(); } catch (Exception e){ System.out.println("Error"); e.printStackTrace(); }
-
PrintWriter
:支持多种数据类型的输出,缺点是没有对应的读取流来读入不同数据类型,代码示例如下:PrintWriter out = new PrintWriter(System.out, true); out.println("Hello"); out.println(4); //输出整型 out.println(3.45); // 输出浮点数
第五题:什么是对象的序列化和反序列化?Java对此提供了哪些支持?
概念
- 对象的序列化:又叫串行化(Serialization),序列化指的是将对象转化为字节序列,当将对象转为字节后便可以将对象存储在文件中或在网络上进行传输;
- 对象的反序列化:将某个对象的字节序列恢复成原来对象的过程称为反序列化;
Java对序列化与反序列化提供的支持
Java的io包中提供了两个类来对对象进行序列化与反序列化,这两个类是ObjectOutputStream
(序列化)与ObjectInputStream
(反序列化)。
注意:只有实现了java.io.Serializable
接口的类才可以被序列化,因此在使用ObjectOutputStream
对对象进行序列化时,要对对象所属的类实现java.io.Serializable
接口。
下面是这两个类的示例代码:
try{
String file = "./object.obj";
/** 序列化 */
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));
oos.writeUTF("This class is a `String`");
String s = "hahahaha";
oos.writeObject(s);
oos.close();
/** 反序列化 */
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
System.out.println(ois.readUTF()); // 读取字符串
s = (String)ois.readObject(); // 读取对象,并将对象转为其所属的类
System.out.println(s);
ois.close();
} catch (Exception e){
System.out.println("Error");
e.printStackTrace();
}
第六题:Java的File类表示什么?有什么作用?
File类介绍与作用:
Java的File类是对文件和路径名的抽象表示,可以通过File类来对文件和路径进行许多操作,这些操作包括删除、创建、重命名文件和目录等,还可以判断文件或目录是否存在,获取文件大小等信息,真的是非常地方便。
File类常用方法
1、构造方法
方法名 | 使用说明 |
---|---|
File(String pathname) | 将指定的路径名字符串转成一个抽象的路径名来创建一个新的File 实例 |
File(String parent, String child) | 通过两个分别表示父路径和子路径的字符串来创建File 实例 |
File(File parent, String child) | 从父目录的抽象路径和子路径名创建File 实例 |
2、常用方法
方法名 | 使用说明 |
---|---|
boolean canRead() | 测试应用程序是否能从指定的文件中进行读取 |
boolean canWrite() | 测试应用程序是否能写当前文件 |
boolean delete() | 删除当前对象指定的文件或目录 |
boolean exists() | 测试当前的File是否存在 |
boolean isAbsolute() | 判断当前路径是否是绝对路径 |
boolean isDirectory() | 判断当前File是否是路径 |
boolean isFile() | 判断当前File是否是普通文件 |
boolean mkdir() | 根据当前File来创建目录 |
boolean mkdirs() | 可以创建多层目录(这些目录不存在) |
boolean renameTo(File dest) | 将当前File改名为指定的File |
long lastModified() | 返回当前 File 对象表示的文件最后修改的时间,返回的是一串数字,表示的是从1970年1月1日以来到现在所经历的毫秒数,可以通过Date类来对这个数字进行包装,获取可读性更强的时间表示 |
long length() | 返回当前 File 对象表示的文件大小,以字节为单位;若File是路径则返回0 |
String getAbsolutePath() | 获取绝对路径 |
String getName() | 获取当前文件名或路径名(最低一级的路径) |
String getParent() | 获取上一层路径 |
String[] list() | 返回当前 File 对象指定的路径文件列表 |
String[] list(FilenameFilter) | 返回当前 File 对象指定的目录中满足指定过滤器的文件列表 |
第七题:Java对文件的读写分别提供了哪些支持?
Java对文件的读操作提供了FileInputStream
与FileReader
两个类进行支持,
对文件的写操作提供了FileOutputStream
与FileWriter
两个类进行支持,下面列举一下这四个类常用的构造函数。
1、字节流 FileInputStream
方法名 | 使用说明 |
---|---|
FileInputStream(File file) | 使用File类的实例来构造输入字节流 |
FileInputStream(String name) | 使用字符串表示的文件名来构造输入字节流 |
2、字节流 FileOutputStream
方法名 | 使用说明 |
---|---|
FileOutputStream(File file) | 使用File类的实例来构造输出字节流 |
FileOutputStream(File file, boolean append) | 使用File类的实例来构造输入出节流,append参数表示是否对文件追加内容 |
FileOutputStream(String name) | 使用字符串表示的文件名来构造输出字节流 |
FileOutputStream(String name, boolean append) | 使用字符串表示的文件名来构造输出字节流,append参数表示是否对文件追加内容 |
3、字符流FileReader
方法名 | 使用说明 |
---|---|
FileReader(File file) | 使用File类的实例来构造输入字符流 |
FileReader(String fileName) | 使用字符串表示的文件名来构造输入字符流 |
4、字符流FileWriter
方法名 | 使用说明 |
---|---|
FileWriter(File file) | 使用File类的实例来构造输出字符流 |
FileWriter(File file, boolean append) | 使用File类的实例来构造输出字符流,append参数表示是否对文件追加内容 |
FileWriter(String fileName) | 使用字符串表示的文件名来构造输出字符流 |
FileWriter(String fileName, boolean append) | 使用字符串表示的文件名来构造输出字符流,append参数表示是否对文件追加内容 |