Java基础-IO流

来源:互联网 发布:网络传真怎么发 编辑:程序博客网 时间:2024/05/16 04:33

终于学习到了本人认为Java中体系最复杂的IO流这一章了。如果在学习之前没有好好的捋一捋IO流的体系,各种流之间的关系,学习起来真的会非常吃力。

IO概述:
IO流(Input&Output):是为了解决不同设备之间数据传输的问题。IO流一般配合着网络,才能发挥其强大的功能。

IO的体系图
这里写图片描述

分析:    在学习IO体系的时候,我们一般是按照字符流和字节流来展开的。每一个体系中,都有对应的普通的流和高效的流。

首先,学习字符流
字符流包括:
A:字符输入流 Reader —— 是一个抽象类,要想实现数据的输入,需要new其子类对象
B:字符输出流 Writer —— 是一个抽象类,new其子类对象

在学习过程中,通常会遇到这样的问题:一个流到底是输入流还是输出流,会有不同的争论。其实这个是相对的,一般情况下,我们都是站在Java程序的角度上去看待这个问题。在Java的角度,流进Java程序的,就是输入流,流出Java程序的就是输出流。需求:我们一般都会使用程序对文本文件来处理数据。要想对文件进行读取和写入数据,那么需要用到与File有关的输入输出流**FileReader & FileWriter**   下面我们来学习一下这两个类

代码: FileWriter

import java.io.FileWriter;import java.io.IOException;public class FileWriterDemo {    public static void main(String[] args) {        // 创建FileWriter对象        FileWriter fw = null;        try {            /*             * 创建字符输出流对象做了几件事? A:调用系统功能创建了指定的文件; B:创建了字符输出流对象; C:把字符输出流对象指向创建的文件             */            fw = new FileWriter("a.txt");            //调用写数据的功能            fw.write("你好,傻逼IO");            /*             * 为什么要flush() 在Java中,1个字符=2个字节             * 在系统文件数据的底层单位是字节,而我们现在使用的是字符输出流,所以不能直接把数据写入文件,             * 在这里,是把要输出的数据存放在缓冲区里,只有我们刷新缓冲区,数据才会被写入到文件中.             */            fw.flush();        } catch (IOException e) {            e.printStackTrace();        } finally {            try {                /*                 * 为什么一定要close() 1.让流对象变成垃圾 2.通知系统去释放与文件相关的资源.                 */                fw.close();            } catch (IOException e) {                e.printStackTrace();            }        }    }}

结果:
这里写图片描述
分析:
A:创建字符流对象,做了几件事? 1、调用了系统功能创建了指定文件;2、创建了字符输出流对象;3、把字符输出流对象
指向了创建的文件。
B:为什么要flush() 在Java中,1个字符=2个字节
在系统文件数据的底层单位是字节,而我们现在使用的是字符输出流,所以不能直接把数据写入文件,
在这里,是把要输出的数据存放在缓冲区里,只有我们刷新缓冲区,数据才会被写入到文件中.
C:为什么一定要close()
1、让流变成垃圾,释放资源
2、通知系统去释放与文件管理相关的资源。

FileWriter的几个小问题

            字符输出流操作步骤:             *      A:创建字符输出流对象             *      B:调用字符输出流对象的写入数据方法,并刷新缓冲区             *      C:释放资源

*
* 三个小问题:
*
* 问题1:为什么FileWriter没有无参构造方法?
* 因为在写数据的时候,必须要明确些到哪里去.
*
* 问题2:flush()和close()的区别?
* flush(): 只刷新缓冲区,流对象还可以使用
* close(): 先刷新缓冲区,再关闭流对象,流对象不可以继续被使用.
*
* 问题3:难道每次调用完流对象的写入数据方法时,都需要刷新缓冲区吗?是否可以不刷新,直接等到close()来解决?
* 这两种方法都不可取.

代码:FileWriter 加入了捕捉异常标准代码

package cn.itcast.filewriter;/* * FileWriter加入异常处理的标准代码 *  */import java.io.FileWriter;import java.io.IOException;public class FileWriterDem3 {    public static void main(String[] args) {        // 创建字符输出流对象        FileWriter fw = null;        try {            fw = new FileWriter("c.txt");            fw.write("干了这杯热翔");            fw.flush();        } catch (IOException e) {            e.printStackTrace();        } finally {            if (fw != null) {                try {                    fw.close();                } catch (IOException e) {                    e.printStackTrace();                }            }        }    }}

FileReader

FileReader 字符输入流
* 构造方法:
* FileReader(File file)
* FileReader(String fileName) 选用
*
* 读取方法:
* int read(): 每次读取一个字符,没读取完一个字符,自动移动到下一个数据位置等待读取
* 当没有数据可读时,会返回-1
int read(char[] cbuf):

代码:
public class FileReaderDemo {    public static void main(String[] args) {        // 创建字符输入流对象        FileReader fr = null;        try {            fr = new FileReader("FileReaderDemo.java");//          int ch = fr.read();//          while(ch != -1){//              System.out.print((char)ch);//              ch = fr.read();//          }            //开发是的写法            int ch = 0;            while((ch=fr.read())!=-1){                System.out.print((char)ch);            }        } catch (IOException e) {            e.printStackTrace();        } finally {            if (fr != null) {                try {                    fr.close();                } catch (IOException e) {                    e.printStackTrace();                }            }        }    }}

结果:
这里写图片描述
分析:
读取一个文件,在控制台上输出

FileReader读取数据方式二:
* int read(char[] cbuf): 每次读取数据,把数据存储到字符数组中,读取长度自定义,一般为1024的整数倍
* 返回值是实际读取的长度.
代码2:

import java.io.FileNotFoundException;import java.io.FileReader;import java.io.IOException;public class FileReaderDemo3 {    public static void main(String[] args) throws IOException {        //创建字符输入流对象        FileReader fr = new FileReader("FileReaderDemo.java");        //读取 开发中的代码        char[] chs = new char[1024];        int len = 0;        while((len = fr.read(chs))!=-1){            System.out.print(new String(chs,0,len));        }    }}

结果:
这里写图片描述
分析:
这个是开始中的标准代码,每次读取1024个字符,大大的提高了效率。在开发中,一般这个字符数组的大小,都是设置为1024的整数倍。

那么在学习完FileReader和FileWriter两个对文件操作的类后,就可以用这些学习过的方法,来进行文件的复制了。
需求:将本项目目录下的FileReaderDemo.java文件,复制到D:\copy.java
* 思路:
* 数据源:
* FileReaderDemo.java – Reader –FileReader
*
* 目的地:
* D:\copy.java – Writer – FileWriter

代码;
import java.io.FileReader;import java.io.FileWriter;import java.io.IOException;public class CopyFileDemo {    public static void main(String[] args) throws IOException {        // 创建字符输入流对象        FileReader fr = new FileReader("FileReaderDemo.java");        // 创建字符输出流对象        FileWriter fw = new FileWriter("D:\\copy.java");        // 读入数据        int ch = 0;        while ((ch = fr.read()) != -1) {            fw.write(ch);        }        fw.flush();        // 释放资源        fw.close();        fr.close();    }}

结果:
这里写图片描述

相对高效的复制操作,其实也就是用了字符数组的原理:
代码:

import java.io.FileReader;import java.io.FileWriter;import java.io.IOException;public class CopyFileDemo2 {    public static void main(String[] args) throws IOException {        //创建字符输入流对象        FileReader fr = new FileReader("FileReaderDemo.java");        //创建字符输出流对象        FileWriter fw = new FileWriter("d:\\copy1.java");        //创建一个大小为1024的字符数组,存储输入流读取到的数据        char[] chs = new char[1024];        int ch = 0;        //读取        while((ch = fr.read(chs))!= -1){            //将存储在字符数组中的数据写进指定的文件            fw.write(chs);        }        //刷新输出流        fw.flush();        //关闭资源        fw.close();        fr.close();    }}

学习完简单的文件字符流类,下面来学习一下简单的文件字节流类
FileInputStream 和 FileOutputStream

在IO体系里,基本上方法和格式都是固定的,出了部分类有自己特有的方法外,其他基本上都是通用。那么,我们直接使用在FileReader 和 FileWriter类中的方法,进行操作

通过字节流往文件中写数据。
*
* 字节输出流操作步骤:
* A:创建字节输出流对象
* B:调用写数据的方法
* C:释放资源

FileOutputStream

代码:
public class FileOutputStreamDemo {    public static void main(String[] args) throws IOException {        // 创建字节输出流对象        // FileOutputStream fos = new FileOutputStream("a.txt",true);        FileOutputStream fos = new FileOutputStream("a.txt");        // 调用写数据的方法        // 写入一个字节        // fos.write(97);        // fos.write(98);        // fos.write(99);        // fos.flush();        // 写一个字节数组        // byte[] bys = { 97, 98, 99, 100, 101 };        byte[] bys = "abcde".getBytes();        // fos.write(bys);        // 写一个字节数组的一部分        fos.write(bys, 0, 2);        // 释放资源        fos.close();    }}

FileInputStream
代码:

public class FileInputStreamDemo {    public static void main(String[] args) throws IOException {        // 创建字节输入流对象        FileInputStream fis = new FileInputStream("b.txt");        // 调用读取数据的方式,并显示        // 方式1        // int by = 0;        // while ((by = fis.read()) != -1) {        // System.out.println(by);        // }        // 方式2        byte[] bys = new byte[1024];        int len = 0;        while ((len = fis.read(bys)) != -1) {            System.out.print(new String(bys, 0, len));        }        // 释放资源        fis.close();    }}

——————————————————————————————————————————-到这里,已经把简单的字符流和字节流学习了。不过这些方法都属于比较低效的。
下面,我们学习一下高效的字符缓冲流和字节缓冲流
A:字符缓冲流
|–BufferedWriter
|–BufferedReader
B:字节缓冲流
|–BufferedInputStream
|–BufferedOutputStream

字符缓冲流
* 我们开始自己定义数组,给出缓冲区大小,是为了提高效率。
* 那么,java在设计类的时候,它也考虑到了这一点,所以,就提供了一种高效的流。带缓冲区的流。
* BufferedWriter:写入数据
* BufferedReader:读取数据
*
* BufferedWriter:
* 构造方法:BufferedWriter(Writer out)
* 为什么传递的是Writer呢?
* 因为BufferedWriter这种流,被称为缓冲流,它只提供数据的缓冲功能。
* 真正的读写还得靠别人。所以,我们这里将使用FileWriter作为参数传递。
*
* 缓冲区只提供缓冲功能,没有真正的读写。
*
* 基本流:能直接进行读写的流对象。
* 高级流:站在基本流的基础上,提供一些特殊的功能。(处理流。)

代码:BufferedWriter
public class BufferedWriterDemo {    public static void main(String[] args) throws IOException {        // 创建缓冲流对象        // Writer fw = new FileWriter("c.txt");        // FileWriter fw = new FileWriter("c.txt");        // BufferedWriter bw = new BufferedWriter(fw);        BufferedWriter bw = new BufferedWriter(new FileWriter("c.txt"));        // 写入数据        bw.write("hello");        bw.flush();        // 释放资源        // fw.close();// 这个不用关闭        bw.close();    }}
代码:FileReader:
import java.io.BufferedReader;import java.io.FileReader;import java.io.IOException;/* * 字符缓冲流读取数据 */public class BufferedReaderDemo {    public static void main(String[] args) throws IOException {        // 创建字符缓冲流对象        BufferedReader br = new BufferedReader(new FileReader("c.txt"));        // 读取数据        // int ch = 0;        // while ((ch = br.read()) != -1) {        // System.out.print((char) ch);        // }        char[] chs = new char[1024];        int len = 0;        while ((len = br.read(chs)) != -1) {            System.out.print(new String(chs, 0, len));        }        // 释放资源        br.close();    }}

在学习简单IO流的时候,有一个复制文件的操作,如果要复制的文件比较大,可以使用字符缓冲流来提高效率
代码:

package cn.itcast_03;import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.FileReader;import java.io.FileWriter;import java.io.IOException;/* * 用字符高效流复制文本文件。 *  * 数据源: *      FileOutputStreamDemo.java * 目的地: *      Copy.java */public class CopyFile {    public static void main(String[] args) throws IOException {        // 封装数据源和目的地        BufferedReader br = new BufferedReader(new FileReader(                "FileOutputStreamDemo.java"));        BufferedWriter bw = new BufferedWriter(new FileWriter("Copy.java"));        // 一次一个字符        // int ch = 0;        // while ((ch = br.read()) != -1) {        // bw.write(ch);        // // bw.flush();        // }        // 一次一个字符数组        char[] chs = new char[1024];        int len = 0;        while ((len = br.read(chs)) != -1) {            bw.write(chs, 0, len);        }        // 释放资源        bw.close();        br.close();    }}

结果:
由于操作速度非常快,都是用毫秒值来计算的,那么我们要怎样才能知道,到底字符缓冲流,是不是真的比较高效呢?
我们在学习System类的时候,有一个currentTimeMillis()的方法,可以用来计算一段代码之间的时间

不多说,马上改造:代码
package cn.itcast_04;import java.io.BufferedInputStream;import java.io.BufferedOutputStream;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;/** * 需求:把d:\\哥有老婆.mp4复制到项目路径下x.mp3(x=1,2,3,4) *  * @author Administrator *  *         基本字节流一次读写一个字节: 共耗时:66922毫秒  *         基本字节流一次读写一个字节数组: 共耗时:94毫秒 *         高效字节流一次读写一个字节:共耗时:1235毫秒 *         高效字节流一次读写一个字节数组:共耗时:47毫秒 */public class CopyMP3 {    public static void main(String[] args) throws IOException {        long start = System.currentTimeMillis();        // method1();        // method2();//      method3();         method4();        long end = System.currentTimeMillis();        System.out.println("共耗时:" + (end - start) + "毫秒");    }    //高效字节流一次读写一个字节数组    private static void method4() throws IOException {        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(                "d:\\哥有老婆.mp4"));        BufferedOutputStream bos = new BufferedOutputStream(                new FileOutputStream("4.mp4"));        byte[] bys = new byte[1024];        int len = 0;        while((len=bis.read(bys))!=-1){            bos.write(bys,0,len);        }        bos.close();        bis.close();    }    //基本字节流一次读写一个字节数组    private static void method3() throws IOException {        FileInputStream fis = new FileInputStream("d:\\哥有老婆.mp4");        FileOutputStream fos = new FileOutputStream("3.mp4");        byte[] bys = new byte[1024];        int len = 0;        while((len=fis.read(bys))!=-1){            fos.write(bys,0,len);        }        fos.close();        fis.close();    }    // 高效字节流一次读写一个字节    private static void method2() throws IOException {        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(                "d:\\哥有老婆.mp4"));        BufferedOutputStream bos = new BufferedOutputStream(                new FileOutputStream("2.mp4"));        int by = 0;        while ((by = bis.read()) != -1) {            bos.write(by);        }        bos.close();        bis.close();    }    // 基本字节流一次读写一个字节    private static void method1() throws IOException {        FileInputStream fis = new FileInputStream("d:\\哥有老婆.mp4");        FileOutputStream fos = new FileOutputStream("1.mp4");        int by = 0;        while ((by = fis.read()) != -1) {            fos.write(by);        }        fos.close();        fis.close();    }}

结果:
* 基本字节流一次读写一个字节: 共耗时:66922毫秒
* 基本字节流一次读写一个字节数组: 共耗时:94毫秒
* 高效字节流一次读写一个字节:共耗时:1235毫秒
* 高效字节流一次读写一个字节数组:共耗时:47毫秒
分析:
高效流确实会更有效率,一般在开发中,我们都是选择高效流来使用。


BufferedWriter 和 BufferedReader 的特有方法

         * BufferedWriter:         *      public void newLine():根据系统平台写入行分隔符         *               * BufferedReader:         *      public String readLine():一次读取一行的数据。但是不包含换行符。代码如下:
public class BufferedStreamDemo {    public static void main(String[] args) throws IOException {        //创建流对象        BufferedReader br = new BufferedReader(new FileReader("bw.txt"));        // 读取数据        String line = null;        while((line=br.readLine())!=null){            System.out.println(line);        }        br.close();    }}
0 0
原创粉丝点击