Java初学者笔记-08、IO流
I:负责把磁盘和网络中的数据读到程序内存中去。
O:负责把程序内存中的数据写到网络或者磁盘中。
按照流的内容,IO流分为字节流和字符流。
字节流:最小单位是字节。适合操作所有类型的文件。比如音频、视频、图片文本等的复制,转移。
字符流:只适合操作纯文本文件。比如读写txt,java文件等。
结合IO和字节流字符流,可分为下面4种。
- 字节输入流 InputStream
- 字节输出流 OutputStream
- 字符输入流 Reader
- 字符输出流 Writer
| 字节输入流 | 字节输出流 | 字符输入流 | 字符输出流 |
|---|---|---|---|
| InputStream | OutputStream | Reader | Writer |
| FileInputStream | FileOutputStream | FileReader | FileWriter |
| BufferedInputStream | BufferedOutputStream | BufferedReader | BufferedWriter |
| InputStreamReader | |||
| PrintStream | PrintWriter | ||
| DataInputStream | DataOutputStream |
字节流
| 抽象类 | 对应的实现类 |
|---|---|
字节输入流 InputStream |
文件字节输入流 FileInputStream |
字节输出流 OutputStream |
文件字节输出流 FileOutputStream |
文件字节输入流 FileInputStream
作用:以内存为基准,可以把磁盘文件中的数据以字节的形式读入到内存中去。
使用构造器创建文件字节输入流
创建字节输入流管道与源文件接通。
public FileInputStream(File file)
public FileInputStream(String pathName) //一般用这个
InputStream is = new FileInputStream("good.txt");
字节输入流管道对象的read()方法
| 方法 | 说明 |
|---|---|
| public int read() | 每次读取一个字节返回,如果发现没有数据可读会返回-1 |
| public int read(byte[] buffer) | 每次用一个字节数组去读取数据,返回字节数组读取了多少个字节,如果发现没有数据可读会返回-1 |
// 1.创建管道与文件连接
InputStream is = new FileInputStream("111.txt");
// 2.定义一个字节数组用于每次读取字节
byte[] buffer = new byte[1024];
// 3.定义一个变量记住每次读多少字节
int len;
// 4.循环读取并转成字符
while( (len = is.read(buffer)) != -1) {
String str = new String(buffer, 0 ,len);
System.out.print(str);
}
is.close();
文件字节输出流 FileOutputStream
作用:以内存为基准,把内存中的数据以字节的形式写出到文件中去。
使用构造器创建文件字节输出流
| 构造器 | 说明 |
|---|---|
| public FileOutputStream(File file) | 创建字节输出流管道与源文件对象接通 |
| public FileOutputStream(String filepath) | 创建字节输出流管道与源文件路径接通 |
| public FileOutputStream (File *file, boolean append) | 创建字节输出流管道与源文件对象接通,可追加数据 |
| public FileOutputStream(String filepath, boolean append) | 创建字节输出流管道与源文件路径接通,可追加数据 |
字节输出流管道对象的write()方法
| 方法名称 | 说明 |
|---|---|
| public void write(int a) | 写一个字节出去 |
| public void write(byte[] buffer) | 写一个字节数组出去 |
| public void write(byte[] buffer, int pos , int len) | 写一个字节数组的一部分出去 |
| public void close() throws IOExcention | 关闭流 |
byte[] bytes = "我爱你中国666".getBytes();
os.write(bytes); //我爱你中国666
os.write(bytes,0,3); //我
os.close();
换行符一般使用
"\r\n"。
使用完流之后,需要马上关闭,因为这个管道占用的是硬件总线资源。
字节流的应用——文件复制
任何文件的底层都是字节,字节流做复制,是一字不漏的转移完全部字节,复制前后的文件格式一致就没问题!
复制过去必须要带文件名!
InputStream fis = new FileInputStream(srcPath);
OutputStream fos = new FileOutputStream(destPath);
byte[] buffer = new byte[1024];
int len;
while((len = fis.read(buffer)) != -1){
fos.write(buffer,0,len);
}
fis.close();
fos.close();
管道资源的释放方案
如何确保流一定能够被释放?如果发生意外,导致代码没有执行close()方法,怎么办?
方案一:使用finally代码区(不推荐)
finally代码区的特点:无论try中的程序是正常执行了,还是出现了异常,最后都一定会执行finally区,除非JVM终止。
//1.创建一个文件字节输入流管道与源文件连通
InputStream fis = null;
Outputstream fos = null;
try {
fis = new FileInputStream(srcPath);
fos = new FileOutputStream(destPath);
//2.读取一个字节数组,写入一个字节数组
byte[] buffer = new byte[1024];
int len;
while((len = fis.read(buffer))!= -1) {
fos.write(buffer, 0, len);
}
System.out.println("复制成功!");
} catch (Exception e) {
e.printStackTrace();
} finally {
//3.释放资源
try {
if(fos != null) fos.close():
} catch (Exception e) {
e.printStackTrace;
}
try {
if(fis != null) fis.close;
} catch (Exception e) {
e.printStackTrace;
}
}
方案二:使用try-with-resource(推荐)
JDK7开始提供的更简单的资源释放方案。
try (
// 1.在这里定义资源,用完后会自动调用其close方法关闭!
InputStream fis = new FileInputStream(scPath);
OutputStream fos = new FileOutputStream(destPath);
){
// 2.读取一个字节数组,写入一个字节数组
byte[] buffer = new byte[1024];
int len;
while((len = fis.read(buffer))!= -1) {
fos.write(buffer, 0, len);
}
system.out.println("复制成功!");
} catch (Exception e) {
e.printStackTrace);
}
- 资源不一定是管道资源,资源一般指的是最终实现了
AutoCloseable接口的资源。- 资源使用完毕后,会自动调用其
close()方法,完成对资源的释放。
字符流
| 抽象类 | 对应的实现类 |
|---|---|
字符输入流 Reader |
文件字符输入流 FileReader |
字符输出流 Writer |
文件字符输出流 FileWriter |
文件字符输入流 FileReader
作用:以内存为基准,可以把文件中的数据以字符的形式读入到内存中去。
使用构造器创建文件字符输入流
创建字符输入流管道与源文件接通。
public FileReader(File file)
public FileReader(String pathName) //一般用这个
字符输入流管道对象的read()方法
| 方法 | 说明 |
|---|---|
| public int read() | 每次读取一个字符返回,如果发现没有数据可读会返回-1 |
| public int read(byte[] buffer) | 每次用一个字符数组去读取数据,返回字符数组读取了多少个字节,如果发现没有数据可读会返回-1 |
文件字符输入流每次读取多个字符,性能较好,而且读取中文是按照字符读取,不会出现乱码!这是一种读取中文很好的方案。
- 创建文件字符输入流管道。
- 定义一个字符数组,每次读多个字符。
- 定义一个变量记录读取长度。
- 循环读取。
文件字符输出流 FileWriter
使用构造器创建文件字符输出流
| 构造器 | 说明 |
|---|---|
| public FileWriter(File file) | 创建字符输出流管道与源文件对象接通 |
| public Filewriter(String filepath) | 创建字符输出流管道与源文件路径接通 |
| public FileWriter (File file, boolean append) | 创建字符输出流管道与源文件对象接通,可追加数据 |
| public FileWriter(String filepath, boolean append) | 创建字符输出流管道与源文件路径接通,可追加数据 |
字符输出流管道对象的write()方法
| 方法名称 | 说明 |
|---|---|
| void write(int c) | 写一个字符 |
| void write(String str) | 写一个字符串 |
| void write(String str, int off, int len) | 写一个字符串的一部分 |
| void write(char[] cbuf) | 写入一个字符数组 |
| void write(char[] cbuf, int off, int len) | 写入字符数组的一部分 |
字符输出流管道对象的刷新与关闭
| 方法名称 | 说明 |
|---|---|
| public void flush() throws IOException | 刷新流,就是将内存中缓存的数据立即写到文件中去生效! |
| public void close() throws IOException | 关闭流的操作,包含了刷新 |
为什么要刷新?
在管道里有内存缓冲区,不是每个字符都要和磁盘进行耦合,而是在内存缓冲区先集中一波,只做一次IO统一刷新到磁盘中。
刷新就是通知内存赶紧将缓冲区的数据全部写出去。
关闭包含了刷新!
缓冲流-提高性能 Buffered
作用:可以提高字节输入流读取数据的性能
原理:缓冲字节输入流自带了8KB缓冲池;缓冲字节输出流也自带了8KB缓冲池。
public BufferedInputStream (InputStream is)把低级的字节输入流包装成一个高级的缓冲字节输入流,从而提高读数据的性能。
public BufferedoutputStream (OutputStream os)把低级的字节输出流包装成一个高级的缓冲字节输出流,从而提高写数据的性能。
public BufferedReader (Reader r)把低级的字符输入流包装成字符缓冲输入流管道,从而提高字符输入流谈字符数据的性能。public String readLine()读取一行数据返回,如果没有数据可读了,返回null。
public BufferedWriter (Writer r)把低级的字符输出流包装成一个高级的缓冲字符输出流管道,从而提高字符输出流写数据的性能。public void newline()换行。
字符输入转换流 InputStreamReader
作用:解决不同编码时,字符流读取文本内容乱码的问题。
解决思路:先获取文件的原始字节流,再将其按真实的字符集编码转成字符输入流,这样字符输入流中的字符就不乱码了。
| 构造器 | 说明 |
|---|---|
| public InputStreamReader (InputStream is) | 把原始的字节输入流,按照代码默认编码转成字符输入流(与直接用FileReader的效果一样) |
| public InputStreamReader (InputStream is , String charset) | 把原始的字节输入流,按照指定字符集编码转成字符输入流(重点) |
// 1.提取文件的原始字节流
InputStream is = new FileInputStream("111.txt");
// 2.使用指定字符集把原始字节流转换为字符输入转换流
Reader isr = new InputStreamReader(is, "GBK");
// 3.创建缓冲字符输入流包装低级的字符输入流
BufferedReader br = new BufferedReader(isr);
打印流 PrintStream | PrintWriter(实用)
非常实用,如果要输出使用这个就行。
| 构造器 | 说明 |
|---|---|
| public PrintStream(OutputStream/File/String) | 打印流直接通向字节输出流/文件/文件路径 |
| public PrintStream (String fileName, Chgrset charset) | 可以指定写出去的字符编码 |
| public PrintStream(OutputStream out, boolean autoFlush) | 可以指定卖现自动刷新 |
| publis Printstream(Outputstream out, boolean autoFlush,String encoding) | 可以指定实现自动刷新,并可指定字符的编码 |
| 打印流提供的方法 | 说明 |
|---|---|
| public void printin(xxx xx) | 打印任意类型的数据出去 |
| public void write(int/byte[]/byte[]一部分) | 可以支持写字节数据出去 |
打印流本身不支持追加,如果要追加需要包装低级管道。
try (
PrintStream ps = new PrintStream(new FileOutputStream("111.txt"), true);//追加
){
ps.print(97);
ps.println('a');
}catch (Exception e){
e.printStackTrace();
}
特殊数据流 DataInputStream | DataOutputStream (实用)
两者成对出现。通信经常需要这个,项目经常用到。
作用:允许把数据和其类型一并写出去。
| 构造器 | 说明 |
|---|---|
| public DataInputStream(InputStream out) | 创建特殊数据输入流包装基础的字节输入流 |
| public DataOutputStream(OutputStream out) | 创建特殊数据输出流包装基础的字节输出流 |
| 方法 | 说明 |
|---|---|
| public final void writeByte(int v) throws IOException | 将byte类型的数据写入基础的字节输出流 |
| public final void writeInt(int v) throws IOException | 将int类型的数据写入基础的字节输出流 |
| public final void writeDouble(Double v) throws IOException | 将double类型的数据写入基础的字节输出流 |
| public final void writeUTF(String str) throws IOException | 将字符串数据以UTF-8编码成字节写入基础的字节输出流 |
| public void write(int/byte[]/byte[]的一部分) | 支持写字节数据出去 |

浙公网安备 33010602011771号