Java基础学习——Java流(二)FileReader和FileWriter、FileInputStream和FileOutputStream

文本文件(.txt、.java、.c、.cpp)-------字符流(FileReader、FileWriter)

非文本文件(.jpg、.mp3、.mp4、.doc、.ppt)------字节流(FileInputStream、FileOutputStream)

一、FileReader

1.每次读取一个字符,循环读取文件中的字符

import java.io.File;
import java.io.FileReader;
import java.io.IOException;

public class Demo02 {
    public static void main(String[] args) throws IOException {
        //利用FileReader读取文件:d:\test.txt “abc老师”
        //1.将文件封装为File类的对象
        File file = new File("d:"+File.separator+"javatest"+File.separator+"test.txt");
        //2.创建FileReader流的对象,传入file文件
        FileReader fr = new FileReader(file);   //异常先在方法上抛出
        //3.读取文件中的数据:利用read()方法,返回的是int类型,于是使用int类型接收

        //1)一个一个字符读取
        /*int n = fr.read();
        //System.out.println(n);  //97,读取到的是第一个字符a的ascii码
        //由于read()一次只能读取一个字符,所以需要循环读取,当读到文件结尾没有字符可以读取时,会返回-1
        while (n!=-1){
            System.out.println(n);
            n = fr.read();
        }*/

        //上面的循环读取更简洁的代码写法,将n=fr.read()写在while循环中
        int n;
        while ((n=fr.read())!=-1){
            System.out.println(n);
        }
    }
}

2.每次读取多个字符,循环读取文件中的字符(缓冲数组)

import java.io.File;
import java.io.FileReader;
import java.io.IOException;

public class Demo02 {
    public static void main(String[] args) throws IOException {
        //利用FileReader读取文件:d:\test.txt “abc老师”
        //1.将文件封装为File类的对象
        File file = new File("d:"+File.separator+"javatest"+File.separator+"test.txt");
        //2.创建FileReader流的对象,传入file文件
        FileReader fr = new FileReader(file);   //异常先在方法上抛出
        //3.读取文件中的数据:利用read()方法,返回的是int类型,于是使用int类型接收

       //2)利用缓冲数组,多个字符一起读取,这里一次性读取5个
        //test.txt:“abchello老师你好“
        char[] ch = new char[5];
        //每次读取ch的长度个也就是5个字符并且存放入数组,这里会返回ch数组的元素数量。
        //也就是说,如果ch中有5个元素,则返回5,如果只有2个元素就返回2
        int len;
        while ((len=fr.read(ch))!=-1) { //fr.read(ch)如果不放在while的()里会导致一直不停的读取
            for (int i = 0; i < len; i++) { //每次读取数组中0到len-1的下标的字符
                System.out.print(ch[i]);
                //len=fr.read(ch)  //如果不放在while的()内也可以放在循环中
            }
            /*//也可以直接将数组转换成字符串
            String str = new String(ch,0,len);//转换数组中从下标[0,len)的字符
            System.out.print(str);*/
        }
    }
}

二、FileWriter

1.每次写入一个字符

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

public class Demo03 {
    public static void main(String[] args) throws IOException {
        //1.将目标文件并封装为对象
        File file = new File("d:\\javatest\\new.txt");
        //2.创建FileWriter类,并传入目标文件对象
        //如果new.txt不存在,会自动创建,如果存在,则会覆盖原内容
        FileWriter fw = new FileWriter(file);
        /*//file后的append参数true表示追加,false表示覆盖
        FileWriter fw = new FileWriter(file,true);  //添加的内容会追加到file后面
        FileWriter fw = new FileWriter(file,false);   //添加的内容会覆盖到file的内容*/

        //3.将数据输出到目标文件:write()方法
        String s="abchello老师你好";
        //1)一个一个字符输入到文件
        for (int i = 0; i < s.length(); i++) {
            //System.out.println(s.charAt(i));//可以返回字符串中的每一个字符
            fw.write(s.charAt(i));
        }
    }
}

2.每次写入多个字符(缓冲数组)

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

public class Demo03 {
    public static void main(String[] args) throws IOException {
        //1.将目标文件并封装为对象
        File file = new File("d:\\javatest\\new.txt");
        //2.创建FileWriter类,并传入目标文件对象
        //如果new.txt不存在,会自动创建,如果存在,则会覆盖原内容
        FileWriter fw = new FileWriter(file);
        /*//file后的append参数true表示追加,false表示覆盖
        FileWriter fw = new FileWriter(file,true);  //添加的内容会追加到file后面
        FileWriter fw = new FileWriter(file,false);   //添加的内容会覆盖到file的内容*/

        //3.将数据输出到目标文件:write()方法
        String s="abchello老师你好";
        
        //2)利用缓冲数组将多个字符一起输入到文件
        //将字符串转为数组
        char[] chars = s.toCharArray();
        //直接将数组写入到文件中
        fw.write(chars);
        //4.关闭流
        fw.close();
    }
}

三、FileReader和FileWriter实现读取文件并写入到另一个文件

1.每次写入一个字符

import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class Demo04 {
    public static void main(String[] args) throws IOException {
        //1.将源文件和目标文件都封装为对象
        File src = new File("D:\\javatest\\demo04source.txt");
        File tgt = new File("D:\\javatest\\demo04target.txt");
        //2.创建FileReader和FileWriter对象接收源文件和目标文件
        FileReader fr = new FileReader(src);
        FileWriter fw = new FileWriter(tgt);

        //3.读取源文件
        //1)一个一个写入
        int n;
        while ((n=fr.read())!=-1){
                fw.write(n);    //fr.read()读取一个字符,fw.write()写入一个字符
            }
        
        //4.关闭流(后用先关)
        fw.close();
        fr.close();
    }
}

 2.每次写入多个字符(缓冲数组)

import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class Demo04 {
    public static void main(String[] args) throws IOException {
        //1.将源文件和目标文件都封装为对象
        File src = new File("D:\\javatest\\demo04source.txt");
        File tgt = new File("D:\\javatest\\demo04target.txt");
        //2.创建FileReader和FileWriter对象接收源文件和目标文件
        FileReader fr = new FileReader(src);
        FileWriter fw = new FileWriter(tgt);

        //3.读取源文件
       
        //2)5个一次性读取,放入数组,一次性写入数组
        char[] ch = new char[5];
        int len;
        while ((len=fr.read(ch))!=-1){
            fw.write(ch,0,len);    //将缓冲数组里的有效元素,一次性写入
        }

        //4.关闭流(后用先关)
        fw.close();
        fr.close();
    }
}

3.将读取到的多个数组的元素先转换为String后一次性写入

import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class Demo04 {
    public static void main(String[] args) throws IOException {
        //1.将源文件和目标文件都封装为对象
        File src = new File("D:\\javatest\\demo04source.txt");
        File tgt = new File("D:\\javatest\\demo04target.txt");
        //2.创建FileReader和FileWriter对象接收源文件和目标文件
        FileReader fr = new FileReader(src);
        FileWriter fw = new FileWriter(tgt);

        //3.读取源文件
     
        //3)将数组的元素转换为String后写入
        char[] ch = new char[5];
        int len;
        while ((len=fr.read(ch))!=-1){
            String s = new String(ch, 0, len);
            fw.write(s);    //每一次将字符串s,一次性写入,
        }
        
        //4.关闭流(后用先关)
        fw.close();
        fr.close();
    }
}

四、使用try/catch处理FileReader和FileWriter中的异常

1.先编写一段读取文件并写入另一个文件的代码,不处理异常

import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;

public class Demo05 {
    public static void main(String[] args) {
        //先编写一段读取文件并写入到另一个文件的代码
        File src = new File("D:\\javatest\\demo04source.txt");
        File tgt = new File("D:\\javatest\\demo04target.txt");

        FileReader fr = new FileReader(src);    //异常1
        FileWriter fw = new FileWriter(tgt);    //异常2

        char[] ch = new char[5];
        int len=fr.read(ch);    //异常3
        while (len!=-1) {
            fw.write(ch,0,len); //异常4
        }
    }
}

2.开始逐个处理异常

对于异常,使用try/catch处理 

1)对于new FileReader(src)和 new FileWriter(tgt)的异常可以进行合并

 合并后代码如

2)对于fr.read(ch)和fw.write()的异常,可以看到都是IOException,与上面的异常相同,所以可以合并到上面的try中,就算异常不一样,也要把所有可能出现异常的语句放到try中,再添加缺少的异常。

 

3)对于close()产生的异常需要单独处理,且需要加上防止空指针异常的语句

五、FileInputStream和FileOutputStream实现读取文件并写入到另一个文件

1.为什么不用FileInputStream和FileOutputStream处理字符(文本文件)

1)对于utf-8存储的字符文件,底层英文字母占1个字节,但是汉字占3个字节,读取时每个汉字会返回3个字节,这样读取没有意义

2)对于读取到的字节,按道理应该使用byte类型来接收,但是byte类型的范围是-128~127,此时对于是否读取到结尾的判断-1,无法判断这个-1是字节值还是读取到了结尾。这里read()方法底层做了处理,使返回的数据都是整数,使用int类型来接收,避免了这种情况。

2.字节流复制非文本文件

1)读一个字节,写一个字节(边读边写)

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class Demo06 {
    public static void main(String[] args) throws IOException {
        //将字符文件封装为对象,demo06source.png:143,355字节
        File src = new File("D:\\javatest\\demo06source.png");
        File tgt = new File("D:\\javatest\\demo06target.png");

        //创建字节流FileInputStream对象,接受文件file
        FileInputStream fis = new FileInputStream(src);
        //创建字节流FileOutputStream对象,接受文件tgt
        FileOutputStream fos = new FileOutputStream(tgt);
        //读取文件
        //1)每次读取一个字节
        int count=0;    //对于文件的字节数设置一个计数器
        int n;
        while ((n=fis.read())!=-1){
            fos.write(n);
            count++;    //每读取一个字节,计数器+1
        }
        System.out.println("count="+count);

        //关闭字节流
        fis.close();
    }
}

2)多个字节读取(缓冲数组),多个字节写入

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class Demo06 {
    public static void main(String[] args) throws IOException {
        //将字符文件封装为对象,demo06source.png:143,355字节
        File src = new File("D:\\javatest\\demo06source.png");
        File tgt = new File("D:\\javatest\\demo06target.png");

        //创建字节流FileInputStream对象,接受文件file
        FileInputStream fis = new FileInputStream(src);
        //创建字节流FileOutputStream对象,接受文件tgt
        FileOutputStream fos = new FileOutputStream(tgt);
        //读取文件
        //2)缓冲数组读取多个字节
        byte[] b = new byte[1024*2];//byte数组长度可以是1024的倍数
        int len;
        while ((len=fis.read(b))!=-1){
            fos.write(b,0,len);
        }
        //关闭字节流
        fis.close();
    }
}

六、缓冲字节流:BufferedInputStream和BufferedOutputStream

1.访问原理

1)逐个字节读取,写入

 2)缓冲数组读取,写入

从上面两种访问的方式,可以得出缓冲数组对于硬盘的访问次数远小于逐个读取,加快程序的读写速度,减少了对硬盘的损耗。

但是我们还可以引入缓冲流,使程序对硬盘的访问降低到1次。

FileInputStream和FileOutputStream等流是与硬件(存储介质)进行的读取,所以速度较慢,当CPU需要使用数据时通过read()、read(byte[])读取数据时就要受到硬件IO的慢速度限制。但是CPU与内存发生的读写速度比硬件IO快10倍不止,所以引入了缓冲流:在内存中建立缓存区,先把存储介质中的数据读取到缓存区中。CPU需要数据时直接从缓冲区读就行了,缓冲区要足够大,在被读完后又触发fill()函数自动从存储介质的文件字节内容中读取字节存储到缓冲区数组。

3)缓冲流原理

 相当于在FileInputStream和FileOutputStream外面再嵌套一层流

2.缓冲字节流BufferedInputStream和BufferedOutpuStream的用法

package com.rzd.no05io;

import java.io.*;

public class Demo07 {
    public static void main(String[] args) throws IOException {
        //1.将文件封装为对象
        File src = new File("D:\\javatest\\demo06source.png");
        File tgt = new File("D:\\javatest\\demo06target.png");
        //2.创建访问字节流对象来接收文件对象
        FileInputStream fis = new FileInputStream(src);
        FileOutputStream fos = new FileOutputStream(tgt);
        //3.嵌套缓冲字节流
        BufferedInputStream bis = new BufferedInputStream(fis);
        BufferedOutputStream bos = new BufferedOutputStream(fos);

        //4.文件读取和写入
        //对于字节流,使用byte数组接收
        byte[] b = new byte[1024 * 6];
        int len;
        while ((len=bis.read(b))!=-1) {
            bos.write(b,0,len);
            //bos.flush();  //底层已经使用flushBuffer()刷新缓冲区,不用手动刷新
        }

        //5.关闭流(倒着关闭)
        //FileInputStream节点流,BufferedInputStream处理流,关闭顺序为:先关闭处理流,再关闭节点流。
        //可以直接关闭高级流(处理流),处理流关闭的时候,会调用节点流的关闭方法
        bos.close();
        bis.close();
       /* fos.close();
        fis.close();*/
    }
}

3.对三种读取写入方式的速度的验证

按照原理,三种读取写入方式的速度应该为:逐个读取写入速度应该 < 缓冲数组读取的速度 < 缓冲流嵌套

可以利用System.currentTimeMillis()得到当前的系统时间来计算出

1)逐个读取写入

2)缓冲数组读取写入

 3)缓冲流

 

 

 时间过短,这里体现不出区别,换个大点的文件应该会有区别

七、缓冲字符流:BufferedReader和BufferedWriter

1.BufferedReader和BufferedWriter完成对文本文件的复制

1)逐个

import java.io.*;

public class Demo08 {
    public static void main(String[] args) throws IOException {
        /*demo04source.txt:
        -FileInputStream和FileOutputStream等流是与硬件(存储介质)进行的读取,所以速度较慢,当CPU需要使用数据时通过read()、read(byte[])读取数据时就要受到硬件IO的慢速度限制。
        -但是CPU与内存发生的读写速度比硬件IO快10倍不止,所以引入了缓冲流:在内存中建立缓存区,先把存储介质中的数据读取到缓存区中。CPU需要数据时直接从缓冲区读就行了。
        -缓冲区要足够大,在被读完后又触发fill()函数自动从存储介质的文件字节内容中读取字节存储到缓冲区数组。*/
        File src = new File("D:\\javatest\\demo04source.txt");
        File tgt = new File("D:\\javatest\\demo04target.txt");

        FileReader fr = new FileReader(src);
        FileWriter fw = new FileWriter(tgt);

        //缓冲字符流嵌套
        BufferedReader br = new BufferedReader(fr);
        BufferedWriter bw = new BufferedWriter(fw);

        //文件读取、写入
        //1)逐个
        int n;
        while ((n=br.read())!=-1){
            bw.write(n);
        }

        bw.close();
        br.close();
    }
}

2)缓冲数组

import java.io.*;

public class Demo08 {
    public static void main(String[] args) throws IOException {
        /*demo04source.txt:
        -FileInputStream和FileOutputStream等流是与硬件(存储介质)进行的读取,所以速度较慢,当CPU需要使用数据时通过read()、read(byte[])读取数据时就要受到硬件IO的慢速度限制。
        -但是CPU与内存发生的读写速度比硬件IO快10倍不止,所以引入了缓冲流:在内存中建立缓存区,先把存储介质中的数据读取到缓存区中。CPU需要数据时直接从缓冲区读就行了。
        -缓冲区要足够大,在被读完后又触发fill()函数自动从存储介质的文件字节内容中读取字节存储到缓冲区数组。*/
        File src = new File("D:\\javatest\\demo04source.txt");
        File tgt = new File("D:\\javatest\\demo04target.txt");

        FileReader fr = new FileReader(src);
        FileWriter fw = new FileWriter(tgt);

        //缓冲字符流嵌套
        BufferedReader br = new BufferedReader(fr);
        BufferedWriter bw = new BufferedWriter(fw);

        //文件读取、写入
        //2)缓冲数组
        char[] ch = new char[20];
        int len;
        while ((len=br.read(ch))!=-1){
            bw.write(ch,0,len);
        }

        bw.close();
        br.close();
    }
}

3)逐行读取

BufferedReader缓冲流有readLine()方法

public class Demo08 {
    public static void main(String[] args) throws IOException {
        /*demo04source.txt:
        -FileInputStream和FileOutputStream等流是与硬件(存储介质)进行的读取,所以速度较慢,当CPU需要使用数据时通过read()、read(byte[])读取数据时就要受到硬件IO的慢速度限制。
        -但是CPU与内存发生的读写速度比硬件IO快10倍不止,所以引入了缓冲流:在内存中建立缓存区,先把存储介质中的数据读取到缓存区中。CPU需要数据时直接从缓冲区读就行了。
        -缓冲区要足够大,在被读完后又触发fill()函数自动从存储介质的文件字节内容中读取字节存储到缓冲区数组。*/
        File src = new File("D:\\javatest\\demo04source.txt");
        File tgt = new File("D:\\javatest\\demo04target.txt");

        FileReader fr = new FileReader(src);
        FileWriter fw = new FileWriter(tgt);

        //缓冲字符流嵌套
        BufferedReader br = new BufferedReader(fr);
        BufferedWriter bw = new BufferedWriter(fw);

        //文件读取、写入
        //3)BufferedReader缓冲流有readLine()方法,按行读取
        String str ;
        while ((str= br.readLine())!=null){
            bw.write(str);
            bw.newLine();   //这里必须加上新起一行的标志,否则读取到的内容不会换行
        }

        bw.close();
        br.close(); 
    }
}

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值