IO流学习笔记
1.文件的基础知识
(1)从编程的角度讲,文件就是保存数据的地方,比如:文字、文档、视频、音频、图片等。
(2)创造文件的相关方法
new File(String pathname)//根据路径构建一个文件
new File(File parent ,String child)//根据父目录文件+子路径构建
new File(Sting parent ,String child)//根据父目录+子路径构建
2.io流原理及流的分类
(1)流的分类:
按照操作数据单位不同分为:字节流(8bit),字符流
按照流的流向不同分为:输入流、输出流
按照流的角色不同分为:节点流、处理流
(2)四大抽象基类:(所有流的抽象父类,除任意流外)
InputStream,OutputStream,Reader,Writer
我们在使用时,要使用他们的派生子类
4个文件流:
FileInputStream,FileOutputStream,FileReader,FileWriter
4个缓冲流:
BufferedInputStream,BufferedOutputStream,BufferedReader,BufferedWriter
2个转换流
InputStreamReader
OutputStreamWriter
2个打印流
PrintStream
PrintWriter
3.FileInputStream
read()方法当读取完数据后,返回-1
@Test
public void read01() throws Exception {
int read = 0;
FileInputStream fileInputStream = new FileInputStream("d:/new4.txt");
while ((read = fileInputStream.read()) != -1) {
System.out.print((char) read);
}
fileInputStream.close();
}
优化使用字节数组,提高效率,如果读取正常,返回值是实际读到的字节数,如果是8个字节,最后可能不足8个字节,最后返回-1
@Test
public void read03() throws Exception {
int readLen = 0;
byte[] buf = new byte[8];//一次读取8个字节
FileInputStream fileInputStream = new FileInputStream("d:/new4.txt");
while ((readLen = fileInputStream.read(buf)) != -1) {
System.out.print(new String(buf, 0, readLen));
}
if (fileInputStream != null) {
fileInputStream.close();
}
}
4.FileOutputStream
write()方法可以读int类型的,也可以读byte[];
@Test
public void out01() throws Exception {
FileOutputStream fileOutputStream = new FileOutputStream("d:/news5.txt");
String s= "Hello,World!";
fileOutputStream.write(s.getBytes());//字符串转字符数组
fileOutputStream.close();
}
当写入内容时,会覆盖原来的内容,如果想要追加内容,在创建时,加一个true
5.练习:文件拷贝
文件可以是图片、音频等,在完成程序时,应该是读取部分数据就写入到指定文件,使用循环
@Test
public void copy01() throws Exception {
FileInputStream fileInputStream = new FileInputStream("d:/zhangwen3.jpg");
FileOutputStream fileOutputStream = new FileOutputStream("d:/zhangwen4.jpg");
byte[] buf = new byte[1024];//减少读取次数,提高效率
int redLen = 0;
while ((redLen = fileInputStream.read(buf)) != -1) {
//读取到后就写入文件,即边读边写
fileOutputStream.write(buf, 0, redLen);
}
if (fileInputStream != null) {
fileInputStream.close();
}
if (fileOutputStream != null) {
fileOutputStream.close();
}
}
6. FileReader
单个字符读取
@Test
public void read1() throws Exception {
//单个字符读取
FileReader fileReader = new FileReader("d:/news6.txt");
int data = 0;
while ((data = fileReader.read())!=-1){
System.out.print((char)data);
}
if(fileReader!=null){
fileReader.close();
}
}
优化:使用字符数组读取
@Test
public void read2() throws Exception {
//单个字符读取
FileReader fileReader = new FileReader("d:/news6.txt");
char[] chars = new char[8];
int readLen = 0;
while ((readLen = fileReader.read(chars))!=-1){
System.out.print(new String(chars,0,readLen));
}
if(fileReader!=null){
fileReader.close();
}
}
7.FileWriter
注意:FileWriter使用过后要关闭(close)或者刷新(falsh),否则写入不到指定文件
@Test
public void write01() throws Exception{
char[] chars ={'a','b','c'};
//写入单个字符
FileWriter fileWriter = new FileWriter("d:/news7.txt",true);
fileWriter.write('H');
fileWriter.write(chars);
if(fileWriter!=null){
fileWriter.close();
}
}
在数据量大的情况下,也可以使用循环
8.节点流和处理流
节点流:节点流可以从一个特定的数据源读写数据,如:FileReader,FileWriter
处理流(也叫包装流):是连接在已存在的流(节点流或者处理流)之上,为程序提供更为强大的读写功能,如BufferedReader,BufferedWriter
处理流的功能主要体现以下两个方面:
1.性能的提高:主要以增加缓冲的方式来提高输入输出的效率
2.操作的便携:处理流可能提供了一系列便携的方法来一次输入输出大批量的数据,使用更加灵活方便
9.BufferedReader
public class exercise01 {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new FileReader("d:/news8.txt"));
String s = "";
while ((s = br.readLine()) != null) {
System.out.println(s);
}
if (br != null) {
br.close();
}
}
}
10.BufferedWriter
public class exercise01 {
public static void main(String[] args) throws Exception {
BufferedWriter bw = new BufferedWriter(new FileWriter("d:/news9.txt"));
bw.write("你好,尚学堂!");
bw.write("你好,oldlu");
bw.newLine();
bw.write("何以解忧,");
bw.newLine();
bw.write("唯有杜康。");
if (bw != null){
bw.close();
}
}
}
11.练习:使用字符缓冲流,实现文件拷贝
优化:为文档添加行号
public static void main(String[] args) {
BufferedReader br = null;
BufferedWriter bw = null;
try {
br = new BufferedReader(new FileReader("d:/news9.txt"));
bw = new BufferedWriter(new FileWriter("d:/news10.txt"));
String temp = "";
int i = 1;
while ((temp = br.readLine()) != null){
bw.write(i+temp);
bw.newLine();
i++;
}
bw.flush();
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
if(br!=null){
br.close();
}
if(bw!=null){
bw.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
12.练习:使用字节缓冲流,实现文件拷贝
@Test
public void copy01(){
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
bis = new BufferedInputStream(new FileInputStream("d:/zhangwen4.jpg"));
bos = new BufferedOutputStream(new FileOutputStream("d:/zhangwen5.jpg"));
byte[] bytes = new byte[1024];
int readLen=0;
while((readLen=bis.read(bytes))!=-1){
bos.write(bytes,0,readLen);
}
bos.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(bis!=null){
bis.close();
}
if(bos!=null){
bos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
13.转换流
当我们需要整行读取字节流时,将字节流转换成字符流就解决了,指定编码方式,能解决乱码问题
需要注意的是,在使用转换流时,只能针对操作文本文件的字节流进行转换,如果字节流操作的是一张图片,此时转换为字符流就会造成数据丢失。
InputStreamReader
@Test
public void exercise01() throws Exception{
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("d:/news10.txt")));
String s = "";
while((s=br.readLine())!=null){
System.out.println(s);
}
if(br!=null){
br.close();
}
}
OutputStreamWriter
@Test
public void exercise02() throws Exception{
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("d:/news11.txt")));
bw.write("hi,韩顺平教育");
if(bw!=null){
bw.close();
}
}
14.打印流
打印流只有输出流,没有输入流
字节打印流:PrintStream
@Test
public void exercise03() throws FileNotFoundException {
PrintStream printStream = new PrintStream(new FileOutputStream("d:/news12.txt"));
printStream.println("韩顺平教育!");
if(printStream!=null){
printStream.close;
}
}
字符打印流:PrintWriter
@Test
public void exercise04() throws Exception{
PrintWriter printWriter = new PrintWriter(new FileWriter("d:/news13.txt"));
printWriter.println("hi,韩顺平教育!");
printWriter.flush();
if(printWriter!=null){
printWriter.close();
}
}
15.对象流
将Dog对象的保存为值和数据类型,称为“序列化”。
将文件中的数据(值和数据类型)重新恢复成Dog对象,称为“反序列化”。
需要让对象可以序列化和反序列化,满足下列条件之一即可:
1.实现Serializable//这是一个标记接口,里面没有任何的方法
2.实现Externalizable//该接口要实现方法,因此推荐使用第一种
注意:对象流仍然是处理流
ObjectInputStream
反序列化,需要按照序列化时的顺序读入
public class ObjectInputStream01 {
public static void main(String[] args) throws Exception{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:/news13.dat"));
System.out.println(ois.readInt());
System.out.println(ois.readBoolean());
System.out.println(ois.readChar());
System.out.println(ois.readDouble());
System.out.println(ois.readUTF());
Object o = ois.readObject();
System.out.println("运行类型="+o.getClass());
System.out.println("dog的信息="+o);
ois.close();
}
}
如果我们要用对象的方法,先将该类的定义引入,再向下转型,就可以使用了
ObjectOutputStream
序列化
public class ObjectOutStream01 {
public static void main(String[] args) throws Exception{
//序列化后,保存的文件格式,不是纯文本形式,而是按照它的格式来保存
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("d:/news13.dat"));
//序列化数据到d:/news13.dat
//自动装箱
oos.writeInt(100);//int ->Interger实现了Serializable
oos.writeChar('a');//char->Char实现了Serializable
oos.writeBoolean(true);//boolean->Boolean实现了Serializable
oos.writeDouble(7.1);//double->Double实现了Serializable
oos.writeUTF("韩顺平教育");//String
//保存一个Dog对象
oos.writeObject(new Dog("旺财",8));
oos.close();
System.out.println("数据保存完毕(序列化形式)");
}
}
class Dog implements Serializable {
private String name;
private int age;
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
}