IO流分类:
1. 输入流(读)和输出流(写)。
2. 因为处理的数据不同,分为字节流和字符流。
close()和flush()的区别:
- flush():将缓冲区的数据刷到目的地中后,流可以使用。
- close():将缓冲区的数据刷到目的地中后,流就关闭了,该方法主要用于结束调用的底层资源。这个动作一定做。
流的操作规律:
- 明确源和目的。
- 数据源:就是需要读取,可以使用两个体系:InputStream、Reader;
- 数据汇:就是需要写入,可以使用两个体系:OutputStream、Writer;
- 操作的数据是否是纯文本数据?
- 如果是:数据源:Reader
数据汇:Writer - 如果不是:数据源:InputStream
数据汇:OutputStream
- 如果是:数据源:Reader
- 明确操作的数据设备。
- 数据源对应的设备:硬盘(File),内存(数组),键盘(System.in)
- 数据汇对应的设备:硬盘(File),内存(数组),控制台(System.out)。
- 需要在基本操作上附加其他功能吗?
- 比如缓冲,如果需要就进行装饰。
字节流: InputStream OutputStream
适合操作非文本文件
处理字节数据的流对象。设备上的数据无论是图片或者dvd,文字,它们都以二进制存储的。二进制的最终都是以一个8位为数据单元进行体现,所以计算机中的最小数据单元就是字节。意味着,字节流可以处理设备上的所有数据,所以字节流一样可以处理字符数据。
输入流:
基类:InputStream(抽象)
实现类: FileInputStream
FileInputStream fi = new FileInputStream(file);
读取:
int i;
while((i=fi.read())!=-1){
System.out.print((char)i);
}
输出流:
基类:OutputStream(抽象)
实现类: FileOutputStream
FileOutputStream fo = new FileOutputStream("C:/a.txt",false);
字符流读写文件:
private static void method2(String src, String dest) throws IOException {
//1,指定数据源
FileInputStream in = new FileInputStream(src);
//2,指定目的地
FileOutputStream out = new FileOutputStream(dest);
//3,读数据
byte[] buffer = new byte[1024];
int len = -1;
while ( (len=in.read(buffer)) != -1) {
//4,写数据
out.write(buffer, 0, len);
}
//5,关闭流
in.close();
out.close();
}
【注】
- 路径: C:/a.txt -> C:\\a.txt
- false: 不覆盖文件,true:更新覆盖原文件
- 原文件不存在则新建
- 路径可由 File 对象代替
字符流: Reader Writer
适合操作文本文件
字符每个国家都不一样,所以涉及到了字符编码问题,那么GBK编码的中文用unicode编码解析是有问题的,所以需要获取中文字节数据的同时+ 指定的编码表才可以解析正确数据。为了方便于文字的解析,所以将字节流和编码表封装成对象,这个对象就是字符流。只要操作字符数据,优先考虑使用字符流体系。
输入流:Reader
实现类:FileReader
//自定义缓冲区
import java.io.*;
class FileReaderDemo2 {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("demo.txt"); //创建读取流对象和指定文件关联。
//因为要使用read(char[])方法,将读取到字符存入数组。所以要创建一个字符数组,一般数组的长度都是1024的整数倍。
char[] buf = new char[1024];
int len = 0;
while(( len=fr.read(buf)) != -1) {
System.out.println(new String(buf,0,len));
}
fr.close();
}
}
输出流:Writer
实现类:FileWriter
缓冲流: Buffer
字节缓冲流:
BufferedInputStream
BufferedOutputStream
字符缓冲流 高效 读取文件
private static void method4(String src, String dest) throws IOException {
//1,指定数据源
BufferedInputStream in = new BufferedInputStream(new FileInputStream(src));
//2,指定目的地
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(dest));
//3,读数据
byte[] buffer = new byte[1024];
int len = -1;
while ( (len = in.read(buffer)) != -1) {
//4,写数据
out.write(buffer, 0, len);
}
//5,关闭流
in.close();
out.close();
}
字符缓冲流:
BufferedReader(读)
FileReader fr = new FileReader("bufdemo.txt");
BufferedReader bufr = new BufferedReader(fr);
String line = null;
while((line=bufr.readLine())!=null){ //readLine方法返回的时候是不带换行符的。
System.out.println(line);
}
bufr.close();
BufferedWriter(写)
FileWriter fw = new FileWriter("bufdemo.txt");
BufferedWriter bufw = new BufferedWriter(fw);//让缓冲区和指定流相关联。
for(int x=0; x<4; x++){
bufw.write(x+"abc");
bufw.newLine(); //写入一个换行符,这个换行符可以依据平台的不同写入不同的换行符。
bufw.flush();//对缓冲区进行刷新,可以让数据到目的地中。
}
bufw.close();//关闭缓冲区,其实就是在关闭具体的流。
字符缓冲流读写文件
public class CopyTextFile {
public static void main(String[] args) throws IOException {
//1,指定数据源, 是数据源中读数据,采用输入流
BufferedReader in = new BufferedReader(new FileReader("file.txt"));
//2,指定目的地,是把数据写入目的地,采用输出流
BufferedWriter out = new BufferedWriter(new FileWriter("copyFile.txt"));
//3,读数据
String line = null;
while ( (line = in.readLine()) != null ) {
out.write(line);//4,写数据
out.newLine();//写入换行符号
}
//5,关闭流
out.close();
in.close();
}
}
转换流: InputStreamReader OutputStreamWriter
转换流特有功能:
- 转换流可以将字节转成字符,原因在于,将获取到的字节通过查编码表获取到指定对应字符。
凡是操作设备上的文本数据,涉及编码转换,必须使用转换流。
转换流 InputStreamReader
【注意】:在读取指定的编码的文件时,一定要指定编码格式,否则就会发生解码错误,而发生乱码现象。
代码演示:
public class InputStreamReaderDemo {
public static void main(String[] args) throws IOException {
//演示字节转字符流的转换流
readCN();
}
public static void readCN() throws IOException{
//创建读取文件的字节流对象
InputStream in = new FileInputStream("c:\\cn8.txt");
//创建转换流对象
//InputStreamReader isr = new InputStreamReader(in);这样创建对象,会用本地默认码表读取,将会发生错误解码。
InputStreamReader isr = new InputStreamReader(in,"utf-8");
//使用转换流去读字节流中的字节
int ch = 0;
while((ch = isr.read())!=-1){
System.out.println((char)ch);
}
//关闭流
isr.close();
}
}
转换流 OutputStreamWriter
【注意】:在写出指定的编码的文件时,一定要指定编码格式,否则读取时编码格式不同可能发生乱码现象。
将字符串按照指定的编码表转成字节,在使用字节流将这些字节写出去。
代码演示:
public static void writeCN() throws Exception {
//创建与文件关联的字节输出流对象
FileOutputStream fos = new FileOutputStream("c:\\cn8.txt");
//创建可以把字符转成字节的转换流对象,并指定编码
OutputStreamWriter osw = new OutputStreamWriter(fos,"utf-8");
//调用转换流,把文字写出去,其实是写到转换流的缓冲区中
osw.write("你好");//写入缓冲区。
osw.close();
}
打印流
PrintWriter
package com.qfedu.bhy.test_printwriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 打印流输出异常日志信息
* @author bhy
*
*/
public class MyException extends Exception{
//设置异常信息
public String getMessage() {
return "异常信息--打印异常日志";
}
//定义异常时执行的方法
public void printException() {
PrintWriter pw = null;
FileWriter fw = null;
try {
fw = new FileWriter("F:/print.txt",true);//true:文件不覆盖
pw = new PrintWriter(fw);
} catch (IOException e) {
e.printStackTrace();
}finally {
this.printStackTrace(pw);//this.printStackTrace(PrintWriter s); 写出当前异常信息到指定打印流中
pw.print(new SimpleDateFormat("yyyy-MM-dd hh:mm:ss")
.format(new Date())+"\r\n");//追加时间信息到打印流中
//关闭流
if(fw!=null) {
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(pw!=null) {
pw.close();
}
}
}
}
附上自定义异常使用代码
package com.qfedu.bhy.test_printwriter;
public class TestPrintWriter {
public static void main(String[] args){
try { /捕获异常
print();
} catch (MyException e) { //处理异常
e.printException();//调用自定义异常的异常处理方法
}
}
public static int print()throws MyException{//声明异常
int[] arr = new int[] {1,4,0,3};
int n = 0 ;
for (int i = 0; i < arr.length+1; i++) {
if(i > arr.length-1 || arr[i] == 0) {
throw new MyException();//抛出自定义异常对象
}else {
n = arr[i+1]/arr[i];
}
}
return n;
}
}
对象流
- ObjectInputStream
- ObjectOutputStream
对象流–实现序列化:
import java.io.*;
class ObjectStreamDemo {
public static void main(String[] args) throws Exception{
writeObj();
readObj();
}
public static void readObj()throws Exception{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("obj.txt"));
Object obj = ois.readObject();//读取一个对象。
System.out.println(obj.toString());
}
public static void writeObj()throws IOException{
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.txt"));
oos.writeObject(new Person("lisi",25)); //写入一个对象。
oos.close();
}
}
class Person implements Serializable{
private static final long serialVersionUID = 42L;//生成一个序列化ID号
private transient String name;//用transient修饰后name将不会进行序列化
public int age;
Person(String name,int age){
this.name = name;
this.age = age;
}
public String toString(){
return name+"::"+age;
}
}