Java--IO流--字节流

女爷i 2021-09-28 07:02 602阅读 0赞

字节流

  • 字节流
    • 字节输入流(InputStream)
      • 文件输入流(FileInputStream)
        • 构造方法
        • 读取字节数据
          • eg.图片复制
            • 复制原理
            • 实现代码:
    • 字节缓冲流(BufferedInputStream)
      • 构造方法
      • 字节流、增强流和带数组增强流的对比
    • 打印流(PrintStream)
      • 构造方法
  • 总结
  • end

字节流

  1. 上一篇博客大致介绍了一下IO流,所以这边博客先总结一下字节流的学习,先上一个字节流的家族图片,然后慢慢介绍字节流中比较常用的几种,比如:InputStreamFileInputStreamBufferedInputStreamOutputStreamFileOutputStreamBufferedOutputStreamPrintStream

在这里插入图片描述

字节输入流(InputStream)

  1. Java.io.InputStream抽象类时表示字节输入流的所有类的超类,可以读取字节信息到内存中,它定义了字节流输入的基本共性功能方法。

public void close():关闭此输入流并释放与呲溜相关的任何系统资源
public abstract int read():从输入流读取数据的下移字节
public int read(byte[] b):从输入流中读取一些字节数,并将他们存储到字节数组b中。

文件输入流(FileInputStream)

  1. java.io.FileInputStream类是文件输入流,从文件中读取字节。

构造方法

  • FileInputStream(File file):通过打开与实际文件的连接来创建一个FileInputStream,该文件由文件系统中的File对象file命名。
  • FileInputStream(String name):通过打开与实际文件的连接来创建一个FileInputStream,该文件由文件系统中的路径名name命名。

    1. 当我们创建一个流对象时,必须传入一个文件路径。该路径下,如果没有该文件,会抛出FileNotFoundException异常。

    public class FileInputStreamConstructor throws IOException{

    1. public static void main(String[] args) {
    2. // 使用File对象创建流对象
    3. File file = new File("a.txt");
    4. FileInputStream fos = new FileInputStream(file);
    5. // 使用文件名称创建流对象
    6. FileInputStream fos = new FileInputStream("b.txt");
    7. }

    }

读取字节数据

  1. 读取字节:read方法,每次可以读取一个字节的数据,提升为int类型,读取到文件末尾,返回-1,如下:

    public class FISRead {

    1. public static void main(String[] args) throws IOException{
    2. // 使用文件名称创建流对象
    3. FileInputStream fis = new FileInputStream("read.txt");
    4. // 读取数据,返回一个字节
    5. int read = fis.read();
    6. System.out.println((char) read);
    7. read = fis.read();
    8. System.out.println((char) read);
    9. read = fis.read();
    10. System.out.println((char) read);
    11. read = fis.read();
    12. System.out.println((char) read);
    13. read = fis.read();
    14. System.out.println((char) read);
    15. // 读取到末尾,返回‐1
    16. read = fis.read();
    17. System.out.println( read);

    // 关闭资源

    1. fis.close();
    2. }

    }
    输出结果:
    a
    b
    c
    d
    e
    ‐1

    1. 上面这种方法比较死,可以用**循环读取**方式来改进,代码如下:

    public class FISRead {

    1. public static void main(String[] args) throws IOException{
    2. // 使用文件名称创建流对象
    3. FileInputStream fis = new FileInputStream("read.txt");
    4. // 定义变量,保存数据
    5. int b
    6. // 循环读取
    7. while ((b = fis.read())!=‐1) {
    8. System.out.println((char)b);
    9. }

    // 关闭资源

    1. fis.close();
    2. }

    }
    输出结果:
    a
    b
    c
    d
    e

    1. 使用该方法时候,值得注意的有如下两点:

虽然读取了一个字节,但是自动提升为int类型
流操作完毕后,必须释放系统资源,调用close方法

  1. 使用字节数组读取:read(byte[ ] b),每次读取b的长度个字节到数组中,返回读取到的有效字节个数,读取到末尾时,返回-1,代码如下:

    public class FISRead {

    1. public static void main(String[] args) throws IOException{
    2. // 使用文件名称创建流对象.
    3. FileInputStream fis = new FileInputStream("read.txt"); // 文件中为abcde
    4. // 定义变量,作为有效个数
    5. int len
    6. // 定义字节数组,作为装字节数据的容器
    7. byte[] b = new byte[2];
    8. // 循环读取
    9. while (( len= fis.read(b))!=‐1) {
    10. // 每次读取后,把数组变成字符串打印
    11. System.out.println(new String(b));
    12. }

    // 关闭资源

    1. fis.close();
    2. }

    }

    输出结果:
    ab
    cd
    ed

    1. 仔细的读者肯定会发现,输出结果最后一项多出了一个错误数据 d,由于最后一次读取时,只读取一个字节e,数组中,上次读取的数据没有完全替代,所以要通过len,获取有效的字节,代码如下:

    public class FISRead {

    1. public static void main(String[] args) throws IOException{
    2. // 使用文件名称创建流对象.
    3. FileInputStream fis = new FileInputStream("read.txt"); // 文件中为abcde
    4. // 定义变量,作为有效个数
    5. int len
    6. // 定义字节数组,作为装字节数据的容器
    7. byte[] b = new byte[2];
    8. // 循环读取
    9. while (( len= fis.read(b))!=‐1) {
    10. // 每次读取后,把数组的有效字节部分,变成字符串打印
    11. System.out.println(new String(b0len));// len 每次读取的有效字节个数
    12. }

    // 关闭资源

    1. fis.close();
    2. }

    }

    输出结果:
    ab
    cd
    e

    1. 使用数组读取需要注意的是,每次读取多个字节,减少了系统间的IO操作次数,从而提高了读写的效率,不过这种方式大部分是在开发中使用。
    2. 通过上面介绍的方法,我们就可以用来做一个简单好玩的小游戏,那就是复制图片。
eg.图片复制
复制原理

在这里插入图片描述

实现代码:
  1. public class Copy {
  2. public static void main(String[] args) throws IOException {
  3. // 1.创建流对象
  4. // 1.1 指定数据源
  5. FileInputStream fis = new FileInputStream("D:\\test.jpg");
  6. // 1.2 指定目的地
  7. FileOutputStream fos = new FileOutputStream("test_copy.jpg");
  8. // 2.读写数据
  9. // 2.1 定义数组
  10. byte[] b = new byte[1024];
  11. // 2.2 定义长度
  12. int len;
  13. // 2.3 循环读取
  14. while ((len = fis.read(b))!=‐1) {
  15. // 2.4 写出数据
  16. fos.write(b, 0 , len);
  17. }
  18. // 3.关闭资源
  19. fos.close();
  20. fis.close();
  21. }
  22. }

字节缓冲流(BufferedInputStream)

  1. 上文讲解了InputStream是基础,但是相比较而言,没有那么高效和强大,BufferedInputStream字节缓冲流是InputStream的增强版,相比较而言,BufferedInputStream在读写这方面可以更高效。简单介绍一下缓冲流。
  2. 缓冲流也叫高效流,是对基本的FileXxx流的增强。
  3. 缓冲流的基本原理是在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO次数,从而提高读写的效率。

构造方法

public BufferedInputStream(InputStream in):创建一个新的缓冲输入流。
public BufferedInputStream(OutPutStream out):创建一个新的缓冲输出流。
如下例子所示:

  1. // 创建字节缓冲输入流
  2. BufferedInputStream bis = new BufferedInputStream(new FileInputStream("bis.txt"));
  3. // 创建字节缓冲输出流
  4. BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("bos.txt"));

为什么说BufferedInputStream是高效流,可以通过下面这个例子得出结论:
首先,给大家演示一下基本流的读写:

字节流、增强流和带数组增强流的对比

  1. public class BufferedDemo {
  2. public static void main(String[] args) throws FileNotFoundException {
  3. // 记录开始时间
  4. long start = System.currentTimeMillis();
  5. // 创建流对象
  6. try (
  7. FileInputStream fis = new FileInputStream("jdk8.exe");
  8. FileOutputStream fos = new FileOutputStream("copy.exe")
  9. ){
  10. // 读写数据
  11. int b;
  12. while ((b = fis.read()) != 1) {
  13. fos.write(b);
  14. }
  15. } catch (IOException e) {
  16. e.printStackTrace();
  17. }
  18. // 记录结束时间
  19. long end = System.currentTimeMillis();
  20. System.out.println("普通流复制时间:"+(end start)+" 毫秒");
  21. }
  22. }
  23. 十几分钟过去了...
  24. 现在给大家演示一下缓冲流执行相同的内容
  25. public class BufferedDemo {
  26. public static void main(String[] args) throws FileNotFoundException {
  27. // 记录开始时间
  28. long start = System.currentTimeMillis();
  29. // 创建流对象
  30. try (
  31. BufferedInputStream bis = new BufferedInputStream(new FileInputStream("jdk8.exe"));
  32. BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy.exe"));
  33. ){
  34. // 读写数据
  35. int b;
  36. while ((b = bis.read()) != 1) {
  37. bos.write(b);
  38. }
  39. } catch (IOException e) {
  40. e.printStackTrace();
  41. }
  42. // 记录结束时间
  43. long end = System.currentTimeMillis();
  44. System.out.println("缓冲流复制时间:"+(end start)+" 毫秒");
  45. }
  46. }
  47. 缓冲流复制时间:8016 毫秒
  48. 没有对比就没有伤害,缓冲流仿佛是别人家的孩子般那么六的一匹;其实,如果再加上使用数组的方式,那么可能就是神人般的存在了。举例如下:
  49. public class BufferedDemo {
  50. public static void main(String[] args) throws FileNotFoundException {
  51. // 记录开始时间
  52. long start = System.currentTimeMillis();
  53. // 创建流对象
  54. try (
  55. BufferedInputStream bis = new BufferedInputStream(new FileInputStream("jdk8.exe"));
  56. BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy.exe"));
  57. ){
  58. // 读写数据
  59. int len;
  60. byte[] bytes = new byte[8*1024];
  61. while ((len = bis.read(bytes)) != 1) {
  62. bos.write(bytes, 0 , len);
  63. }
  64. } catch (IOException e) {
  65. e.printStackTrace();
  66. }
  67. // 记录结束时间
  68. long end = System.currentTimeMillis();
  69. System.out.println("缓冲流使用数组复制时间:"+(end start)+" 毫秒");
  70. }
  71. }
  72. 缓冲流使用数组复制时间:666 毫秒
  73. 是否被震惊到了呢?
  74. 好了,接下来介绍一下打印流(PrintStream);

打印流(PrintStream)

  1. 平时我们在控制台打印输出,是调用了print方法和println方法完成的,这两个方法都是来自于java.io.PrintStream类,该类能够方便地打印各种数据类型的值,是一种边界的输出方式,所以,这种流也是我们经常用到的。

构造方法

  1. public PrintStreamString fileName):使用指定的文件名创建一个新的打印流
  2. 如下例子:
  3. PrintStream ps = new PrintStream("ps.txt");
  4. 就是将内容输入到一个名为pstxt文本中去。
  5. System.out就是PrintStream类型的,只不过它的流向是系统规定的,即打印到控制台上,不过,既然是流对象,我们就可以玩一个“小把戏”,就是将数据输出到指定文本文件中。
  6. public class PrintDemo {
  7. public static void main(String[] args) throws IOException {
  8. // 调用系统的打印流,控制台直接输出97
  9. System.out.println(97);
  10. // 创建打印流,指定文件的名称
  11. PrintStream ps = new PrintStream("ps.txt");
  12. // 设置系统的打印流流向,输出到ps.txt
  13. System.setOut(ps);
  14. // 调用系统的打印流,ps.txt中输出97
  15. System.out.println(97);
  16. }
  17. }

总结

  1. 字节流经常用到的方法就是这么几种,所以就简单的介绍一下,如果需要知道其他流的使用方法,可以底下留言,我们可以一起探讨探讨。

end

  1. 谢谢您的阅读!期待与您进一步探讨。

发表评论

表情:
评论列表 (有 0 条评论,602人围观)

还没有评论,来说两句吧...

相关阅读

    相关 IO

    1、IO流-字节流 1.1 IO流的概述 IO流的作用:就是可以对文件或者网络中的数据进行读、写操作。如下图所示: 把数据从磁盘、网络中读取到程序中来,用到的是输

    相关 IO——

    字节输出流OutputStream 此抽象类,是表示输出字节流的所有类的超类。操作的数据都是字节,定义了输出字节流的基本共性功能方法。 输出流中定义的方法: close()