IO流的分类
-
根据处理数据类型的不同分为:字符流和字节流
-
根据数据流向不同分为:输入流和输出流
进行输入、输出操作一般都会按照如下步骤进行:
- 通过File类定义一个要操作文件的路径
- 通过字节流或字符流的子类对象为父类对象实例化
- 进行数据的读(输入)、写(输出)操作
- 数据流属于资源操作,资源操作必须关闭
java.io包定义了两类流:
- 字节流(JDK 1.0):InputStream、OutputStream
- 字符流(JDK 1.1):Writer、Reader
1. 字节流
1.1 字节输出流(OutputStream)
OutputStream这个抽象类是表示字节输出流的所有类的超类。
输出流接收输出字节并将其发送到某个接收器。
需要定义OutputStream子类的应用OutputStream必须至少提供一个写入一个字节输出的方法。
OutputStream类提供了三个输出的方法:
- 输出单个字节:public abstract void write(int b)
- 输出全部字节数组:public void write(byte[] b)
- 输出部分字节数组:public void write(byte[] b,int off,int len)
OutputStream本身属于抽象类,如果想为抽象类进行对象的实例化操作,需要使用抽象类的子类,进行文件操作可以使用FileOutputStream子类。在这个子类中定义了如下构造方法:
- FileOutputStream(File file) 创建文件输出流以写入由指定的File对象表示的文件
- FileOutputStream(File file, boolean append) 文件内容追加
使用全部字节数组进行输出示例:
//1. 定义要输出的文件路径
File file = new File("E:"+File.separator+"demo"+File.separator+"test.txt");
//如果目录不存在则先创建目录
if(file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
//2. 应该使用OutputStream和其子类进行对象的实例化,此时目录存在,文件还不存在
OutputStream outputStream = new FileOutputStream(file);
//3. 进行文件内容的输出
String str = "好好学习,天天向上";
//将字符串转为byte数组
byte[] data = str.getBytes();
outputStream.write(data);
//4. 关闭资源
outputStream.close();
使用部分字节数组输出示例
//1. 定义要输出的文件路径
File file = new File("E:"+File.separator+"demo"+File.separator+"study.txt");
//如果目录不存在则先创建目录
if(file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
//2. 应该使用OutputStream和其子类进行对象的实例化,此时目录存在,文件还不存在
OutputStream outputStream = new FileOutputStream(file);
//3. 进行文件内容的输出
String str = "我们要好好学习技术,然后找个好工作,多赚点钱,补贴家用,实现自我价值,成为一个对社会有用的人";
//将字符串转为byte数组
byte[] data = str.getBytes();
outputStream.write(data,0,6);
//4. 关闭资源
outputStream.close();
1.2 字节输入流:InputStream
InputStream抽象类是表示输入字节流的所有类的超类。
需要定义InputStream子类的应用InputStream必须始终提供一种返回输入的下一个字节的方法。
InputSream提供了三个输入的方法:
- public abstract int read() 从输入流读取数据的下一个字节
- public int read(byte[] b) 从输入流读取一些字节数,并将它们存储到缓冲区b 。 实际读取的字节数作为整数返回。 该方法阻塞直到输入数据可用,检测到文件结束或抛出异常。
- public int read(byte[] b,int off,int len) 从输入流读取len字节的数据到一个字节数组。 尝试读取多达len个字节,但可以读取较小的数字。 实际读取的字节数作为整数返回。该方法阻塞直到输入数据可用,检测到文件结束或抛出异常。
使用FileInputStream读入文件示例
//1. 定义要输入的文件路径
File file = new File("E:"+File.separator+"demo"+File.separator+"study.txt");
//判断文件是否存在后才可以进行读取
if(file.exists()){
// 2. 使用FileInputStream进行读取
InputStream inputStream = new FileInputStream(file);
//准备处理一个1024的数组
byte[] data = new byte[1024];
//字节数组的操作脚标
int foot = 0;
//表示每次读取的字节数据
int temp = 0;
//读取一个字节
while((temp = inputStream.read()) != -1){
if(temp != -1){
data[foot++] = (byte)temp;
}
}
//4. 关闭流
inputStream.close();
System.out.println("["+new String(data,0,foot)+"]");
}
}
2. 字符流
2.1 字符输出流:Writer
Writer是用于写入字符流的抽象类。子类必须实现的唯一方法是write(char [],int,int),flush()和close()。 然而,大多数子类将覆盖这里定义的一些方法,以便提供更高的效率,或者附加功能。
Writer提供的常用方法
- write(char[] cbuf) 写入一个字符数组。
- write(char[] cbuf, int off, int len) 写入字符数组的一部分。
- write(int c) 写一个字符
- write(String str) 写一个字符串
- write(String str, int off, int len) 写一个字符串的一部分。
- append(char c) 附加指定的字符
- close() 关闭流,先刷新。
- flush() 刷新流。
使用字符输出流输出字符串示例
//1. 定义要输出的文件路径
File file = new File("E:"+File.separator+"demo"+File.separator+"writer.txt");
//如果目录不存在则创建
if(!file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
//2. 实例化Writer类对象
Writer out = new FileWriter(file);
//3. 进行内容输出
String str = "好好学习,天天向上!!!";
//输出字符串数据
out.write(str);
//4. 关闭流
out.close();
2.2 字符输入流:Reader
用于读取字符流的抽象类。 子类必须实现的唯一方法是read(char [],int,int)和close()。 然而,大多数子类将覆盖这里定义的一些方法,以便提供更高的效率以及附加的功能。
Reader提供的常用方法
- read() 读一个字符
- read(char[] cbuf) 将字符读入数组。
- read(char[] cbuf, int off, int len) 将字符读入数组的一部分。
- read(CharBuffer target) 尝试将字符读入指定的字符缓冲区。
- ready() 告诉这个流是否准备好被读取。
- close() 关闭流并释放与之相关联的任何系统资源。
- mark(int readAheadLimit) 标记流中的当前位置。
- reset() 重置流。
读入文件可以使用子类FileReader,示例代码如下:
//1. 定义要输入的文件路径
File file = new File("E:"+File.separator+"demo"+File.separator+"writer.txt");
//判断文件是否存在后才可以进行读取
if(file.exists()){
// 2. 为Reader类对象实例化
Reader input = new FileReader(file);
// 3. 进行数据读取
char[] c = new char[1024];
int len = input.read(c);
//4. 关闭流
input.close();
System.out.println(new String(c,0,len));
}
与字节输入流相比结构几乎一样,只是数据类型由byte变为char
3. 字节流与字符流的区别
- 字节流直接与终端进行数据交互,字符流需要将数据经过缓存区处理后才可以输出
- 读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。
- 字节流处理二进制数据,字符流处理文本文件
- 字节流可以转为字符流,而字符流不能转为字节流
- 进行中文处理时优先考虑字符流
4. 字节流转换为字符流
在java.io包里面提供了两个类:InputStreamReader和OutputStreamWriter用于将字节流转为字符流
名称: | InputStreamReader | OutputStreamWriter |
---|---|---|
定义结构: | public class InputStreamReader extends Reader | InputStreamReader(InputStream in) |
构造方法: | public class OutputStreamWriter extends Writer | OutputStreamWriter(OutputStream out) |
InputStreamReader是将字节输入流转为字符输入流:它读取字节,并使用指定的charset将其解码为字符。 它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集。每个调用InputStreamReader的read()方法会导致从底层字节输入流读取一个或多个字节。 为了使字节有效地转换为字符,可以从底层流读取比满足当前读取操作所需的更多字节。
为了最大的效率,请考虑在BufferedReader中包装一个InputStreamReader。 例如:BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
OutputStreamWriter是将字节输出流转为字符输出流。 它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集。
每次调用write()方法都会使编码转换器在给定字符上被调用。 所得到的字节在写入底层输出流之前累积在缓冲区中。 可以指定此缓冲区的大小。 请注意,传递给write()方法的字符不会缓冲。
为了最大的效率,请考虑在BufferedWriter中包装一个OutputStreamWriter,以避免频繁的转换器调用。 例如:Writer out = new BufferedWriter(new OutputStreamWriter(System.out));
将字节输出流转为字符输出流示例
File file = new File("E:"+ File.separator+"demo"+File.separator+"study.txt");
if(!file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
//字节流
OutputStream output = new FileOutputStream(file);
//将字节流转换为字符流
Writer out = new OutputStreamWriter(output);
String c = "Hello World!";
//进行输出
out.write(c);
out.flush();
out.close();
将字节输入流转为字符输入流示例
File file = new File("E:"+ File.separator+"demo"+File.separator+"study.txt");
if(!file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
//字节输入流
InputStream in = new FileInputStream(file);
//将字节输入流转为字符输入流
Reader input = new InputStreamReader(in);
char[] c = new char[1024];
//读数据
input.read(c);
//关闭流
input.close();
System.out.println(new String(c));
- 两个转换类都是字符流的子类,属于字符流与字节流沟通的桥梁