Java-IO流详解
一、IO流相关概念介绍
IO流:输入与输出流,其实输入输出可以用内存作为参照,输入指的是把硬盘中的数据读取到内存中使用,输出指的是把内存的数据写入到硬盘保存。
IO流分类:
字节流:字节输入流InputStream 字节输出流OutputStream
字符流: 字符输入Reader 字符输出流Writer
注意:在计算机中,一切文件数据在存储时都是以二进制数字形式存储的,传输时也如此,因此字节流可以传输任意文件数据。在操作时,无论使用什么流对象,底层传输的都是二进制数据。
二、字节输出流OutputStream
java.io.OutputStream,是一个抽象类,此抽象类是表示字节输出流的所有类的父类。
定义的共性方法:
public void close():关闭此输出流并释放与此流相关联的任何系统资源。
public void flush():刷新此输出流并强制任何缓冲的输出字节流。
public void write(byte[] b):将b.lengh字节从指定的字节数组写入输出流
一次性写入多个字节,如果写的第一个字节是正数(0-127),显示的时候会 查询ASCII表,如果写的第一个字节是负数,那么第一个字节会和第二个字节,两个字节组成一个中文显示,查询系统默认编码表(简体中文是GBK)。
public void write(byte[] b,int off,int len):从指定的字节数组写入len字节,从偏移量off(开始的索引)开始输出到此输出流。
public void write(int b):将指定的字节写入输出流。
注意:OutputStream是一个抽象类,想要使用方法,需要使用子类对象,常用的子类FileOutputStream(文件字节输出流)。
构造方法:
FileOutputStream(String name):创建向指定名称的文件中写入数据的输出文件流。
FileOutputStream(File file):创建向指定file对象中写入数据的输出文件流。
构造方法的作用:
1.创建一个FileOutputStream对象。
2.会根据构造方法中传递的文件/文件路径,创建一个空文件。
3.会把创建好的FileOutputStream指向创建好的文件。
写入数据的原理:
java程序->JVM->OS(操作系统)->OS调用写数据的方法->把数据写入到文件中。
字节输出流的使用步骤:
(下面几个步骤都会抛出异常,可以一次性抛出异常IOException)
1.创建一个FileOutputStream对象,构造方法中传递文件写入的路径或对象。
2.调用对象中得write方法。
3.释放资源(流的使用会占用一定的内存,使用完毕要把内存清空,提高程序的效率)。
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
public class IoDemo01 {
public static void main(String[] args) throws IOException {
// 1.创建一个FileOutputStream对象,构造方法中传递文件写入的路径或对象(会抛出异常)
FileOutputStream f = new FileOutputStream("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt");//绝对路径和相对路径都可以
// 2.调用对象中得write方法
f.write(65);//写入的数据为A
// public void write(byte[] b):将b.lengh字节从指定的字节数组写入输出流
//一次性写入多个字节,如果写的第一个字节是正数(0-127),显示的时候会查询ASCII表,如果写的第一个字节是负数
//那么第一个字节会和第二个字节,两个字节组成一个中文显示,查询系统默认编码表(简体中文是GBK)
//第一个字节是正数
byte[] b1 ={66,67,65,66};//BCAB
f.write(b1);
//第一个字节是负数
byte[] b2 ={-66,65,67,69};
f.write(b2);//続CE
// public void write(byte[] b,int off,int len):从指定的字节数组写入len字节,从偏移量off开始输出到此输出流
f.write(b1, 0, 1);//B
/*
写入字符串的方法:可以使用String类中的getBytes()方法把字符串转换为字节数组
*/
String s ="字符串";
byte[] b3 = s.getBytes();
//会将字符串转成对应的字节数组
System.out.println(Arrays.toString(b3));//[-41, -42, -73, -5, -76, -82]
f.write(b3);//字符串
// 3.释放资源(流的使用会占用一定的内存,使用完毕要把内存清空,提高程序的效率)
f.close();
}
}
追加写数据:使用两个参数的构造方法:
FileOutputStream(File file, boolean append) 创建文件输出流以写入由指定的 File对象表示的文件。
append - 如果 true ,则字节将被写入文件的末尾而不是开头。
false-创建新文件,覆盖原来的文件。
FileOutputStream(String name, boolean append) 创建文件输出流以指定的名称写入文件。
append - 如果 true ,则字节将被写入文件的末尾而不是开头。
false-创建新文件,覆盖原来的文件。
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class IoDemo02 {
public static void main(String[] args) throws IOException {
// append - 如果 true ,则字节将被写入文件的末尾而不是开头
//false-创建新文件,覆盖原来的文件
FileOutputStream f = new FileOutputStream("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt",true);
//2.调用对象中得write方法
f.write("hello".getBytes());
//3.释放资源
f.close();
}
}
三、字节输入流InputStream
java.io.InputStream抽象类,此抽象类表示所有字节输入流的父类。
定义的共性方法:
int read():从输入流中读取数据的下一个字节,读取到文件末尾返回-1。
int read(byte[] b):从输入流中读取一定数量的字节,并将其存入缓冲区数组b中。
void close():关闭此输入流并释放有关的所有系统资源。
注意:InputStream也是一个抽象类,需要使用子类来进行方法的使用,常用子类为FileInputStream。
构造方法:
FileInputStream(String name)通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的路径名 name命名。
FileInputStream(File file)通过打开与实际文件的连接创建一个 FileInputStream ,该文件由文件系统中的 File对象 file命名。
构造方法的作用:
1.创建一个 FileInputStream对象,构造方法中指定读取的路径或文件。
2.会把 FileInputStream对象指向要读取的文件。
读取数据原理:
java程序->JVM->OS->OS读取方法->读取文件
字节输入流使用步骤:
1.创建创建一个 FileInputStream对象,构造方法中指定读取的路径或文件。
2.调用对象中read方法,读取文件。
3.释放资源。
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
public class IoDemo03 {
public static void main(String[] args) throws IOException {
// 1.创建创建一个 FileInputStream对象,构造方法中指定读取的路径或文件
FileInputStream f = new FileInputStream("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt");
//2.调用对象中read方法,读取文件,要多次读取可以使用循环
//int read():从输入流中读取数据的下一个字节,读取到文件末尾返回-1
// int i1=f.read();
// System.out.println(i1);//65
//
// int i2=f.read();
// System.out.println(i2);//66
//
// int i3=f.read();
// System.out.println(i3);//-1 ,读取到文件末尾返回-1
// int read(byte[] b):从输入流中读取一定数量的字节,并将其存入缓冲区数组b中
byte[] b = new byte[3];
int i4 = f.read(b);
System.out.println(i4);//2
System.out.println(Arrays.toString(b));//[65, 66, 0]
//3.释放资源
f.close();
}
}
四、Reader字符输入流
java.io.Reader抽象类,是所有字符输入流的顶层父类。
字节流读取中文时可能不会显示完整字符,因为在UTF-8格式下一个中文字符占用3个字节,GBK格式下一个中文字符占用2个字节,因此Java中有了对应的字符输入输出流。
Reader定义的一些共性方法:
int read():读取单个字符并返回
int read(char[] ch):一次读取多个字符,将字符存入数组
void close():关闭流并释放资源
注意:Reader是一个抽象类,需要使用子类,重点介绍FileReader
FileReader:文件字符输入流,用于将字符从硬盘文件中的数据以字符的形式读取到内存中。
构造方法:
FlieReader(String filename):创建一个新的 FileReader, 给定要读取的文件的名称。
FilleReader(File file):创建一个新的 FileReader ,给出 File读取。
使用步骤:
1.创建FlieReader对象,并在构造方法中指定数据源。
2.使用read方法进行字符读取。
3.释放资源。
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
public class IoDemo04 {
public static void main(String[] args) throws IOException {
// FileInputStream f = new FileInputStream("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt");
// while(f.read()!=-1){
// System.out.println((char)f.read());//产生乱码
// }
// f.close();
// 1.创建FlieReader对象,并在构造方法中指定数据源
FileReader f = new FileReader("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt");
//2.使用read方法进行字符读取
// int read():读取单个字符并返回
int i1 = f.read();
System.out.println((char)i1);//进行类型转换
//int read(char[] ch):一次读取多个字符,将字符存入数组
char[] ch = new char[100];//存储读取到的数据
int i2 = 0;//记录读取的有效数据
while((f.read(ch)!=-1)){//和字节流一样,文件末尾读取-1
/*
输出可以使用String类的构造方法:
String(char[] value):把字符数组转化为字符串
String(char[] value,int offset,int len):把字符数组从索引offset开始,len长转换为字符串
*/
System.out.print(new String(ch,0,5));
}
//3.释放资源
f.close();
}
}
五、 Writer字符输出流
java.io.Writer抽象类,是所有字符输出流的最顶层父类。
共性的成员方法;
void write(int c) 写入单个字符。
void write(char[] ch)写入字符数组。
void write(String str)写一个字符串。
void write(String str, int off, int len)写一个字符串的一部分。
abstract void write(char[] ch, int off, int len)写一个字符数组的一部分。
void flush()刷新该流的缓冲。
void close():关闭此流,但要先刷新。
注意:Writer是一个抽象类,想要使用必须使用其子类对象,重点介绍FileWriter。
FlieWriter:文件字符输出流,把内存中的数据写入文件。
构造方法:
FileWriter(String fileName)构造一个给定文件名的FileWriter对象。
FileWriter(File file)给一个File对象构造一个FileWriter对象。
使用步骤:
1.创建一个FileWriter对象,在其构造方法中写入数据存储路径。
2.使用FileWriter中的方法write,把数据写入到内存缓冲区(字符转换为字节的过程)。
3.使用flush方法,把内存缓冲区中的数据,刷新到文件中。
4.释放资源。
注意:
flush方法:刷新缓冲区,流对象可以继续使用。
close方法:先刷新缓冲区,再通知系统释放资源,流对象不可再使用。
import java.io.FileWriter;
import java.io.IOException;
public class IoDemo05 {
public static void main(String[] args) throws IOException {
// 1.创建一个FileWriter对象,在其构造方法中写入数据存储路径
FileWriter f = new FileWriter("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt");
// 2.使用FileWriter中的方法write,把数据写入到内存缓冲区(字符转换为字节的过程)
//void write(int c) 写入单个字符
f.write(67);
//3.使用flush方法,把内存缓冲区中的数据,刷新到文件中
f.flush();//C
//释放资源
f.close();//其实释放资源时会先执行flush方法
}
}
FileWriter续写及追击数据的方法:
FileWriter(File file, boolean append)给一个File对象构造一个FileWriter对象。
append:布尔值,如果为true,不会创建新的文件覆盖源文件,如果为false,创建新的文件覆盖源文件。
FileWriter(String fileName, boolean append)构造一个FileWriter对象,给出一个带有布尔值的文件名,表示是否附加写入的数据。
append:布尔值,如果为true,不会创建新的文件覆盖源文件,如果为false,创建新的文件覆盖源文件。
import java.io.FileWriter;
import java.io.IOException;
public class IoDemo06 {
public static void main(String[] args) throws IOException {
FileWriter f = new FileWriter("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt",true);
f.write("呵呵");
//f.flush();
f.close();
}
}
五、IO异常的处理
IO异常的处理,使用try-catch-finally来进行处理。
在JDK1.7之前IO异常的处理
格式:
try
{可能出现异常的代码}
catch(异常对象 变量名){
异常的处理逻辑
}finally{
一定会执行的代码,也就是资源释放
}
在JDK1.7后增加了新特性,在try后面加上一个小括号,里面可以定义流对象,try中代码执行完毕,会自动把资源进行释放,不用再写finally。
格式:
try(定义流对象){//可以定义多个流对象,之间用逗号隔开
可能产生异常的代码
}catch(异常类变量 变量名){
异常的处理逻辑
}
在JDK1.9以后又增加了新特性,try的前面可以定义流对象,在try的后面括号可以直接引入流对象的名称(变量名)在try代码执行完毕之后流对象也可以释放掉,不用写finally。
A a new = A();
B b new = B();
try(a,b)
{
可能出现异常的代码
}
catch(异常对象 变量名){
异常的处理逻辑
}
import java.io.FileWriter;
import java.io.IOException;
public class IoDemo07 {
public static void main(String[] args) {
FileWriter f = null;
try{
//可能出现异常的代码
f = new FileWriter("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt");
f.write("呵呵");
}catch(IOException e){
//异常的处理逻辑
System.out.println(e);
}finally{
try {
f.close();//因为局部变量的作用域只在最近的大括号才能生效,因此需要提高定义范围
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//JDK1.7后增加了新特性
try(FileWriter f1 = new FileWriter("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt");
FileWriter f2 = new FileWriter("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt");
){
f1.write("哈哈");
f2.write("哈哈");
}catch(IOException e){
System.out.println(e);
}
}
}
六、Properties集合
java.util.Properties extends Hashtable<K,V> implements Map<K,V>, Properties(双列集合)是唯一一个与IO流相结合的集合,表示一组持久的属性。 Properties可以保存到流中或从流中加载。属性列表中的每个键及其对应的值都是一个字符串(key和value默认都是字符串)。
Properties中特有方法:
将集合中的数据(临时数据),存储到硬盘中(持久化数据)。
void store(OutputStream out, String comments) 将此属性列表(键和元素对)写入此 Properties表中,以适合于使用load(InputStream)方法加载到 Properties表中的格式输出流。
OutputStream out:字节输出流,不能写入中文
comments:注释,用来解释说明文档,不能使用中文,默认为Unicode编码一般使用空字符串""。
void store(Writer writer, String comments)将此属性列表(键和元素对)写入此 Properties表中,以适合使用 load(Reader)方法的格式输出到输出字符流。
Writer writer:字节输入流,能写入中文。
comments:注释,用来解释说明文档,不能使用中文,默认为Unicode编码一般使用空字符串""。
将硬盘中保存的文件(键值对组成的)读取到集合中进行使用:
void load(InputStream inStream)从输入字节流读取属性列表(键和元素对)。
InputStream inStream:字节输入流,不能读取中文字符的键值对。
void load(Reader reader)以简单的线性格式从输入字符流读取属性列表(关键字和元素对)。
Reader reader:字符输入流,能读取含有中文的键值对
其它常用方法:
Object setProperty(String key, String value)相当于 Hashtable中方法 put。
String getProperty(String key)通过key找到对应的value值,相当于Map中的get方法。
Set stringPropertyNames()返回此属性列表中的一组键,其中键及其对应的值为字符串,相当于Map集合中keySet方法。
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
import java.util.Set;
public class IoDemo08 {
public static void main(String[] args) throws IOException {
//不需要指定泛型,默认都是字符串
Properties pr = new Properties();
//Object setProperty(String key, String value)相当于 Hashtable中方法 put
pr.setProperty("唐三藏", "唐僧");
pr.setProperty("孙行者", "孙悟空");
pr.setProperty("天蓬元帅", "猪八戒");
//key和value都是字符串,不能是其它类型
//pr.setProperty(1, 1);
//String getProperty(String key)通过key找到对应的value值,相当于Map中的get方法
String value = pr.getProperty("孙行者");
System.out.println(value);//输出结果:孙悟空
//Set<String> stringPropertyNames()返回此属性列表中的一组键,其中键及其对应的值为字符串,相当于Map集合中keySet方法
Set<String> names = pr.stringPropertyNames();
for(String key:names){
System.out.print(key+"="+pr.getProperty(key)+" ");//输出结果:天蓬元帅=猪八戒 唐三藏=唐僧 孙行者=孙悟空
}
/*
void store(OutputStream out, String comments)
void store(Writer writer, String comments)
使用步骤:
1.创建Properties集合,并完成添加数据
2.创建一个OutputStream流对象/Writer流对象,在构造方法中指定输出路径
3.调用Properties中store方法,进行输出
4.释放资源
*/
// 1.创建Properties集合,并完成添加数据
Properties pr1 = new Properties();
//Object setProperty(String key, String value)相当于 Hashtable中方法 put
pr1.setProperty("唐三藏", "唐僧");
pr1.setProperty("孙行者", "孙悟空");
pr1.setProperty("天蓬元帅", "猪八戒");
// 2.创建一个OutputStream流对象/Writer流对象,在构造方法中指定输出路径
//OutputStream流对象
FileOutputStream out = new FileOutputStream("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt");
//Writer流对象
FileWriter writer = new FileWriter("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt");
//3.调用Properties中store方法,进行输出
// OutputStream out:字节输出流,不能写入中文,会产生乱码
//pr1.store(out,"storage");
/* #storage
#Mon Feb 08 10:34:31 CST 2021
\u5929\u84EC\u5143\u5E05=\u732A\u516B\u6212
\u5510\u4E09\u85CF=\u5510\u50E7
\u5B59\u884C\u8005=\u5B59\u609F\u7A7A*/
//Writer writer:字节输入流,能写入中文
pr1.store(writer, "storage");
/* #storage
#Mon Feb 08 10:31:33 CST 2021 //时间是默认加的
天蓬元帅=猪八戒
唐三藏=唐僧
孙行者=孙悟空*/
// 4.释放资源
out.close();
writer.close();
System.out.println();
/*
void load(InputStream inStream)从输入字节流读取属性列表(键和元素对)。
void load(Reader reader)以简单的线性格式从输入字符流读取属性列表(关键字和元素对)
使用步骤:
1.创建一个Properties集合
2.创建InputStream/Reader流对象,在构造方法中指定读取路径(可以使用匿名内部类)
3.调用Properties集合中load方法读取保存键值对的文件
4.遍历Properties集合
4.释放资源
注意:
1.存储键值对的文件,键与值连接符可以自己定义
2.存储键值对的文件,键与值默认都是字符串,不用再加引号
3.存储键值对的文件,可以使用#号注释,注释的内容不会再被读取
*/
// 1.创建一个Properties集合
Properties pr3 = new Properties();
//2.创建InputStream/Reader流对象,在构造方法中指定读取路径
//InputStream流对象
FileInputStream in = new FileInputStream("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt");
//Reader流对象
FileReader fr = new FileReader("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt");
// 3.调用Properties集合中load方法
// pr3.load(in);
pr3.load(fr);
// 4.遍历Properties集合
//InputStream流对象不能读取中文键值对,会产生乱码
// Set<String> set = pr3.stringPropertyNames();
// for(String key:set){
// System.out.println(key+"="+); /* ??????=孙悟空
// ?ì?????§=唐僧
// ??????=猪八戒*/
// }
//Reader流对象能读取中文键值对
Set<String> set = pr3.stringPropertyNames();
for(String key:set){
System.out.println(key+"="+pr3.getProperty(key));
/*天蓬元帅=猪八戒
唐三藏=唐僧
孙行者=孙悟空*/
}
}
}
七、缓冲流概述
缓冲流:增强基本流的功能,在基本流的基础上演变而来。
按照数据类型进行分类分为:
字节缓冲流:BufferedInputStrem BufferedOutputStream
字符缓冲流:BufferedReader BufferedWriter
缓冲流的基本原理:是在创建流对象时会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统的IO次数,提高读写的效率。
八、字节缓冲输出流BufferedOutputStream
字节缓冲输出流构造方法:
BufferedOutputStream(OutputStream out):创建一个新的缓冲输出流。
OutputStream out:字节输出流对象
BufferedOutputStream(OutputStream out, int size)创建一个新的缓冲输出流,以便以指定的缓冲区大小将数据写入指定的底层输出流。
OutputStream out;字节输出流对象
int size:指定字节缓冲区大小,不指定使用默认值
其它常用成员方法可以使用父类OutputStream中常用方法:
public void close():关闭此输出流并释放与此流相关联的任何系统资源。
public void flush():刷新此输出流并强制任何缓冲的输出字节流。
public void write(byte[] b):将b.lengh字节从指定的字节数组写入输出流。一次性写入多个字节,如果写的第一个字节是正数(0-127),显示的时候会查询ASCII表,如果写的第一个字节是负数 ,那么第一个字节会和第二个字节,两个字节组成一个中文显示,查询系统默认编码表(简体中文是GBK)。
public void write(byte[] b,int off,int len):从指定的字节数组写入len字节,从偏移量off(开始的索引)开始输出到此输出流。
public void write(int b):将指定的字节写入输出流。
使用方法:
1.创建一个FileoutputStream对象,指定数据输出路径。
2.创建一个BufferedOutputStream对象,构造方法中传递FileoutputStream对象,和指定缓冲区大小,不指定则使用默认值。
3.调用BufferedOutputStream对象的write方法,把数据写入到缓冲区中。
4.使用BufferedOutputStream对象的flush方法,将缓冲区中的数据刷新到指定路径的文件中去。
5.释放资源,在调用close方法之前,其实会先调用flush方法,将数据刷新到文件中去,所以第4步可选择性省略。
import java.io.BufferedOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class IoDemo09 {
public static void main(String[] args) throws IOException {
//1.创建一个FileoutputStream对象,指定数据输出路径
FileOutputStream out = new FileOutputStream("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt");
//2.创建一个BufferedOutputStream对象,构造方法中传递FileoutputStream对象,和指定缓冲区大小,不指定则使用默认值
BufferedOutputStream bout = new BufferedOutputStream(out,100);
//3.调用BufferedOutputStream对象的write方法,把数据写入到缓冲区中
//写入单个数据
// bout.write(97);//a
//写入一个字节数组
byte[] bytes = {98,99,97};
bout.write(bytes);//bca
//写入一个字节数组的指定长度部分
// bout.write(bytes, 0, 1);//a
// 4.使用BufferedOutputStream对象的flush方法,将缓冲区中的数据刷新到指定路径的文件中去
bout.flush();
//5.释放资源,在调用close方法之前,其实会先调用flush方法,将数据刷新到文件中去,所以第4步可选择性省略
out.close();
bout.close();
}
}
九、字节缓冲输入流BufferedInputStream
构造方法:
BufferedInputStream(InputStream in)创建一个BufferedInputStream并保存其参数,输入流 in ,供以后使用。
InputStream in;字节输入流对象
BufferedInputStream(InputStream in, int size)创建 BufferedInputStream具有指定缓冲区大小,并保存其参数,输入流 in ,供以后使用。
InputStream out;字节输入流对象
int size:指定字节缓冲区大小,不指定使用默认值
常用方法继承自父类InputStream:
int read():从输入流中读取数据的下一个字节,读取到文件末尾返回-1。
int read(byte[] b):从输入流中读取一定数量的字节,并将其存入缓冲区数组b中。
void close():关闭此输入流并释放有关的所有系统资源。
使用步骤:
1.创建一个InputStream流对象,构造方法中指定读取的路径或者文件。
2.创建BufferedInputStream对象,构造方法中传入InputStream流对象,可以指定大小,也可以不写,使用默认值。
3.调用BufferedInputSteram的read方法,进行文件的读取。
4.释放资源。
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class IoDemo10 {
public static void main(String[] args) throws IOException {
// 1.创建一个InputStream流对象,构造方法中指定读取的路径或者文件
FileInputStream f = new FileInputStream("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt");
//2.创建BufferedInputStream对象,构造方法中传入InputStream流对象,可以指定大小,也可以不写,使用默认值
BufferedInputStream bf = new BufferedInputStream(f);
//3.调用BufferedInputSteram的read方法,进行文件的读取
byte[] bytes = new byte[100];//定义存储数据
while(f.read(bytes)!=-1){//和InputStream一样,读取文件末尾为-1
System.out.print(new String(bytes,0,3));//bca
}
// 4.释放资源
bf.close();
}
}
十、字符缓冲输出流BufferedWriter
构造方法:
BufferedWriter(Writer out)创建使用默认大小的输出缓冲区的缓冲字符输出流。
Writer out;字符输出流对象。
BufferedWriter(Writer out, int size)创建一个新的缓冲字符输出流,使用给定大小的输出缓冲区。
Writer out;字符输出流对象。
int size:指定字节缓冲区大小,不指定使用默认值。
特有操作方法:
void newLine()写一行行分隔符,会根据不同的操作系统获取不同的行分隔符。
其它常用操作方法继承自父类Writer:
void write(int c) 写入单个字符
void write(char[] ch)写入字符数组
void write(String str)写一个字符串
void write(String str, int off, int len)写一个字符串的一部分
abstract void write(char[] ch, int off, int len)写一个字符数组的一部分。
void flush()刷新该流的缓冲
void close():关闭此流,但要先刷新
使用步骤:
1.创建一个FileWriter流对象,构造方法中指定数据输出路径。
2.创建一个BufferedWriter对象,构造方法中传递Writer流对象,根据需要指定缓冲区大小,可以不指定大小,使用默认值。
3.调用BufferedWriter对象中的write方法,进行数据写入到内存缓冲区。
4.使用BufferedWriter中的方法flush,将内存缓冲区中的数据刷新到文件中。
5.释放资源。
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
public class IoDemo11 {
public static void main(String[] args) throws IOException {
//1.创建一个FileWriter流对象,构造方法中指定数据输出路径
FileWriter f = new FileWriter("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt");
// 2.创建一个BufferedWriter对象,构造方法中传递Writer流对象,根据需要指定缓冲区大小,可以不指定大小,使用默认值
BufferedWriter bw = new BufferedWriter(f);
// 3.调用BufferedWriter对象中的write方法,进行数据写入到内存缓冲区
// void write(int c) 写入单个字符
bw.write(99);//c
// void write(char[] ch)写入字符数组
char[] ch={'a','b','c'};
bw.write(ch);//abc
//void newLine()写一行行分隔符,会根据不同的操作系统获取不同的行分隔符
bw.newLine();
//void write(String str)写一个字符串
bw.write("哈哈");//哈哈
// void write(String str, int off, int len)写一个字符串的一部分
String str = "hello";
bw.write(str,0,3);//hel
// 4.使用BufferedWriter中的方法flush,将内存缓冲区中的数据刷新到文件中
bw.flush();
//5.释放资源
bw.close();
}
}
十一、字符缓冲输入流BufferedReader
构造方法:
BufferedReader(Reader in)创建使用默认大小的输入缓冲区的缓冲字符输入流。
BufferedReader(Reader in, int size)创建使用指定大小的输入缓冲区的缓冲字符输入流。
特有操作方法:
String readLine()读一行文字(读一行文字。 一行被视为由换行符(’\ n’),回车符(’\ r’)中的任何一个或随后的换行符终止)。
返回值:包含行的内容的字符串,不包括任何行终止字符,如果已达到流的末尾,则为null。
常用操作其它方法继承自父类Reader:
int read():读取单个字符并返回。
int read(char[] ch):一次读取多个字符,将字符存入数组。
void close():关闭流并释放资源。
使用步骤:
1.创建一个FileReader流对象,构造方法中传递读取的文件路径。
2.创建BuffedReader对象,构造方法中传递FileReader流对象,并可以指定缓冲区大小,也可不指定,使用默认大小。
3.调用BufferedReader中的read/readLine方法,进行文本读取。
4.释放资源。
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class IoDemo12 {
public static void main(String[] args) throws IOException {
// 1.创建一个FileReader流对象,构造方法中传递读取的文件路径
FileReader f = new FileReader("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt");
//2.创建BuffedReader对象,构造方法中传递FileReader流对象,并可以指定缓冲区大小,也可不指定,使用默认大小
BufferedReader br = new BufferedReader(f);
//3.调用BufferedReader中的read/readLine方法,进行文本读取
int a = br.read();
String str = br.readLine();
System.out.println((char)a);//输出结果:c
System.out.println(str);//输出结果:abc
// 4.释放资源
br.close();
}
}
十二、转换流OutputStreamWriter
OutputStreamWriter:是字符流转换成字节流的通道,可使用指定的charset将写入流中的字符编码成字节。
如果使用不同的编码表进行文件的读取和写入,会出现乱码,如eclipse系统默认为GBK,如果读取UTF-8文件就会出错。Java中提供了转换流来进行不同编码表的转换,为OutputStreamWriter和InputStreamReader。
构造方法:
OutputStreamWriter(OutputStream out)创建一个使用默认字符编码的OutputStreamWriter。
OutputStream out:字节流对象。
OutputStreamWriter(OutputStream out, String charsetName)创建一个使用命名字符集的OutputStreamWriter。
OutputStream out:字节流对象
charsetName:指定字符集名称,不区分大小写
其他常用方法继承自父类Writer:
void write(int c) 写入单个字符。
void write(char[] ch)写入字符数组。
void write(String str)写一个字符串。
void write(String str, int off, int len)写一个字符串的一部分。
abstract void write(char[] ch, int off, int len)写一个字符数组的一部分。
void flush()刷新该流的缓冲。
void close():关闭此流,但要先刷新。
使用步骤:
1.创建一个FileOutputStream对象,构造方法中指定输出数据的文件或路径。
2.创建 OutputStreamWriter,构造方法中传递为OutputStream对象和指定编码表名称。
3.使用 OutputStreamWriter对象中的write方法,把字符转换为为字节存出到缓冲区中。
4.使用 OutputStreamWriter中flush方法,将数据刷新到文件中
5.释放资源。
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
public class IoDemo13 {
public static void main(String[] args) throws IOException {
//1.创建一个OutputStream对象,构造方法中指定输出数据的文件或路径
FileOutputStream out = new FileOutputStream("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt");
// 2.创建 OutputStreamWriter,构造方法中传递为OutputStream对象和指定编码表名称,不写默认GBK
OutputStreamWriter outwriter1 = new OutputStreamWriter(out,"GBK");
OutputStreamWriter outwriter2 = new OutputStreamWriter(out,"utf-8");
//3.使用 OutputStreamWriter对象中的write方法,把字符转换为为字节存出到缓冲区中
outwriter1.write("你好");//你好
outwriter2.write("你好");//浣犲ソ utf-8出现乱码
//4.使用 OutputStreamWriter中flush方法,将数据刷新到文件中
outwriter1.flush();
outwriter2.flush();
// 5.释放资源
outwriter1.close();
outwriter2.close();
}
}
十三、转换流InputStreamReader
InputStreamReader:是从字节流到字符流的桥:它读取字节,并使用指定的charset将其解码为字符 。它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集。
构造方法:
InputStreamReader(InputStream in)创建一个使用默认字符集的InputStreamReader。
InputStream in:字节输入流
InputStreamReader(InputStream in, String charsetName)创建一个使用命名字符集的InputStreamReader。
InputStream in:字节输入流
String charsetName:指定字符集,不区分大小写
其他常用方法继承自父类Reader:
int read():读取单个字符并返回。
int read(char[] ch):一次读取多个字符,将字符存入数组。
void close():关闭流并释放资源。
使用步骤:
1.创建一个FileInputStream流对象,构造方法中指定读取文件或者文件路径。
2.创建InputStreamReader,构造方法中传递FileInputStream流对象,并指定字符集,不指定则使用默认字符集。
3.调用InputStreamReader中read方法,进行文件读取。
4.释放资源。
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
public class IoDemo14 {
public static void main(String[] args) throws IOException {
// 1.创建一个FileInputStream流对象,构造方法中指定读取文件或者文件路径
FileInputStream f = new FileInputStream("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt");
//2.创建InputStreamReader,构造方法中传递FileInputStream流对象,并指定字符集,不指定则使用默认字符集
InputStreamReader i1 = new InputStreamReader(f,"GBK");
InputStreamReader i2 = new InputStreamReader(f,"utf-8");
// 3.调用InputStreamReader中read方法,进行文件读取,文件内容为”你好“
int len = 0;//记录有效数据个数
// while((len=i1.read())!=-1){//文件末尾为-1
// System.out.print((char)len);//输出结果:你好
// }
while((len=i2.read())!=-1){
System.out.print((char)len);//输出结果:???
}
//4.释放资源
//i1.close();
i2.close();
}
}
十三、序列化
序列化和反序列化:
Java提供了一种对象序列化机制,用一个字节序列可以表示一个对象,该字节序列表示该对象的数据、对象的类型和对象中存储属性等该字节序列还可以从文件中读取回来,重构对象,对其进行反序列化。
字节----ObjectOutputStream(序列化-对象转换为字节)—>对象
字节<----ObjectInputStream(反序列化-字节重构对象)—>对象
序列化:把对象以流的方式,写入到文件中保存。
反序列化:把文件以流的形式读取出来。
ObjectOutputStream:对象的序列化流,把对象以流的方式写入到文件中保存。
ObjectOutputStream(OutputStream out)创建一个写入指定的OutputStream的ObjectOutputStream
特有成员方法:
void writeObject(Object obj)将指定的对象写入ObjectOutputStream
注意:
序列化与反序列化时候,会抛出NotSerializableException(没有序列化异常),可以通过将类在定义时实现java.io.Serializable接口
以启用序列化和反序列化功能,未实现此接口的类将无法进行序列化及反序列化 ,Serializable接口为标记性接口,其中没有任何抽象方法,只是在进行序列化和反序列化时检测类上是否有这个标记,有就可以进行序列化及反序列化,没有则不可进行序列化及反序列化抛出NotSerializableException(没有序列化异常)。
使用步骤:
1.创建一个类,实现Serializable接口,并将其实例化
2.创建一个FileOutputStream对象,构造方法中指定输出文件或路径。
3.创建ObjectOutputStream对象,构造方法中传递OutputStream对象。
4.调用writeObject方法,将对象传入。
5.释放资源。
序列化前提:
1.类必须实现Serializable接口,不实现此接口的类将不会使任何状态序列化或反序列化。
2.该类所有属性必须使可序列化的,如果有一个属性不需要可序列化,则该属性必须标明使注明是瞬态的,即用transient关键字修饰。
static关键字:静态关键字
静态关键字优先于非静态关键字加载到内存中,被static关键字修饰的成员变量是不能被序列化的,序列化的都是对象。
transient关键字:瞬态关键字
被transient关键字修饰的成员变量不能被序列化。
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class IoDemo15 {
public static void main(String[] args) throws IOException {
//序列化
//1.创建一个自定义对象,并将其实例化
Student p = new Student("张三", 19);
//2.创建一个OutputStream对象,构造方法中指定输出文件或路径
FileOutputStream f = new FileOutputStream("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt");
// 3.创建ObjectOutputStream对象,构造方法中传递OutputStream对象
ObjectOutputStream oo = new ObjectOutputStream(f);
//4.调用writeObject方法,将对象传入
oo.writeObject(p);//进行序列化后结果 sr
// io.Student/[掆?? I ageL stuNamet Ljava/lang/String;xp t 寮犱笁
//5.释放资源
oo.close();
}
}
class Student implements Serializable{
// 强烈建议所有可序列化的类都明确声明serialVersionUID值,因为默认的serialVersionUID计算对类详细信息非常敏感
static final long serialVersionUID = 666L;
private String stuName;
private /*transient*/ int age;
public Student(String stuName, int age) {
super();
this.stuName = stuName;
this.age = age;
}
public Student() {
super();
}
public String getStuName() {
return stuName;
}
public void setStuName(String stuName) {
this.stuName = stuName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student [stuName=" + stuName + ", age=" + age + "]";
}
}
十四、反序列化
ObjectInputStream:对象的反序列化流,把文件中保存的对象,以流的方式进行读取。
构造方法;
ObjectInputStream(InputStream in)创建从指定的InputStream读取的ObjectInputStream。
特有的成员方法:
Object readObject()从ObjectInputStream读取一个对象声明抛出了ClassNotFoundException(class文件找不到异常),当不存在对象的class文件时抛出此异常。
使用步骤:
1.创建一个FileInputStream对象,构造方法中传递读取的文件路径或文件
2.创建ObjectInputStream,构造方法中传递FileInputStream对象。
3.调用ObjectInputStream中readObject()方法,读取保存对象的文件。
4.释放资源。
5.打印读出的对象。
反序列化的前提:
1.所要存储的的类对象,类必须实现Serializable接口。
2.必须存在类对应的class文件 。
注意:
当JVM反序列化对象时,能找到class文件,但是class文件在序列化对象时发生了修改,那么反序列化操作也会失败。抛出InvalidClassException。
发生异常的原因:
1.该类的序列版本号与从流中读取的类描述符的版本号不匹配。
2.该类包含未知数据类型。
3.该类没有可访问的无参构造方法。
Serializable接口给需要序列化的类,提供了一个版本序列号,serialVersion该版本号的目的在于验证序列化的对象和对应列是否和对应类匹配 。
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
public class IoDemo16 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
// 反序列化
// 1.创建一个FileInputStream对象,构造方法中传递读取的文件路径或文件
FileInputStream fi = new FileInputStream("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt");
// 2.创建ObjectInputStream,构造方法中传递FileInputStream对象
ObjectInputStream oi = new ObjectInputStream(fi);
// 3.调用ObjectInputStream中readObject()方法,读取保存对象的文件
Object obj = oi.readObject();
// 4.释放资源
oi.close();
// 5.打印读出的对象
System.out.println(obj);// 输出结果:Student [stuName=张三, age=19]
//transeint关键字修饰后输出结果;Student [stuName=张三, age=0]
//将age的修饰符改为public后报错: serialVersionUID = -8505643103320664334, local class serialVersionUID = 2790456493892586949
}
}
十五、打印流
打印流:
java.io.PrintStream:打印流,为另一个输出流添加了功能,即能够方便地打印各种数据值的表示。
PrintStream流特点:
1.只负责输出,不进行输入
2.与其他输出流不同, PrintStream从不抛出IOException相反,异常情况只是设置一个可以通过checkError方法测试的内部标志。
特有方法:
void print(任意类型的数据)
void println(任意类型数据并换行)
构造方法:
PrintStream(File file)使用指定的文件创建一个新的打印流,而不需要自动换行(输出到一个文件)
PrintStream(OutputStream out)创建一个新的打印流(输出到一个流)
PrintStream(String fileName)使用指定的文件名创建新的打印流,无需自动换行(输出到一个文件路径)
PrintStream继承了OutputStream,因此可以使用父类成员方法:
注意:
如果使用父类成员方法write写数据,则查看数据时会查询编码表
如果使用自身特有方法print/println,则写数据时原样输出
使用步骤:
1.创建一个PrintStream对象,构造方法中添加数据输出路径(会抛出FileNotFoundException)
2.调用父类write方法/自身特有方法,写入数据
3.释放资源
可以改变输出语句的目的地,输出语句,默认在控制台打印,使用System.setOut方法改变输出语句的目的地改为参数传递的打印流的目的地.
static void setOut(PrintStream out)重新分配“标准”输出流重新分配“标准”输出流。
import java.io.FileNotFoundException;
import java.io.PrintStream;
public class IoDemo18 {
public static void main(String[] args) throws FileNotFoundException {
//1.创建一个PrintStream对象,构造方法中添加数据输出路径
PrintStream ps = new PrintStream("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt");
// 2.调用父类write方法/自身特有方法,写入数据
//调用父类write方法
ps.write(101);//e
//自身特有方法
ps.print(101);//101
//3.释放资源
ps.close();
//static void setOut(PrintStream out)
System.out.println("呵呵");//控制台输出
PrintStream p = new PrintStream("D:\\eclipse\\eclipse\\example\\study\\io\\1.txt");
System.setOut(p);
System.out.println("呵呵在1.txt中输出");//文件中输出
p.close();
}
}