IO流

来源:互联网 发布:未妨惆怅是清狂 知乎 编辑:程序博客网 时间:2024/05/18 02:36

IO流

字节流

在计算机中,所有文件都是以字节形式存在的,IO流中针对字节的输入输出提供了一系列的流,统称为字节流。
这里写图片描述
这里写图片描述

InputStream

  • int read():从输入流读取一个字节,把它转换为0~255之间的整数,并返回这一整数,返回读取到的内容。如果因为已经到达流末尾而没有可用的字节,则返回值-1。
  • int read(byte[ ] b):从输入流读取若干字节,把它们保存到参数b指定的字节数组中,返回整数表示读取到的字节数。如果因为已经到达流末尾而没有可用的字节,则返回值-1。
  • void close():关闭此输入流并释放与该留关联的所有系统资源

第一个read()方法是从输入流中逐个读入字节,而第二个read()方法则将若干个字节以字节数组的形式一次性读入,从而提高读数据的效率。在进行IO流操作时,当前IO流会占用

OutputStream

  • void write(int b):将指定的字节写入此流。一次写一个字节(比如我传入97,则会把对应的字母a写进去)虽然写出的是一个int数,但是到文件上的是一个字节,会自动去除前三个8位。
  • void write(byte[ ] b):把字节数组中的所有数据都写入输出流
  • void write(byte [ ] b,int off,int len):将指定byte数组中从偏移量off开始的len个字节写入输出流。(从数组b的off位置开始写入len个字节)
  • void close():关闭此输出流并释放与该留关联的所有系统资源

第一个方法逐个写入字节,后两个方法是将若干个字节以字节数组的形式一次性写入,提高写数据的效率

InputStream和OutputStream这两个类是抽象类,不能被实例化。

字节流读写文件

针对文件的读写,提供了两个类,FileInputStream和FileOutputStream

FileInputStream

FileInputStream用于读取文件中的数据

构造方法:

  • FileInputStream(String name)
  • FileInputStream(File file)
public class Demo {    public static void main(String[] args) throws IOException{        //a.txt中的内容为ab        FileInputStream fis=new FileInputStream("a.txt");//相当于在内存和硬盘之间建立一条通道        int x=fis.read();//从硬盘上读取一个字节        System.out.println(x);//97        int y=fis.read();        System.out.println(y);//98        int z=fis.read();        System.out.println(z);//-1 结束标记为-1        fis.close();        //------------------------------        FileInputStream fiss=new FileInputStream("a.txt");        int b=-1;        while ((b=fiss.read())!=-1) {            System.out.println(b);        }        fiss.close();    }}

FileOutputStream

构造方法:

  • FileOutputStream(String name):如果没有这个文件,会创建一个。如果有,会先将这个文件的内容清空
  • FileOutputStream(String name,boolean append):如果append的值为true,则将字节写入文件末尾,而不是先将文件的内容清空。
  • FileOutputStream(File file)
  • FileOutputStream(File file)
public class Demo {    public static void main(String[] args) throws IOException{        FileOutputStream fos=new FileOutputStream("b.txt");//创建字节流输出对象,如果没有就自动创建一个        fos.write(97);//虽然写出的是一个int数,但是到文件上的是一个字节,会自动去除前三个8位        fos.write(98);        fos.close();        FileOutputStream foss=new FileOutputStream("b.txt",true);//如果想续写就在第二个参数传true        foss.write(97);        foss.close();    }}

拷贝文件

新建一个文件a.txt,里边填写abc

public class Demo {    public static void main(String[] args) throws IOException{        FileInputStream fis=new FileInputStream("a.txt");        FileOutputStream fos=new FileOutputStream("b.txt",true);        int num1=fis.read();//从a.txt中读取一个字节,存到num1中        fos.write(num1);//向b.txt中写入一个字节,把num1中的字节写入        System.out.println((char)num1);//a        int num2=fis.read();         fos.write(num2);        System.out.println((char)num2);//b        int num3=fis.read();        fos.write(num3);        System.out.println((char)num3);//c        int num4=fis.read();        System.out.println(num4);//-1    }}

上面可以简写为

public class Demo {    public static void main(String[] args) throws IOException{        FileInputStream fis=new FileInputStream("a.txt");        FileOutputStream fos=new FileOutputStream("b.txt",true);        int num=-1;        while ((num=fis.read())!=-1) {            fos.write(num);            System.out.println((char)num);        }    }}

这样一个字节一个字节的读,一个字节一个字节的写,效率很低。就相当于我从车上往下搬饮料是一瓶一瓶的搬。

定义一个数组,把字节存入到数组中,一个数组,一个数组的读写。这就相当于一箱一箱的搬饮料。字节流一次读写一个数组的速度肯定比一次读写一个快。

public class Demo {    public static void main(String[] args) throws IOException{        FileInputStream fis=new FileInputStream("a.txt");        FileOutputStream fos=new FileOutputStream("b.txt",true);        byte[] arr=new byte[2];//定义一个2个字节大小的数组        while (fis.read(arr)!=-1) {//读取2个字节到arr中            fos.write(arr);//将arr中的字节写入到流中            for (byte b : arr) {                System.out.println((char)b);            }            System.out.println("-----------------");        }    }}

运行结果为

ab-----------------cb-----------------

a.txt文件中有abc三个字节,第一次读取两个字节ab,第二次的cb是什么鬼?
这里写图片描述

第一次读取了ab到数组arr中,然后接着往下读取,这时候就还剩一个c。第二次把c读取到数组arr中,覆盖了原来的a,现在数组中的数据就变为了cb。然后b.txt中的内容就变为了abcb

如何解决这个问题?

public class Demo {    public static void main(String[] args) throws IOException{        FileInputStream fis=new FileInputStream("a.txt");        FileOutputStream fos=new FileOutputStream("b.txt",true);        byte[] arr=new byte[2];//定义一个2个字节大小的数组        int len=-1;        while ((len=fis.read(arr))!=-1) {//读取arr个字节            fos.write(arr,0,len);            for (byte b : arr) {                System.out.println((char)b);            }            System.out.println("-----------------");        }    }}

运行结果为

ab-----------------cb-----------------

这里写图片描述

别的地方都一样,但这次运行完之后,b.txt中的内容为abc了。符合最终的目标。

len=fis.read(arr)其中len记录了这次读取的字节数。

fos.write(arr,0,len);这句话的意思是,从arr数组的0下标开始写入len个字节,而len为这次读取的字节数,这次只读取了c,所以len为1。也就是说这此只写入了c这个字符。

BufferedInputStream和BufferOutputStream

字节流一次读写一个数组的速度明显比一次读写一个字节的速度快。Java本身设计的时候,也考虑到了这样的设计思想,提供了字节缓冲区流。

BufferedInputStream内置了一个缓冲区(数组),BufferedInputStream会一次性从文件中读取8192个,存在缓冲区中。直到缓冲区中所有的都被使用过,才重新从文件中读取8192个。

BufferedOutputStream也内置了一个缓冲区,程序向流中写出字节时,不会直接写到文件,先写到缓冲区中。直到缓冲区写满,才会把缓冲区中的数据一次性写到文件里。

这里写图片描述

bis对fis装饰了一下,功能更强大了。

先将a.txt中的东西都读到bis内置的数组中,再将数组中的字节一个一个的赋给b,b再将他的值一个一个的存到bos的内置数组中。当bos中的内置数组满了之后会自动将数据写入b.txt。

虽然步骤更加繁琐但因为操作都是在内存中完成的,所以和之前一个一个字节的读速度快(只要降低到硬盘的读写次数就会提高效率)。但和自己定义一个数组来做缓冲区相比,慢。自己定义的那个只用了一个数组,而这个用了两个数组。

public class Demo {    public static void main(String[] args) throws IOException {        FileInputStream fis=new FileInputStream("a.txt");        FileOutputStream fos=new FileOutputStream("b.txt");        BufferedInputStream bis=new BufferedInputStream(fis);//将fis装饰一下        BufferedOutputStream bos=new BufferedOutputStream(fos);        int b=-1;        while ((b=bis.read())!=-1) {            bos.write(b);        }    }}

运行完这段代码会发现,b.txt中并没有把abc拷贝过去。

在代码末尾加一句bos.flush(),abc就都拷过去了。因为BufferedOutputStream中的内置缓冲区,是直到缓冲区写满,才会把缓冲区中的数据一次性写到文件里。这才3个字节,没有填满数组。数组中的数据不会写到b.txt中。

flush()方法可以将数组中的数据强制写入目标设备,此过程称为刷新。

而close()方法会在关闭资源之前刷新一遍(看其源码可知,在其内部调用了flush()方法)。

IO异常的处理方式

public class Demo {    public static void main(String[] args){        FileInputStream fis=new FileInputStream("a.txt");//可能路径中有不存在的盘符        FileOutputStream fos=new FileOutputStream("b.txt",true);//可能路径中有不存在的盘符        byte[] arr=new byte[2];        int len=-1;        while ((len=fis.read(arr))!=-1) {//可能文件不可读            fos.write(arr,0,len);//可能文件不可写        }        fis.close();//可能没有正常关闭        fos.close();    }}

每句话都可能报错,之前是直接抛出去,但抛出去之后,流就关闭不了了,浪费系统资源。

jdk1.6版本之前的解决办法

public class Demo {    public static void main(String[] args) throws IOException {        FileInputStream fis = null;        FileOutputStream fos = null;        try {            fis = new FileInputStream("a.txt");            fos = new FileOutputStream("b.txt", true);            byte[] arr = new byte[2];            int len=-1;            while ((len = fis.read(arr)) != -1) {                fos.write(arr, 0, len);            }        } finally {            try {                if (fis != null)                    fis.close();            } finally {           //try finally的嵌套的目的是能关一个尽量关一个                if (fos != null)                    fos.close();            }        }    }}

jdk1.7版本处理异常

public class Demo {    public static void main(String[] args) throws IOException {        try (                FileInputStream fis = new FileInputStream("a.txt");                FileOutputStream fos = new FileOutputStream("b.txt", true);            ) {                byte[] arr = new byte[2];                int len=-1;                while ((len = fis.read(arr)) != -1) {                    fos.write(arr, 0, len);                }            }    }}

当写在try的小括号里,在执行完大括号里边的内容后,会自动调用其close方法。

字符流

当用字节流读取中文的时候,很可能读到半个中文,造成乱码。字节流写出中文的时候,字节流直接操作的是字节,写出中文必须将字符串转换成字节数组。

Reader和Writer是字符流的顶级父类

这里写图片描述

这里写图片描述

FileReader

FileReader可以从关联的文件中读取一个或一组字符

通过编码表来一次能够获取一个字符。按照字符的大小读取,不会出现半个中文。

FileWriter

字符流的拷贝

在a.txt中填写字符大家好

public class Demo {    public static void main(String[] args) throws IOException {        FileReader fr=new FileReader("a.txt");        FileWriter fw=new FileWriter("b.txt");        int c=-1;        while((c=fr.read())!=-1){            fw.write(c);        }    }}

运行代码,a.txt中的内容并没有拷贝到,b.txt。而在末尾添加了fw.flush()后,就可以拷贝过去了。

因为在其内部自己定义了一个1024大小的char数组来做缓冲区。2048个字节,相当于2k。

什么时候用字符流?

字符流可以拷贝纯文本文件(不可以拷贝非纯文本文件,比如传个图片,上面的编码在码表上查不到),但不推荐使用,因为读取时会把字节转换为字符,写出时还要把字符转换会字节。

在只读或只写的时候可以用字符流。

BufferedReader和BufferedWriter

BufferedReader和BufferedWriter内置一个16k的缓冲区。其中有方法可以读一行

  • readLine()
  • newLine():写出回车换行符
public class Demo {    public static void main(String[] args) throws IOException {        BufferedReader br=new BufferedReader(new FileReader("a.txt"));        BufferedWriter bw=new BufferedWriter(new FileWriter("b.txt"));        String line;        while((line=br.readLine())!=null){            bw.write(line);            bw.newLine();//写出回车换行符            //bw.write("\r\n");也可以回车换行,但只在windows系统有效。Linux的是\n。Mac的是\r        }        br.close();        bw.close();    }}

使用指定的编码表读写字符

项目–>右键–>Properties–>Resource–>Text flie encoding里边默认的为GBK

FileReader是使用默认码表读取文件,如果需要使用指定码表读取,可以使用InputStreamReader(字节流,编码表)

FileWriter是使用默认码表写出文件,如果需要使用指定码表写出,可以使用InputStreamWriter(字节流,编码表)

public class Demo {    public static void main(String[] args) throws IOException {        InputStreamReader isr=new InputStreamReader(new FileInputStream("a.txt"),"utf-8");        OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("b.txt"),"utf-8");        int c=-1;        while ((c=isr.read())!=-1) {            osw.write(c);        }        isr.close();        osw.close();    }}
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 小雯回乡爷爷家下说 老赵操孙萧萧章300 爷爷你慢慢的 娇兰玉婷兰花系列 奋发人生 爷爷奶奶的奋斗力史 爷爷趴在玉婷的身上 朋友的妻子字幕中文翻译 露脸怀孕嫂嫂在线播放 中文字幕侵犯妻子在线疯人院 硬上嫂嫂在线 在线播放 怀孕 中文字幕女老师在线播放 丈夫经常晚归妻子不满离婚 农村孕妇对白 年轻母亲9完整高清免费观看 国产孕妇碰碰碰 厨房侵犯中文字幕 我邻居的妻子中文字幕在线 怀孕全部过程视频播放 水电工在厨房和妻子的视频 妻子出轨水电工在线播放 老公把婆婆干怀孕 在丈夫面前被侵 中文字幕全集 部长的妻子味道中文字幕 中文字幕被水电工掠夺的妻子 妻子在厨房跟水电工 互动 妻子与水电工在线 丈夫出差妻子与水电工 樱萌子被水电工侵犯中文字幕 在丈夫的面前侵犯入侵中文字幕 好妻子在线中文字幕 前田香织侵犯中文字幕 佐佐木明希上司中文字幕迅雷 医生d淫孕妇 公公一晚上要8次 公公现在就想要白关婷中文字幕 丈夫上司侵犯系列在线 义父犯美媳嫁樱花叶菜在线播放 儿子的妻子在线中文字幕云播 老公去世公公每天晚上抱着我睡 被水电工掠夺的妻子在线播放b