一、I/O原理
- 文件是数据源,在程序中以流(Stream)的形式存在。
- I/O是Input和Output的缩写,I/O技术是非常实用的技术,用于处理数据传输(如:读/写文件,网络通信)。
- Java程序中,对于数据的输入/输出操作是以流(stream)的方式进行的。
- java.io 包是 Java 标准库中的一个核心包,提供了用于系统输入和输出的类,它包含了处理数据流(字节流和字符流)、文件读写、序列化以及数据格式化的工具。

一个流可以理解为一个数据的序列。输入流表示从一个源读取数据,输出流表示向一个目标写数据。
二、I/O流的分类
- 按操作数据单位分为:字节流(二进制文件)、字符流(文本文件)
- 按数据的流向分为:输入流、输出流
- 按流的角色分为:节点流、处理流
三、流的分类
下图是一个描述输入流和输出流的类层次图

| 分类 | 字节输入流 | 字节输出流 | 字符输入流 | 字符输出流 |
|---|---|---|---|---|
| 抽象基类 | InputStream | OutputStream | Reader | Writer |
| 访问文件 | FileInputStream | FileOutputStream | FileReader | FileWriter |
| 访问数组 | ByteArrayInputStream | ByteArrayOutputStream | CharArrayReader | CharArrayWriter |
| 访问管道 | PipedInputstream | PipedOutputStream | PipedReader | PipedWriter |
| 访问字符串 | StringReader | StringWriter | ||
| 缓冲流 | BufferdInputStream | BufferedOutputStream | BufferedReader | BufferedWriter |
| 转换流 | InputStreamReader | OutputStreamWriter | ||
| 对象流 | ObjectInputStream | ObjectOutputStream | ||
| 过滤流 | FilterInputStream | FilterOutputStream | FilterReader | FilterWriter |
| 打印流 | PrintStraeam | PrintWriter | ||
| 推回输入流 | PushbackInputStream | PushbackReader | ||
| 数据流 | DateInputStream | DataOutputStream |
四、字节流
1. 字节流写数据
| 方法名 | 描述 |
|---|---|
| void write(int b) | 将指定的字节写入输出流,b 的低 8 位将被写入流中 |
| void write(byte[] b) | 将字节数组 b 中的所有字节写入输出流 一次写一个字节数组数据 |
| void write(byte[] b,int off,int len) | 将字节数组 b 中的所有字节写入输出流 一次写一个字节数组的部分数据 |
| void flush() | 刷新输出流并强制写出所有缓冲的数据,确保数据被立即写入目标输出 |
| void close() | 关闭输出流并释放与该流相关的所有资源。关闭后不能再写入 |
使用字节输出流写数据的示例:
public class FileOutputStreamTest1 {
public static void main(String[] args) throws IOException {
// 步骤一:创建字节输出流对象(调用系统功能创建了文件,创建字节输出流对象,让字节输出流对象指向文件)
File file = new File("file.txt");
FileOutputStream fos = new FileOutputStream(file);
// 步骤二:调用字节输出流对象的写数据方法
fos.write(97);
// 步骤三:释放资源(关闭此文件输出流并释放与此流相关联的任何系统资源)
fos.close();
}
}
2. 字节流读数据
| 方法 | 描述 |
|---|---|
| int read() | 读取一个字节的数据,返回值为 0 到 255 之间的整数。如果到达流的末尾,返回 -1 |
| int read(byte[] b) | 从输入流中读取字节,并将其存储在字节数组 b 中,返回实际读取的字节数。如果到达流的末尾,返回 -1 |
| int read(byte[] b, int off, int len) | 从输入流中读取最多 len 个字节,并将它们存储在字节数组 b 的 off 偏移位置,返回实际读取的字节数。如果到达流的末尾,返回 -1 |
| long skip(long n) | 跳过并丢弃输入流中的 n 个字节,返回实际跳过的字节数 |
| int available() | 返回可以读取的字节数(不阻塞) |
| void close() | 关闭输入流并释放与该流相关的所有资源 |
| void mark(int readlimit) | 在流中的当前位置设置标记,readlimit 是可以读取的字节数上限 |
| void reset() | 将流重新定位到上次标记的位置,如果没有标记或标记失效,抛出 IOException |
| boolean markSupported() | 检查当前输入流是否支持 mark() 和 reset() 操作 |
使用字节输入流读取数据的示例:
一次读一个字节字符数据
public class FileInputStreamTest1 {
public static void main(String[] args) throws IOException {
// 步骤一:创建字节输入流对象
FileInputStream fis = new FileInputStream("file.txt");
int file = 0;
// 步骤二、调用字节输入流对象的读数据方法
while((file=fis.read())!=-1){
System.out.print((char)file);
}
// 步骤三、释放资源
fis.close();
}
}
一次读一个字节数组数据
public class FileInputStreamTest2 {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("file.txt");
byte[]bytes = new byte[1000];
int length = 0;
while((length=fis.read(bytes))!=-1){
System.out.print(new String(bytes,0,length));
}
fis.close();
}
}
五、字符流
1. 字符流写数据
字符流写数据的5种方式
| 方法 | 描述 |
|---|---|
| void write(int c) | 写入一个字符c |
| void write(String str) | 写入一个字符串 |
| void write(String str,int off,int len) | 写入字符串的一部分,off偏移量,len长度 |
| void write(char[] cbuf) | 写入一个字符数组 |
| void write(char[] cbuf,int off,int len) | 写入字符数组的一部分,off偏移量,len长度 |
刷新和关闭的方法
| 方法 | 说明 |
|---|---|
| flush() | 刷新流,之后还可以继续写数据 |
| close() | 关闭流,释放资源,但是在关闭之前会先刷新流。一旦关闭,就不能再写数据 |
2. 字符流读数据
字符流读数据的两种方式
| 方法名 | 描述 |
|---|---|
| int read() | 从输入流中读取字符,一次读取一个字符数据 |
| int read(byte[] b) | 一次读取一个字符数组数据 |
六、解决乱码问题——字节与字符的转化
数据持久化或网络传输都是以字节进行的,所以必须要有字符到字节或字节到字符的转化。
1. 字符流中的编码解码问题
- InputStreamReader 类是字节到字符的转化桥梁,InputStream 到 Reader 的过程要指定编码字符集,否则将采用操作系统默认字符集,很可能会出现乱码问题。StreamDecoder 正是完成字节到字符的解码的实现类。
- OutputStreamWriter 是从字符流到字节流的桥梁,使用指定的编码将写入的字符编码为字节,由StreamEncoder完成编码过程。
//文件名 :fileStreamTest2.java
import java.io.*;
public class fileStreamTest {
public static void main(String[] args) throws IOException {
File f = new File("a.txt");
FileOutputStream fop = new FileOutputStream(f);
// 构建FileOutputStream对象,文件不存在会自动新建
OutputStreamWriter writer = new OutputStreamWriter(fop, "UTF-8");
// 构建OutputStreamWriter对象,参数可以指定编码,默认为操作系统默认编码,windows上是gbk
writer.append("中文输入");
// 写入到缓冲区
writer.append("\r\n");
// 换行
writer.append("English");
// 刷新缓存冲,写入到文件,如果下面已经没有写入的内容了,直接close也会写入
writer.close();
// 关闭写入流,同时会把缓冲区内容写入文件,所以上面的注释掉
fop.close();
// 关闭输出流,释放系统资源
FileInputStream fip = new FileInputStream(f);
// 构建FileInputStream对象
InputStreamReader reader = new InputStreamReader(fip, "UTF-8");
// 构建InputStreamReader对象,编码与写入相同
StringBuffer sb = new StringBuffer();
while (reader.ready()) {
sb.append((char) reader.read());
// 转成char加到StringBuffer对象中
}
System.out.println(sb.toString());
reader.close();
// 关闭读取流
fip.close();
// 关闭输入流,释放系统资源
}
}
2. 字符串中的编码解码问题
- 编码:byte[] getBytes(String charsetName)使用指定的字符集将该 String编码为一系列字节,无指定则使用平台的默认字符集。\
- 解码:String(byte[] bytes, String charsetName)通过指定的字符集解码指定的字节数组来创建字符串,无指定则使用平台的默认字符集。
七、字符缓冲流
1. BufferedWriter
将文本写入字符输出流,缓冲字符,以提供单个字符,数组和字符串的高效写入,可以指定缓冲区大小,或者可以接受默认大小。默认值足够大,可用于大多数用途。
方法void newLine() 写一行行分隔符。 行分隔符字符串由系统属性line.separator定义,并不一定是单个换行符(‘\ n’)字符。
2. BufferedReader
从字符输入流读取文本,缓冲字符,以提供字符,数组和行的高效读取,可以指定缓冲区大小,或者可以使用默认大小。 默认值足够大,可用于大多数用途。
方法String readLine() 读一行文字。 结果包含行的内容的字符串,不包括任何行终止字符如果流的结尾。
八、文件目录
1.创建目录
- mkdir( )方法创建一个文件夹,成功则返回true,失败则返回false。失败表明File对象指定的路径已经存在,或者由于整个路径还不存在,该文件夹不能被创建。
- mkdirs()方法创建一个文件夹和它的所有父文件夹。
import java.io.File;
public class CreateDir {
public static void main(String[] args) {
String dirname = "/tmp/user/java/bin";
File d = new File(dirname);
// 现在创建目录
d.mkdirs();
}
}
2.读取目录
一个目录其实就是一个 File 对象,它包含其他文件和文件夹。
如果创建一个 File 对象并且它是一个目录,那么调用 isDirectory() 方法会返回 true。
可以通过调用该对象上的 list() 方法,来提取它包含的文件和文件夹的列表。
3.删除目录或文件
删除文件可以使用 java.io.File.delete() 方法。
需要注意的是当删除某一目录时,必须保证该目录下没有其他文件才能正确删除,否则将删除失败。
310

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



