IO流原理及流的分类
流按不同的角度分类
主要关注蓝色框的这些流。
一、流的分类:
1.操作数据单位:字节流、字符流
2.数据的流向:输入流、输出流
3.流的角色:节点流、处理流
二:流的体系结构
抽象基类 节点流(或文件流) 缓冲流(处理流的一种)
InputStream FileInputStream BufferedInputStream
OutputStream FileOutputStream BufferedOutputStream
Reader FileReader BufferedReader
Writer FileWriter BufferedWriter
字符输入输出流
FileReader读入数据
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
public class Demo2 {
public static void main(String[] args){
/*
将hello.txt文件内容读入程序中,并输出到控制台
*/
//1.实例化File类的对象,指明要操作的文件
File file=new File("D:\\java代码\\src\\src\\com\\java\\hello.txt");
//2.提供具体的流
FileReader fr=null;
try{
fr=new FileReader(file);
//3.数据的读入 返回读入的一个字符。如果达到文件末尾,返回-1
// 方式一:
// int data=fr.read();
// while (data!=-1){
// System.out.print((char)data);
// data=fr.read();
// }
//方式二:语法上针对方式一的修改
int data;
while ((data=fr.read())!=-1){
System.out.print((char)data);
}
}catch (IOException e){
e.printStackTrace();
}finally {
//4.流的关闭操作
if (fr!=null){
try {
fr.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
}
}
说明:
1.read()的理解:返回读入的一个字符。如果达到文件末尾,返回-1;
2异常的处理:为了保证流资源一定可以执行关闭操作。需要使用try-catch-finlly处理。
3.读入的文件一定要存在,否则报错FileNotFoundException 找不到指定文件。
FileReader中使用read(char[ ] cbuf)
对read()操作升级:使用read的重载方法。
方式一:
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
public class Demo2 {
public static void main(String[] args){
/*
将hello.txt文件内容读入程序中,并输出到控制台
*/
//1.实例化File类的对象,指明要操作的文件
File file=new File("D:\\java代码\\src\\src\\com\\java\\hello.txt");
//2.提供具体的流
FileReader fr=null;
try{
fr=new FileReader(file);
char[] cbuf=new char[5];
int len;
//read(char[] cbuf):返回每次读入cbuf数组中的字符个数。
//如果读到文件末尾,返回-1.
while ((len=fr.read(cbuf))!=-1){
//错误的写法,如果末尾的文件内容比较短,不足数组长度5,那么将无法覆盖整个数组
//那么输出时,上一次输出未被覆盖的内容会再一次输出
// for(int i=0;i<cbuf.length;i++){
// System.out.print(cbuf[i]);
// }
//改正:
for(int i=0;i<len;i++){
System.out.print(cbuf[i]);
}
}
}catch (IOException e){
e.printStackTrace();
}finally {
//4.流的关闭操作
if(fr!=null){
try {
fr.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
}
}
方式二:
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
public class Demo2 {
public static void main(String[] args){
/*
将hello.txt文件内容读入程序中,并输出到控制台
*/
//1.实例化File类的对象,指明要操作的文件
File file=new File("D:\\java代码\\src\\src\\com\\java\\hello.txt");
//2.提供具体的流
FileReader fr=null;
try{
fr=new FileReader(file);
char[] cbuf=new char[5];
int len;
//错误写法,对应之前的i<cbuf.length错误
// while ((len=fr.read(cbuf))!=-1){
// String str=new String(cbuf);
// System.out.print(str);
// }
//正确写法
while ((len=fr.read(cbuf))!=-1){
String str=new String(cbuf,0,len);
System.out.print(str);
}
}catch (IOException e){
e.printStackTrace();
}finally {
//4.流的关闭操作
if (fr!=null){
try {
fr.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
}
}
FileWriter读出数据
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
public class Demo2 {
public static void main(String[] args){
/*
从内存中写出数据到硬盘的文件里
说明:
输出操作对应的file可以不存在,若不存在,输出的过程中会自动创建此文件。
FileWriter fw=new FileWriter(file,false)
表示不在文件原有的内容上叠加读出的内容,删去程序执行前的原有内容重新写
默认情况是false
FileWriter fw=new FileWriter(file,true)
表示在文件原有的内容后面继续写内容
*/
//1.实例化File类的对象,指明要操作的文件
File file=new File("D:\\java代码\\src\\src\\com\\java\\hello.txt");
//2.提供FileWriter的对象,用于数据的写出
FileWriter fw=null;
try {
fw=new FileWriter(file);
//3.写出的操作
fw.write("I have a deream\n");
fw.write("i love u");
}catch (IOException e){
e.printStackTrace();
}finally {
if(fw!=null){
//4.流资源关闭
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
利用FileReader和FileWriter实现文本文件的复制
import java.io.*;
public class Demo1{
public static void main(String[] args) {
//file:原文件,一定要存在
//file1:复制内容的文件,可以不存在,系统自动创建
File file=new File("D:\\java代码\\src\\src\\com\\java\\hello.txt");
File file1=new File("D:\\java代码\\src\\src\\com\\java\\hello1.txt");
FileReader fr=null;
FileWriter fw=null;
try{
fw=new FileWriter(file1);
fr=new FileReader(file);
char[] cbuf=new char[10];
int len;
while ((len=fr.read(cbuf))!=-1){
fw.write(sbuf,0,len);
}
}catch (IOException e){
e.printStackTrace();
}finally {
if(fr!=null){
try {
fr.close();
}catch (IOException e){
e.printStackTrace();
}
}
if(fw!=null){
try {
fw.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
}
}
字符流不能处理图片文件
字节输入输出流
FileInputStream和FileOutputStream不能处理文字文件(但是复制操作可以),可能会乱码,但是数字和字母可以。
而字符流不能用于复制非文本文件。
复制图片:
import java.io.*;
public class Demo1{
public static void main(String[] args) {
File file=new File("D:\\大一下学期文档\\桌面壁纸.jpg");
File file1=new File("D:\\大一下学期文档\\ok.jpg");
FileInputStream fr=null;
FileOutputStream fw=null;
try{
fw=new FileOutputStream(file1);
fr=new FileInputStream(file);
byte[] buffer=new byte[1024];
int len;
while ((len=fr.read(buffer))!=-1){
fw.write(buffer,0,len);
}
}catch (IOException e){
e.printStackTrace();
}finally {
if(fr!=null){
try {
fr.close();
}catch (IOException e){
e.printStackTrace();
}
}
if(fw!=null){
try {
fw.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
}
}
结论: 对于文本文件(.txt,.java,.c,.cpp),使用字符流处理。对于非文本文件(.jpg,.map3,.mp4,.avi,.doc,.ppt,…),使用字节流处理。
使用缓冲流(字节型)对非文本文件的复制
BufferedInputStream
BufferedOutputStream
缓存流的作用:提高流的读取、写入的速度
提高的原因:内部提供了一个缓冲区。
import java.io.*;
public class Demo1{
public static void main(String[] args) {
/*
处理流之一:缓冲流的使用
1.缓冲流:
BufferedInputStream
BufferedOutputStream
BufferedReader
BufferedWriter
2.作用:提供流的读取、写入的速度
*/
//实现非文本文件的复制
//1.造文件
File srcfile=new File("D:\\大一下学期文档\\桌面壁纸.jpg");
File desfile=new File("D:\\大一下学期文档\\ok.jpg");
//2.造节点流
FileInputStream fis=null;
FileOutputStream fos=null;
//3.造缓冲流
BufferedInputStream bis=null;
BufferedOutputStream bos=null;
try {
fis=new FileInputStream(srcfile);
fos=new FileOutputStream(desfile);
bis=new BufferedInputStream(fis);
bos=new BufferedOutputStream(fos);
//复制细节:读取+写入
byte[] buffer=new byte[10];
int len;
while ((len=bis.read(buffer))!=-1){
bos.write(buffer,0,len);
}
}catch (IOException e){
e.printStackTrace();
}finally {
/*4.资源关闭:先关外层再内层
造流的时候先造内层再外层
说明:关闭外层流的同时,内层流也会自动地关闭。
所以关于内层流的关闭可以省略
*/
try {
if(bis!=null)
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if(bos!=null)
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
使用缓冲流(字符型)对文本文件复制
BufferedWriter
BufferedReader
处理流就是“套接”在已有流的基础上的。
和之前字节型的缓冲流类似,不过相对于字节流,多了一个读取方法。
处理流之二:转换流
处理流之二:转换流的使用:将一个字节的输入流转换为字符的输入流
1.转换流:
InputStreamReader
OutputStreamWriter
2.作用:提供字节流与字符流之间的转换
3.解码:字节、字节数组--->字符数组、字符串
编码:字符数组、字符串--->字节、字节数组
4.字符集
解码
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
public class Demo {
public static void main(String[] args) {
FileInputStream fis=null;
InputStreamReader isr=null;
try {
fis=new FileInputStream("D:\\java代码\\src\\src\\com\\java\\hello.txt");
//参数2:指明字符集,字符集的种类取决于hello.txt文件存储时按照什么字符集
isr=new InputStreamReader(fis,"UTF-8");
char[] cbuf=new char[20];
int len;
while ((len=isr.read(cbuf))!=-1){
String str=new String(cbuf,0,len);
System.out.println(str);
}
}catch (IOException e){
e.printStackTrace();
}finally {
try {
if(isr!=null)
isr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
编码
import java.io.*;
public class Demo {
public static void main(String[] args) {
File file=new File("D:\\java代码\\src\\src\\com\\java\\hello.txt");
File file1=new File("D:\\java代码\\src\\src\\com\\java\\hello1.txt");
FileInputStream fis=null;
FileOutputStream fos=null;
InputStreamReader isr=null;
OutputStreamWriter osw=null;
try {
fis=new FileInputStream(file);
fos=new FileOutputStream(file1);
isr=new InputStreamReader(fis,"UTF-8");
osw=new OutputStreamWriter(fos,"gbk");
char[] cbuf=new char[20];
int len;
while ((len=isr.read(cbuf))!=-1){
osw.write(cbuf,0,len);
}
}catch (IOException e){
e.printStackTrace();
}finally {
try {
if(isr!=null)
isr.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if(osw!=null)
osw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
字符集
标准输入、输出流
该部分内容只需要稍作了解
对象流
对象序列化机制
import java.io.*;
public class Demo {
public static void main(String[] args) {
/*
对象流的使用
1.ObjectInputStream和ObjectOutputStream
2.作用:用于存储和读取基本数据类型数据或对象的处理流。
它的强大之处就是可以把java中的对象写入到数据源中,
也能把对象从数据源中还原回来。
*/
//序列化过程:将内存中的java对象保存到磁盘中或通过网络传输出去。
//使用ObjectOutputStream实现
ObjectOutputStream oos= null;
try {
oos = new ObjectOutputStream(new FileOutputStream("hello.dat"));
oos.writeObject(new String("i love beijing"));
oos.flush();//刷新操作
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if(oos!=null)
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//反序列化过程:将磁盘文件中的对象还原为内存中的一个java对象
//使用OnjectInputStream来实现
ObjectInputStream ois= null;
try {
ois = new ObjectInputStream(new FileInputStream("hello.dat"));
Object obj= null;
obj = ois.readObject();
String str=(String)obj;
} catch (IOException e) {
e.printStackTrace();
}catch (ClassNotFoundException e) {
e.printStackTrace();
}finally {
try {
if(ois!=null)
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
java对象可序列化需要满足的要求
需要当前类提供一个全局常量:serialVersionUID
自定义Person类:
import java.io.*;
public class Demo {
public static void main(String[] args) {
ObjectOutputStream oos=null;
try {
oos=new ObjectOutputStream(new FileOutputStream("object.dat"));
oos.writeObject(new Person("11",12));
oos.flush();
}catch (IOException e){
e.printStackTrace();
}finally {
try {
if (oos!=null)
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
ObjectInputStream ois=null;
try {
ois=new ObjectInputStream(new FileInputStream("object.dat"));
Person p=(Person) ois.readObject();
System.out.println(p);
}catch (IOException e){
e.printStackTrace();
}catch (ClassNotFoundException e){
e.printStackTrace();
}catch (ClassCastException e){
e.printStackTrace();
}finally{
try {
if(ois!=null)
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
class Person implements Serializable{
public static final long serialVersionUID=475463534532L;
private String name;
private int age;
public Person(String name,int age){
this.name=name;
this.age=age;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
ObjectOutputStream和ObjectInputStream不能序列化static和transient修饰的成员变量。
随机存取文件流
p616-619跳过先不看