一. 概述
1. 流(stream)的概念
- 流:流就是有能力产出数据或接收数据的对象,本质是数据传输,作用是在数据源和程序间建立传送通道
2. IO流的分类
按数据流向分为
- 输入流:外部(磁盘)数据读入到程序(内存)中
- 输出流:程序数据输出到磁盘中
按数据单位分为
- 字节流:按字节操作数据,一般处理非文本文件(jpg、mp4、mp3、doc、ppt)
- 字符流:按字符操作数据,一般处理文本文件(txt、java、c、cpp)
按流的功能分为
- 节点流:直接在数据源于程序间进行传输的流
- 处理流:对已存在的流(节点流或处理流)包装(可多次),增强传输功能的流
流的整体分类
基类 | 字节流 | 字符流 |
---|---|---|
输入流 | InputStream | Reader |
输出流 | OutputStream | Writer |
其中,文件、数组、管道、字符串类为节点流,其余为处理流
分类 | InputStream | OutputStream | Reader | Writer |
---|---|---|---|---|
文件 | FileInputStream | FileOutputStream | FileReader | FileWriter |
数组 | ByteArrayInputStream | ByteArrayOutputStream | CharArrayReader | CharArrayWriter |
管道 | PipedInputStream | PipeOutputStream | PipedReader | PipedWriter |
字符串 | StringReader | StringWriter | ||
转换流 | InputStreamReader | OutputStreamWriter | ||
对象流 | ObjectInputStream | ObjectOutputStream | ||
打印流 | PrintStream | PrintWriter | ||
过滤流 | FilterInputStream | FilterOutputStream | FilterReader | FilterWriter |
缓冲流 | BufferedInputStream | BufferedOutputStream | BufferedReader | BufferedWriter |
推回流 | PushbackInputStream | PushbackReader | ||
数据流 | DataInputStream | DataOutputStream |
*表中加粗项为常用流
3. File类(java.io.File)
File类的对象代表文件或目录,用于对文件或目录的创建、查找和删除操作
File类的构造器:
- File(String filePath) 根据给定路径字符串创建新的File实例
- File(String parentPath, String childPath) 根据父路径和子路径创建新的File实例
- File(File parentFile, String childPath)根据父文件对象和子路径创建新的File实例
// 文件路径名
String path = "D:\\123.txt";
File file1 = new File(path);
// 文件路径名
String path2 = "D:\\1\\2.txt";
File file2 = new File(path2); -------------相当于D:\\1\\2.txt
// 通过父路径和子路径字符串
String parent = "F:\\aaa";
String child = "bbb.txt";
File file3 = new File(parent, child); --------相当于F:\\aaa\\bbb.txt
// 通过父File对象和子路径字符串
File parentDir = new File("F:\\aaa");
String child = "bbb.txt";
File file4 = new File(parentDir, child); --------相当于F:\\aaa\\bbb.txt
二. 常用流的使用
使用流的标准化代码操作流程,以读取为例,写入同理
- 创建 File 类对象,指明读取的数据来源,文件必须存在
- 创建相应输入流,将File类对象作为参数传入流的构造器
- 创建相应的字节或字符数组
- .close() 关闭流
- 对异常进行 try-catch-finally 处理
1. 文件流
选择原则:对于处理纯文本数据,就优先考虑字符流,除此之外都使用字节流
假设使用文件流读取一个txt文本文件,代码如下:
@Test
public void testFileReader() throws IOException {
//1.File类的实例化
File file = new File("Hello.txt");
//2.FileReader流实例化
FileReader fr = new FileReader(file);
//3.读取字符 read(char[] c):返回每次读入c数组的字符个数,如果到文件末尾,返回-1
char[] c = new char[5];
int len;
while((len = fr.read(c)) != -1){
String str = new String(c, 0, len);
System.out.print(str);
}
//4.关闭流
fr.close();
}
写入txt文件同理
@Test
public void testFileWriter() throws IOException {
//1.File类的实例化
File file = new File("Hello.txt");
//2.FileWriter流实例化
FileWriter fw = new FileWriter(file);
//3.写入字符
fw.write("Hello, world!\n");
//4.关闭流
fw.close();
}
2. 缓冲流
作用:创建一个内置默认大小(8kb)的缓冲数组,通过缓冲区读写,提高读写效率
读取:一次性从文件中读取8kb,存在缓冲区中直到装满,再读取下一个8kb数组
写入:先写到缓冲区中直到写满,再写入文件,使用flush()可强制缓冲区写入文件
实现图片的复制操作
@Test
public void testBufferedStream(){
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
//1.造文件
File srcFile = new File("图片1.jpg");
File destFile = new File("图片2.jpg");
//2.造流
//2.1造节点流
FileInputStream fis = new FileInputStream(srcFile);
FileOutputStream fos = new FileOutputStream(destFile);
//2.2造缓冲流,可以合并书写
bis = new BufferedInputStream(fis);
bos = new BufferedOutputStream(fos);
//3.文件读取、写出操作
byte[] buffer = new byte[1024];
int len;
while ((len = bis.read(buffer)) != -1){
bos.write(buffer,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.关闭流
if (bos != null){
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bis != null){
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
3. 转换流
- InputStreamReader:字节数组 -> 字符数组(解码)
- OutputStreamWriter:字符数组 -> 字节数组(编码)
实现把文本文件由UTF-8编码转为GBK编码格式
@Test
public void test() {
InputStreamReader isr = null;
OutputStreamWriter osw = null;
try {
//1.造文件、造流
File file1 = new File("dbcp_utf8.txt");
File file2 = new File("dbcp_gbk.txt");
FileInputStream fis = new FileInputStream(file1);
FileOutputStream fos = new FileOutputStream(file2);
isr = new InputStreamReader(fis, "utf-8");
osw = new OutputStreamWriter(fos, "gbk");
//2.读写过程
char[] cbuf = new char[20];
int len;
while ((len = isr.read(cbuf)) != -1){
osw.write(cbuf,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//3.关流
if (isr != null){
try {
isr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (osw != null){
try {
osw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
4. 打印流
print()和println()都来自字节打印流PrintStream
实现复制文本文件
@Test
public printTest(){
BufferedReader br = new BufferedReader(new FileReader("copy.txt"));
PrintStream ps = new PrintStream("printcopy.txt");
String line;
while((line = br.readline()) != null){
ps.println(line);
}
br.close();
ps.close();
}
5. 对象流
序列化机制允许把内存中的Java对象转换成平台无关的二进制流,从而允许把这种二进制流持久地保存在磁盘上,或通过网络将这种二进制流传输到另一个网络节点,当其它程序获取了这种二进制流,就可以恢复成原来的Java对象。
- ObjectOutputStream:内存中的对象 -> 存储文件、网络发送(序列化过程)
- ObjectInputStream:存储文件、网络接收 -> 内存中的对象(反序列化过程)
一个对象想要序列化,必须满足以下条件:
- 实现 java.io.Serializable 接口
- 提供一个全局常量 serialVersionUID(序列版本号,用于反序列化验证)
- 该对象的内部属性必须是可序列化的(static和transient修饰的属性不可序列化)
Person类的对象序列化实现
@Test
public void personSerializeTest(){
Person p = new Person();
p.name = "张三";
p.age = 28;
try{
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("Person.dat"));
oos.writeObject(p);
oos.close();
fileOut.close();
}catch(IOException i){
i.printStackTrace();
}
}