1. IO流概念
InputOutputStream - 输入输出流
Java程序输入输出数据的方式
2. IO流的分类
根据方向可以分为 输入流 输出流
根据操作的内容的不同 分为 字节流 和 字符流
两两相乘就得到了四大基本流:
输入流 输出流
字符流 Reader Writer
字节流 InputStream OutputStream
这四大基本流都是抽象的,使用时通常使用这些抽象类的具体实现类
字符输入流 Reader - FileReader
构造方法:
构造方法摘要
FileReader(File file)
在给定从中读取数据的 File 的情况下创建一个新 FileReader。
FileReader(String fileName)
在给定从中读取数据的文件名的情况下创建一个新 FileReader。
重要方法:
int read()
读取单个字符。
int read(char[] cbuf)
将字符读入数组。
abstract int read(char[] cbuf, int off, int len)
将字符读入数组的某一部分。
abstract void close()
关闭该流并释放与之关联的所有资源。
**为什么read方法返回的不是char而是Int
因为read如果返回的是char,则无法用任意的char表示到达了文件的结尾,所以此处不返回char 而是返回int,正常情况下返回的是正数,强转为char即可得到对应字符,而当读取到文件结尾返回-1表示
案例:编写一个流 来读取外部文件中的字符数据
package cn.tedu.io;
import java.io.FileReader;
import java.io.Reader;
/**
* 案例:编写一个流 来读取外部文件中的字符数据
*/
public class Demo01 {
public static void main(String[] args) throws Exception {
//1.创建文件字符输入流链接到 1.txt上
Reader reader = new FileReader("1.txt");
//2.通过流读取文件中的数据
int i = 0;
while((i=reader.read())!=-1){
System.out.println((char)i);
}
//3.关闭流
reader.close();
}
}
字符流-字符输出流-Wirter-FileWriter
构造方法
构造方法摘要
FileWriter(File file)
根据给定的 File 对象构造一个 FileWriter 对象。
FileWriter(String fileName)
根据给定的文件名构造一个 FileWriter 对象。
重要方法
void write(char[] cbuf)
写入字符数组。
abstract void write(char[] cbuf, int off, int len)
写入字符数组的某一部分。
void write(int c)
写入单个字符。
abstract void close()
关闭此流,但要先刷新它。
abstract void flush()
刷新该流的缓冲。
**在输出数据时,有部分数据可能会被缓冲在流的内部,通过调用flush()可以强制刷新流,将缓存在流内部的数据刷出出去,所以在writer()之后 最好做一次flush()
**调用close()方法时,close()方法内部会隐含的做一次flush()防止在关流时有数据死在缓冲区内
案例:编写一个流 来讲指定的字符写出到外部文件中
package cn.tedu.io;
import java.io.FileWriter;
import java.io.Writer;
/**
* 案例:编写一个流 来将指定的字符写出到外部文件中
*/
public class Demo02 {
public static void main(String[] args) throws Exception {
//1.创建文件字符输出流
Writer writer = new FileWriter("2.txt");
//2.通过字符输出流输出数据
writer.write((int)'a');
writer.write((int)'b');
writer.write((int)'c');
writer.write((int)'d');
writer.write((int)'e');
//3.刷新流
//writer.flush();
//--关闭流,关闭流过程中会隐含的刷新一次流
writer.close();
}
}
关闭流的过程
IO流用过之后必须关闭,但是IO流的代码中往往存在大量的异常,为了保证关流的操作一定会被执行,所以通过关流都在finally代码块中进行。
而为了保证finally中可以看到流对象,通常都要外置定义流对象。
又由于close方法本身有异常,需要再次捕获异常。
而在finally里通过将引用置为null 使其成为垃圾 可以被回收。
finally {
//3.关闭流
if(reader!=null){
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
} finally{
reader = null;
}
}
if(writer!=null){
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
} finally{
writer = null;
}
}
}
案例:编写流来拷贝文件
package cn.tedu.io;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
/**
* 案例:利用字符流实现字符文件的拷贝 1.txt -> 3.txt
*/
public class Demo03 {
public static void main(String[] args) {
Reader reader = null;
Writer writer = null;
try {
//1.创建字符输入流 连接1.txt 创建字符输出流 连接3.txt
reader= new FileReader("1.txt");
writer = new FileWriter("3.txt");
//2.从1.txt读取数据
int i = 0;
while((i = reader.read())!=-1){
writer.write(i);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//3.关闭流
if(reader!=null){
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
} finally{
reader = null;
}
}
if(writer!=null){
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
} finally{
writer = null;
}
}
}
}
}
**由于一次拷贝一个字节 效率非常低 我们可以自定义一个缓冲区
package cn.tedu.io;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
/**
* 通过字符流 拷贝字符文件 讨论效率问题
*/
public class Demo04 {
public static void main(String[] args){
//--开始时间
long begin = System.currentTimeMillis();
Reader reader = null;
Writer writer = null;
try {
//1.创建流
reader = new FileReader("4.txt");
writer = new FileWriter("5.txt");
//2.拷贝数据
//int count = 0;
int i = 0;
char [] buf = new char [1024];
while ((i = reader.read(buf)) != -1) {
//System.out.println("读取了"+(++count)+"次");
writer.write(buf,0,i);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//3.关闭流
if(reader!=null){
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
} finally{
reader = null;
}
}
if(writer!=null){
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
writer = null;
}
}
}
//--结束时间
long end = System.currentTimeMillis();
System.out.println("====共耗时:"+(end-begin)+"ms====");
}
}
缓冲流概述
java提供了自带缓冲区的流 BufferedReader bufferedWriter,内部自带缓冲区
功能:
装饰其他流 提升读写性能
装饰起来流 提供额外方法
重要API
构造方法:
构造方法摘要
BufferedReader(Reader in)
创建一个使用默认大小输入缓冲区的缓冲字符输入流。
BufferedReader(Reader in, int sz)
创建一个使用指定大小输入缓冲区的缓冲字符输入流。
重要方法:
String readLine()
读取一个文本行。
构造方法:
构造方法摘要
BufferedWriter(Writer out)
创建一个使用默认大小输出缓冲区的缓冲字符输出流。
BufferedWriter(Writer out, int sz)
创建一个使用给定大小输出缓冲区的新缓冲字符输出流。
重要方法:
void newLine()
写入一个行分隔符。
案例:利用缓冲流 包装普通的文件流 复制文件
package cn.tedu.io;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
/**
* BufferedReader和BufferedWriter提供的新方法
*
* BufferedReader
* readline()
*
* BufferedWriter
* newLine()
*/
public class Demo06 {
public static void main(String[] args) throws Exception {
//1.创建流 并用缓冲流包装
BufferedReader reader = new BufferedReader(new FileReader("1.txt"));
BufferedWriter writer = new BufferedWriter(new FileWriter("2.txt"));
//2.对接流 拷贝文件
String line = null;
while((line = reader.readLine())!=null){
writer.write(line);
writer.newLine();
}
//3.关闭流
reader.close();
writer.close();
}
}
字节流-字节输入流-InputStream-FileInputStream
构造方法:
构造方法摘要
FileInputStream(File file)
通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的 File 对象 file 指定。
FileInputStream(String name)
通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的路径名 name 指定。
重要方法:
int read()
从此输入流中读取一个数据字节。
int read(byte[] b)
从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中。
int read(byte[] b, int off, int len)
从此输入流中将最多 len 个字节的数据读入一个 byte 数组中。
void close()
关闭此文件输入流并释放与此流有关的所有系统资源。
**其中read()方法读取字节信息,但返回的是一个int,这是因为如果返回byte,则无论返回什么都无法表示读取到文件结尾的状态,所以read()方法 返回的是int,正常读取到数据时都是正数,直接强转就可以得到对应byte,而当读取到文件结尾时,返回一个-1,作为特殊状态值。
案例:利用字节流复制文件
package cn.tedu.io2;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
/**
* 利用字节流实现文件的复制
*/
public class Demo01 {
public static void main(String[] args) throws Exception {
//1.创建流
InputStream in = new FileInputStream("1.wmv");
OutputStream out = new FileOutputStream("2.wmv");
//2.对接流 实现复制
int i = 0;
while((i = in.read())!=-1){
out.write(i);
}
//3.关闭流
in.close();
out.close();
}
}
案例:利用字节流复制文件 - 使用自定义的缓冲区
package cn.tedu.io2;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
/**
* 利用字节流实现文件的复制 - 使用缓冲区
*/
public class Demo02 {
public static void main(String[] args) throws Exception {
//1.创建流
InputStream in = new FileInputStream("1.wmv");
OutputStream out = new FileOutputStream("2.wmv");
//2.对接流 实现复制
int i = 0;
byte [] tmp = new byte[1024];
while((i = in.read(tmp))!=-1){
out.write(tmp,0,i);
}
//3.关闭流
in.close();
out.close();
}
}
字节流-字节输出流-OutputStream-FileOutputStream
构造方法:
**通过boolean的append参数,可以指定数据是否追加,如果传入false(默认就是false)则,会产生新的文件覆盖旧的文件,如果传入true,则在原有文件的基础上进行追加
构造方法摘要
FileOutputStream(File file)
创建一个向指定 File 对象表示的文件中写入数据的文件输出流。
FileOutputStream(File file, boolean append)
创建一个向指定 File 对象表示的文件中写入数据的文件输出流。
FileOutputStream(String name)
创建一个向具有指定名称的文件中写入数据的输出文件流。
FileOutputStream(String name, boolean append)
创建一个向具有指定 name 的文件中写入数据的输出文件流。
普通方法:
void write(byte[] b)
将 b.length 个字节从指定 byte 数组写入此文件输出流中。
void write(byte[] b, int off, int len)
将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此文件输出流。
void write(int b)
将指定字节写入此文件输出流。
void flush()
刷新此输出流并强制写出所有缓冲的输出字节。
void close()
关闭此文件输出流并释放与此流有关的所有系统资源。
**在利用输出流输出数据的过程中,流的底层具有缓冲机制提升效率,但同时也有可能造成部分数据堆积在底层流的缓冲区中,一时无法写出,此时可以调用flush()方法,手动的将流中缓冲的数据写出
**close()方法关闭流,在关闭流的过程中,会隐含的调用一次flush() 保证不会有数据死在缓冲区里。
1. 转换流概述
字符流的底层也是字节流,只不过在字节流的基础上增加了缓冲区和编解码器。
字符流内置的编解码器默认采用的编码集是系统码,并且无法修改。
这在使用字符流读写非系统码的字符数据时就会造成乱码。
此时无法通过字符流解决,java提供了转换流,可以自己编写字节流读取数据,再通过转换流转换为字符流,并且在这个过程中自己手动指定码表,从而实现采用指定码表的自定义字符流。
转换流API
java.io
类 InputStreamReader
构造方法:
构造方法摘要
InputStreamReader(InputStream in)
创建一个使用默认字符集的 InputStreamReader。
InputStreamReader(InputStream in, String charsetName)
创建使用指定字符集的 InputStreamReader。
java.io
类 OutputStreamWriter
构造方法:
构造方法摘要
OutputStreamWriter(OutputStream out)
创建使用默认字符编码的 OutputStreamWriter。
OutputStreamWriter(OutputStream out, String charsetName)
创建使用指定字符集的 OutputStreamWriter。
案例:拷贝一个utf-8编码集 包含中文的文本文件 要求产生的文件也是utf-8编码
package cn.tedu.io2;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
/**
* 案例:通过转换流 生成自定义码表的字符流 复制文件 解决乱码
*/
public class Demo04 {
public static void main(String[] args) throws Exception {
//1.创建字节流
InputStream in = new FileInputStream("d://8.txt");
OutputStream out = new FileOutputStream("d://9.txt");
//2.创建转换流 将字节流转换为字符流 并显式指定码表为utf-8
InputStreamReader reader = new InputStreamReader(in,"utf-8");
OutputStreamWriter writer = new OutputStreamWriter(out,"utf-8");
//3.对接流 复制文件
char [] data = new char[1024];
int i = 0;
while((i=reader.read(data))!=-1){
writer.write(data,0,i);
}
//4.关闭流
reader.close();
writer.close();
}
}
案例:拷贝一个utf-8编码集 包含中文的文本文件 要求产生的文件是gbk编码
package cn.tedu.io2;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
/**
* 案例:通过转换流 生成自定义码表的字符流 复制文件 将utf-8文件转换为gbk格式的文件
*/
public class Demo05 {
public static void main(String[] args) throws Exception {
//1.创建字节流
InputStream in = new FileInputStream("d://8.txt");
OutputStream out = new FileOutputStream("d://9.txt");
//2.创建转换流 将字节流转换为字符流 并显式指定码表为utf-8
InputStreamReader reader = new InputStreamReader(in,"utf-8");
OutputStreamWriter writer = new OutputStreamWriter(out,"gbk");
//3.对接流 复制文件
char [] data = new char[1024];
int i = 0;
while((i=reader.read(data))!=-1){
writer.write(data,0,i);
}
//4.关闭流
reader.close();
writer.close();
}
}