Java中的IO流

Java中的IO流


      Java的核心库java.io提供了全面的IO接口。包括:文件读写、标准设备输出等。Java中IO是以流为基础进行输入输出的,所有数据被串行化写入输出流,或者从输入流读入。


百度百科:

http://baike.baidu.com/link?url=r9vOfxsGkUHzoGw3rxvw0YQJiFHsmS3P2cQGV4prjdT14RCCXNxCvd3KNuHgxF56Upj86uJ2EAkK1_vjSiHIYK


在线API:

http://www.apihome.cn/api/java/java.io_1


Java IO流的分类

  • 1) 字节流:数据流中的最小的数据单元是字节,一次读入读出8位二进制;

  • 2) 字符流:数据流中的最小的数据单元是字符,一次读入读出16位二进制,java中的字符是Unicode编码,一个字符占用两个字节。


字节流

输入字节流:InputStream类
  • InputStream类是个抽象类是所有字节输入流的超类。

1


读取文件:FileInputStream
  • 在src目录下创建一个a.txt文件

2


  • 创建一个FileInputStream类的对象用来读取a.txt文件
package com.lingdu.file;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class FileInputStreamDemo {

    /**
     * 使用InputStream抽象类的子类FileInputStream类
     * 从一个文件中读取流数据
     */
    public static void test1() {
        try {
            //读取src下的a.txt文件
            FileInputStream myStream = new FileInputStream("src/a.txt");
            int a = 0;
            //如果没读到文件尾,则继续执行
            while((a = myStream.read()) != -1){
                System.out.print((char)a);
            }
            //关闭流(使用完之后都要关闭)
            myStream.close();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }


    public static void main(String[] args) {
        test1();
    }
}

3


  • 使用多态的特性使用子类FileInputStream
    /**
     * 使用多态的特性使用子类FileInputStream
     */
    public static void test2() {
        try {

            InputStream is = new FileInputStream("src/a.txt");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

输出字节流OutputStream类

4


写到文件:FileOutputStream


写入一个字符到文件中

/**
 * 写入一个字符到文件中
 * @author Administrator
 *
 */
public class FileOutputStreamDemo {


    public static void  test1() {
        try {
            OutputStream os = new FileOutputStream("src/a.txt");
            os.write(97);
            os.flush();
            os.close();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

5



写入一个数组到文件

/**
     * 写入一个数组到文件
     */
    public static void test2() {
//方法比较笨拙不推荐使用,这里只是作为演示
        byte myArray[] = new byte[5];
        myArray[0] = 97;
        myArray[1] = 98;
        myArray[2] = 99;
        myArray[3] = 100;
        myArray[4] = 101;
        try {
            OutputStream os = new FileOutputStream("src/b.txt");
            os.write(myArray);
            os.flush();
            os.close();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

6



写入一个字符串到文件

/**
* 写入一个字符串到文件
*/
public static void test3() {
        String myContent = "I am a good man!";
        try {
            OutputStream os = new FileOutputStream("src/c.txt");
            os.write(myContent.getBytes());
            os.flush();
            os.close();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

7



FileInputStream 和 FileOutputStream 类

通过FileInputStream 和 FileOutputStream 类拷贝文件


步骤:

  • 1、 使用FileInputStream类读取到文件

  • 2、 使用FileOutputStream类写入到新文件


这里我在src目录下创建一个a.txt文件作为测试

8



拷贝方法:

    /**
     * 读取文本文件,读取图片,读取视频
     */
    public static void copyFile(String sourceName,String dest){
        System.out.println("源文件:" + sourceName + ",目标文件:" + dest);
        //1:先读取一个文件
        //2:写入一个文件
        try {
            FileInputStream fis = new FileInputStream(sourceName);
            FileOutputStream fos = new FileOutputStream(dest);
            int a = 0;
            //当还未到达文件尾时,循环读取
            while((a = fis.read()) != -1){
                //每读取一个字节过来,我们就写入到另一个文件里去
                fos.write(a);//这里只会正常写入数据,不会把-1写进去
            }
            fos.flush();//把缓冲区里的数据强制写入到文件中
            fos.close();//关闭输出流
            fis.close();//关闭输入流
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }       
    }


这是如果读取一个视频的话,速度就会变的很慢。


我用一个22mb的视频和1G的视频作为测试

9


Main函数

public static void main(String[] args) {

        //程序运行开始时间
        long begin = System.currentTimeMillis();

        HomeWork.copyFile("src/a.txt", "src/b.txt");

        //程序运行时间=结束时间-开始时间  ,得到的是毫秒值。
        long end = System.currentTimeMillis() - begin;
        System.out.println("\n用时:" + end/1000f + "s");
    }

10

复制22mb的视频都那么吃力,可想而知用1G的视频将会等待更久



所以我们要改进一下我们的程序



使用byte数组的方式进行复制

  • 为了测试,我在src目录下创建了一个a.txt的文件用于测试,并且在txt文本中保存一些数据

11


    /**
     * 由于读取速度太慢,所以要学习新的方法,让我们更快一点
     */
    public static void test2(){
        //设置每次写入3个字节
        byte[] myArray = new byte[3];
        try {
            InputStream is = new FileInputStream("src/a.txt");
            //如果到达文件尾,无法满足while的条件,不会执行while语句的内容
            while(is.read(myArray) != -1){
                for (int i = 0; i < myArray.length; i++) {

                    //打印一下每个字符
                    System.out.print((char)myArray[i]);
                }
            }
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

12

结果是可以复制的



问题:

  • 我当前a.txt文件下保存的数据是lingdu,但是如果我在加一些内容会怎样呢?

13


保存运行一下得到的不是我想要的数据 多出了du 两个字符

14


原因就是:

  • 因为数组定义的长度是3

  • 第一次读取到lin 输出

  • 第二次读取到gdu 输出

  • 第三次读取到a 因为读取时是覆盖操作 所以a覆盖了g之后,后面的全部输出 adu

  • 所以最后的结果是 lingduadu


知道原因之后我们就要改进一下这个方法了

/**
* 问题:
* 当使用数组的时候,如果文件里的字符的长度不是数组的倍数的时候,拿到的数据会重复
*/
    public static void test3(){
        //这里的数组长度是指 每次读取3个字节
        byte[] myArray = new byte[3];
        //定义一个变量用来保存数组的长度
        int len;
        try {
            InputStream is = new FileInputStream("src/a.txt");
            //如果到达文件尾,无法满足while的条件,不会执行while语句的内容
            while((len = is.read(myArray)) != -1){
                //这样就解决了数据重复的问题
                for (int i = 0; i < len; i++) {

                    System.out.print((char)myArray[i]);
                }
            }
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

15

解决了这个重复的问题之后我们就可以继续进行复制了。


现在我们使用数组的方式对1G视频进行复制

    /**
     * 优化
     * 使用数组进行读取
     */
    public static void test4(){
        //这里的数组长度是指 每次读取1024个字节
        byte[] myArray = new byte[1024];
        //定义一个变量用来保存数组的长度
        int len;
        try {

            InputStream is = new FileInputStream("src/1.wmv");
            OutputStream os = new FileOutputStream("src/test.wmv");
            //如果到达文件尾,无法满足while的条件,不会执行while语句的内容
            while((len = is.read(myArray)) != -1){

                //定义过新的数组,这个数组要防止有多余的数据
                byte descArray[] = new byte[len]; 

                //这样就解决了数据重复的问题
                for (int i = 0; i < len; i++) {

                    //System.out.print((char)myArray[i]);


                    descArray[i] = myArray[i];
                }

                os.write(descArray);                    

            }
            os.flush();
            os.close();
            is.close();
            System.out.println("写入成功!");
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }


使用数组的方式写入一个1G的视频才用了1.7秒左右,比刚刚使用1个字节写入快了几百倍

16


BufferedInputStream和BufferedOutputStream 类


性能优化

使用封装好的write(byte[] b, int off, int len)方法,简易代码。
    /**
     * 性能优化
     * 1:使用封装好的方法直接使用write(myArray, 0, len);
     */
    public static void test5(){
        //这里的数组长度是指 每次读取1024个字节
        byte[] myArray = new byte[1024];
        //定义一个变量用来保存数组的长度
        int len;
        try {

            InputStream is = new FileInputStream("src/1.wmv");
            OutputStream os = new FileOutputStream("src/test.wmv");


            //如果到达文件尾,无法满足while的条件,不会执行while语句的内容
            while((len = is.read(myArray)) != -1){
                //最后一次读取数据的时候,只把数组的第0个长度开始到数组的指定len(我们从流里最好一次实际读出的数据)
                os.write(myArray, 0, len);
            }
            os.flush();
            os.close();
            is.close();
            System.out.println("写入成功!");
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }


使用封装好的方法要比自己定义数组数值快很多,而已省去了很多的代码,提高了开发效率

17


使用缓冲区 BufferedInputStream和BufferedOutputStream
    /**
     * 进一步性能优化
     * 2:使用缓冲区 BufferedInputStream跟BufferedOutputStream 
     */
    public static void test6(){
        //这里的数组长度是指 每次读取3个字节
        byte[] myArray = new byte[1024];
        //定义一个变量用来保存数组的长度
        int len;
        try {
            //把原来的流装进一个类里
            BufferedInputStream bis = new BufferedInputStream(new FileInputStream("src/1g.wmv"));   
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("src/test.wmv"));

            //如果到达文件尾,无法满足while的条件,不会执行while语句的内容
            while((len = bis.read(myArray)) != -1){
                //最后一次读取数据的时候,只把数组的第0个长度开始到数组的指定len(我们从流里最好一次实际读出的数据)
                bos.write(myArray, 0, len);
            }
            bos.flush();
            bos.close();
            bis.close();
            System.out.println("写入成功!");
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }


使用缓冲区写入数据的时候,速度快了1倍

18



ByteArrayInputStream 类
  • 当我们没有文件的时候,如何使用流?


这时我们就要用到ByteArrayInputStream 类

    /**
     * 当我们没有文件的时候,如何使用流
     * 
     */
    public static void test8(){
        String content = "lingdu";
        ByteArrayInputStream is = new ByteArrayInputStream(content.getBytes());
        int i = 0;
        while((i = is.read()) != -1){
            System.out.print((char)i);
        }
    }

19



当文件里有中文的时候,会出现乱码

    /**
     * 新的问题:当文件里有中文的时候,可能会乱码
     * 
     */
    public static void test9(){
        String content = "魑魅魍魉";
        byte myArray[] = content.getBytes();
        ByteArrayInputStream is = new ByteArrayInputStream(content.getBytes());

        for (int i = 0; i < myArray.length; i++) {
            System.out.print((char)myArray[i]);
        }
        System.out.println();

        byte a = 0;
        while((a = (byte)is.read()) != -1){
            System.out.print((char)a);
        }
    }

20


如何解决乱码问题呢?

    /**
     * 解决乱码问题
     * 
     */
    public static void test10(){
        String content = "魑魅魍魉";
        byte myArray[] = content.getBytes();
        ByteArrayInputStream is = new ByteArrayInputStream(content.getBytes());
        int len = 0;
        try {
            while((len = is.read(myArray)) != -1){
                System.out.println(new String(myArray));
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

21


  • 如果我要读取一个文本文件里面的中文呢?

我在src下创建一个a.txt,并写入数据

22

    /**
     * 读取文件
     * 解决乱码问题
     * 
     */
    public static void test11(){
        InputStream is;
        try {
            is = new FileInputStream("a.txt");
            byte myArray[] = new byte[6];
            ByteArrayInputStream bais = new ByteArrayInputStream(myArray);
            int len = 0;
            while((len = is.read(myArray)) != -1){
                System.out.println(new String(myArray));
            }
        } catch (FileNotFoundException e1) {
            e1.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


运行结果并不会出现乱码

23


字符流


Reader类


优点:

  • 对InputStream进行包装

  • 比较擅长读取文本文件


还是拿刚刚的文件进行测试,为了解决中文问题,引用字符流

/**
     * 引用字符流,来解决中文问题
     * Reader抽象类,InputStreamReader实现类
     */
    public static void test12() {
        try {
            //InputStreamReader(InputStream in, String charsetName)   可以设置文件的编码
            Reader reader = new InputStreamReader(new FileInputStream("src/a.txt"), "UTF-8");
            int a;
            while((a = reader.read())!= -1){
                System.out.print((char)a);
            }
            reader.close();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

24



使用数组进行读取

    /**
     * 字符流其实就是对字节流进行了包装
     * 字符流读数组
     */
    public static void test13() {
        try {
            Reader reader = new InputStreamReader(new FileInputStream("src/a.txt"), "UTF-8");

            //字符长度越大,越不会出错
            char myArray[] = new char[12];
            int a;
            while((a = reader.read(myArray))!= -1){
                System.out.print(new String(myArray));
            }
            reader.close();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

25


BufferedReader类


性能优化:

  • 使用BufferedReader 进行包装
    /**
     * 字符流
     * BufferedReader
     * 提高读取效率
     */
    public static void test15() {
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("src/a.txt"), "UTF-8"));
            //准备读取
            while (reader.ready()) {
                //打印一行数据
                System.out.println(reader.readLine());
            }
            reader.close();
        } catch (UnsupportedEncodingException | FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

26


Writer类


所谓有读取就有写入,所以引用字符输出流Writer,对OutputStream进行包装

  • 写入数据到文件
    /**
     * 字符流
     * Writer抽象类,OutputStreamWriter实现类
     * 写入数据到文件
     */
    public static void test14() {
        try {
            //true表示在尾部继续添加数据
            Writer writer = new OutputStreamWriter(new FileOutputStream("c.txt",true));
            //BufferedWriter bw = new BufferedWriter(writer);
            writer.write("零度");
            writer.flush();
            writer.close();



        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

数据已经写入到c.txt文件下了

27


BufferedWriter类


性能优化:

  • 当然我们也可以让程序写快一些,就是使用BufferedWriter
/**
     * 字符流
     * BufferedWriter
     * 提高写入字符流效率
     */
    public static void test16() {
        try {
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("a.txt")));
            bw.write("hello 零度!");
            bw.write("pro");
            bw.flush();
            bw.close();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

28


Scanner 类


Scanner 类使读取文件更为简单

/**
 *读取文件的时候要更方便
 */
public static void test18() {
    try {
        Scanner sc = new Scanner(new FileInputStream("a.txt"));
        while(sc.hasNextLine()){
            System.out.println(sc.nextLine());
        }
        System.out.println("读取完成!");
    } catch (FileNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }


}

29


printWriter类


对输出流进行包装,输出操作更简单了

    /**
     *为了能够输出数据的时候更方便,我们要引入printWriter
     */
    public static void test17() {
        try {
            PrintWriter pw = new PrintWriter("a.txt");
            pw.print("I am 零度! 我");
            pw.print(18);
            pw.print("岁");
            pw.flush();
            pw.close();
            System.out.println("写入完成!");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

    }

30

31

### 回答1: JavaIO流操作基本流程如下: 1. 创建流对象:通过File类或其他相关类创建输入流或输出流对象。 2. 打开流:使用输入流或输出流对象的open()方法打开流,这样就可以读取或写入数据。 3. 读取或写入数据:使用输入流或输出流对象的read()或write()方法读取或写入数据。 4. 关闭流:使用输入流或输出流对象的close()方法关闭流,释放资源。 需要注意的是,在使用IO流操作时,要遵循“先打开、后关闭”的原则,以确保数据的完整性和流的正确性。同时,在操作过程也需要进行异常处理,以避免出现不必要的错误。 ### 回答2: JavaIO流基本操作流程如下: 1. 打开文件或者建立网络连接:使用File类或者URL类打开文件或者建立网络连接。 2. 创建流对象:根据需要选择输入流(读取数据)或输出流(写入数据),并创建相应的流对象。常见的输入流有FileInputStream、BufferedReader等,常见的输出流有FileOutputStream、BufferedWriter等。 3. 读取或写入数据:使用流对象读取或写入数据。对于输入流,可以通过调用相关方法(如read()、readline()等)逐个字符或逐行读取数据;对于输出流,可以通过调用相应方法(如write()、print()等)逐个字符或逐行写入数据。 4. 关闭流:读取或写入完成后,需要关闭文件或网络连接,以释放资源。可以调用流对象的close()方法来关闭流。 需要注意的是,在处理IO流时,应该始终使用try-catch-finally块,以确保在发生异常时能够正确关闭流。可以把IO操作放在try块,catch块用于捕获异常,并在finally块关闭流。 另外,为了提高IO效率,可以考虑使用缓冲流来进行读写操作。缓冲流(BufferedInputStream、BufferedOutputStream、BufferedReader、BufferedWriter)可以通过缓冲区将数据从源读入到缓冲区,再从缓冲区写入到目标,提高读写的速度。 以上就是JavaIO流基本操作的流程。根据实际需要选择合适的流对象,并遵循打开、读取/写入、关闭的流程,可以实现灵活、高效的IO操作。 ### 回答3: 在JavaIO流是用于处理输入输出操作的工具。下面是JavaIO流的基本操作流程: 1. 创建流对象:通过使用Java的InputStream和OutputStream类来创建流对象。InputStream类用于读取输入流,而OutputStream类用于写入输出流。 2. 打开流:通过使用流对象对应的构造函数和方法来打开输入和输出流。根据具体情况,可以选择文件流、网络流或内存流来打开流。 3. 读取/写入数据:使用流对象提供的读取和写入方法来读取和写入数据。例如,使用InputStream的`int read()`方法来读取一个字节的数据,使用OutputStream的`void write(int b)`方法来写入一个字节的数据。 4. 关闭流:在读取或写入结束后,必须关闭流以释放相关资源。通过调用流对象的`close()`方法来关闭流。 需要注意的是,在处理异常的时候,我们需要对可能出现的`IOException`进行处理。可以使用try-catch语句块来捕获和处理异常。 流程示例: ```java import java.io.*; public class IOExample { public static void main(String[] args) { try { // 1. 创建流对象 FileInputStream fis = new FileInputStream("input.txt"); FileOutputStream fos = new FileOutputStream("output.txt"); // 2. 打开流 // 3. 读取/写入数据 int data; while ((data = fis.read()) != -1) { fos.write(data); } // 4. 关闭流 fis.close(); fos.close(); } catch(IOException e) { e.printStackTrace(); } } } ``` 上述示例,我们创建了一个用于将一个文件的内容拷贝到另一个文件的程序。首先,我们创建了一个FileInputStream对象来读取输入文件的内容,然后创建了一个FileOutputStream对象来写入输出文件。接下来,我们通过循环从输入流读取一个字节的数据,并将其写入到输出流,直到读取完所有的数据。最后,我们关闭了流对象来释放资源。 这就是JavaIO流的基本操作流程。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值