InputStream和OutputStream

文章目录

  • InputStream字节输入流
      • 缓冲
  • OutputStream字节输出流

InputStream字节输入流

InputStream就是Java标准库提供的最基本的输入流。它位于java.io这个包里。java.io包提供了所有同步IO的功能。

要特别注意的一点是,InputStream并不是一个接口,而是一个抽象类,它是所有输入流的超类。

FileInputStreamInputStream的一个子类。FileInputStream就是从文件流中读取数据。

完整地读取一个FileInputStream的所有字节:

public void readFile() throws IOException {
    // 创建一个FileInputStream对象:
    InputStream input = new FileInputStream("src/readme.txt");
    for (;;) {
        int n = input.read(); // 反复调用read()方法,直到返回-1
        if (n == -1) {
            break;
        }
        System.out.println(n); // 打印byte的值
    }
    input.close(); // 关闭流
}

缓冲

在读取流的时候,一次读取一个字节并不是最高效的方法。很多流支持一次性读取多个字节到缓冲区,对于文件和网络流来说,利用缓冲区一次性读取多个字节效率往往要高很多。InputStream提供了两个重载方法来支持读取多个字节:

  • int read(byte[] b):读取若干字节并填充到byte[]数组,返回读取的字节数
  • int read(byte[] b, int off, int len):指定byte[]数组的偏移量和最大填充数

利用上述方法一次读取多个字节时,需要先定义一个byte[]数组作为缓冲区,read()方法会尽可能多地读取字节到缓冲区, 但不会超过缓冲区的大小。read()方法的返回值不再是字节的int值,而是返回实际读取了多少个字节。如果返回-1,表示没有更多的数据了。

private static void testFileInputStream() throws IOException {
        File file = new File("haha.txt");
        FileInputStream fis = new FileInputStream(file);
        //一次读取一个字节 读完之后并跳转到下一个字节 直到读完为止 -1
//        int ch = 0;
//        while ((ch = fis.read()) != -1) {
//            System.out.println((char) ch);
//        }
        //一次读取一组字节
        byte[] buf = new byte[1024]; // 1024 byte = 1kb
        int len = 0;
        while ((len = fis.read(buf)) != -1) {
            System.out.println(new String(buf, 0, len));
        }
        
         File file = new File("haha.txt");
        //文件若不存在 则自动创建
        //append false 覆盖
        //append true 追加
        FileOutputStream fos = new FileOutputStream(file, true);

        //写出单个字节数据
        fos.write(97);
        fos.write(98);
        fos.write(99);

        //写出多个字节数据 字节数组
        String s = "Hello World!";
        fos.write(s.getBytes());
        //必须要关掉流:操作完毕一个文件后 要保存并退出
        fos.close();
  }

在计算机中,类似文件、网络端口这些资源,都是由操作系统统一管理的。应用程序在运行的过程中,如果打开了一个文件进行读写,完成后要及时地关闭,以便让操作系统把资源释放掉,否则,应用程序占用的资源会越来越多,不但白白占用内存,还会影响其他应用程序的运行。

InputStreamOutputStream都是通过close()方法来关闭流。关闭流就会释放对应的底层资源。

在读取或写入IO流的过程中,可能会发生错误,例如,文件不存在导致无法读取,没有写权限导致写入失败,等等,这些底层错误由Java虚拟机自动封装成IOException异常并抛出。因此,所有与IO操作相关的代码都必须正确处理IOException

try ... finally来保证InputStream在无论是否发生IO错误的时候都能够正确地关闭:

try {
            //关联源文件的字节输入流
            FileInputStream fis = new FileInputStream(source);
            //关联字节输入流缓冲流 缓冲区默认8192字节大小
            bis = new BufferedInputStream(fis);
            //关联目标文件的字节输出流
            FileOutputStream fos = new FileOutputStream(aim);
            //关联字节输出流缓冲流 缓冲区默认8192字节大小
            bos = new BufferedOutputStream(fos);

            byte[] buf = new byte[1024];
            int len = 0;
            while ((len = bis.read(buf)) != -1) {
                bos.write(buf, 0, len);
                //bos.flush();
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

OutputStream字节输出流

InputStream相反,OutputStream是Java标准库提供的最基本的输出流。

InputStream类似,OutputStream也是抽象类,它是所有输出流的超类。

InputStream类似,OutputStream也提供了close()方法关闭输出流,以便释放系统资源。要特别注意:OutputStream还提供了一个flush()方法,它的目的是将缓冲区的内容真正输出到目的地。

向磁盘、网络写入数据的时候,出于效率的考虑,操作系统并不是输出一个字节就立刻写入到文件或者发送到网络,而是把输出的字节先放到内存的一个缓冲区里(本质上就是一个byte[]数组),等到缓冲区写满了,再一次性写入文件或者网络。对于很多IO设备来说,一次写一个字节和一次写1000个字节,花费的时间几乎是完全一样的,所以OutputStream有个flush()方法,能强制把缓冲区内容输出。

通常情况下,我们不需要调用这个flush()方法,因为缓冲区写满了OutputStream会自动调用它,并且,在调用close()方法关闭OutputStream之前,也会自动调用flush()方法。

实际上,InputStream也有缓冲区。例如,从FileInputStream读取一个字节时,操作系统往往会一次性读取若干字节到缓冲区,并维护一个指针指向未读的缓冲区。然后,每次我们调用int read()读取下一个字节时,可以直接返回缓冲区的下一个字节,避免每次读一个字节都导致IO操作。当缓冲区全部读完后继续调用read(),则会触发操作系统的下一次读取并再次填满缓冲区。

复制一个文件

public class IODemo02 {
    public static void main(String[] args) throws IOException {
        int count = 0;
        
        //源文件
        File source = new File("C:\\Users\\HENG\\Desktop\\周杰伦 - 暗号.m4a");
        //目标文件
        File aim = new File(source.getName());

        //关联源文件的字节输入流
        FileInputStream fis = new FileInputStream(source);

        //关联目标文件的字节输出流
        FileOutputStream fos = new FileOutputStream(aim);

        byte[] buf = new byte[1024 * 1024]; // KB
        int len = 0;
        while ((len = fis.read(buf)) != -1) {
            count++;
            fos.write(buf,0, len);
        }
        System.out.println("count = " + count);
        fis.close();
        fos.close();
    }
}

字节缓冲输入流/输出流

public class IODemo03 {
    public static void main(String[] args) {
        //源文件
        File source = new File("C:\\Users\\jameth\\Desktop\\周杰伦 - 暗号.m4a");
        //目标文件
        File aim = new File(source.getName());
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        try {
            //关联源文件的字节输入流
            FileInputStream fis = new FileInputStream(source);
            //关联字节输入流缓冲流 缓冲区默认8192字节大小
            bis = new BufferedInputStream(fis);
            //关联目标文件的字节输出流
            FileOutputStream fos = new FileOutputStream(aim);
            //关联字节输出流缓冲流 缓冲区默认8192字节大小
            bos = new BufferedOutputStream(fos);

            byte[] buf = new byte[1024];
            int len = 0;
            while ((len = bis.read(buf)) != -1) {
                bos.write(buf, 0, len);
                //bos.flush();
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
  • FileOutputStream实现了文件流输出;
  • ByteArrayOutputStream在内存中模拟一个字节流输出。

某些情况下需要手动调用OutputStreamflush()方法来强制输出缓冲区。

总是使用try(resource)来保证OutputStream正确关闭。

你可能感兴趣的:(javaSE,java,算法,前端)