Java--IO流--字节流

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Luojun13Class/article/details/88415925

字节流

        上一篇博客大致介绍了一下IO流,所以这边博客先总结一下字节流的学习,先上一个字节流的家族图片,然后慢慢介绍字节流中比较常用的几种,比如:InputStream、FileInputStream、BufferedInputStream、OutputStream、FileOutputStream、BufferedOutputStream、PrintStream。
在这里插入图片描述

字节输入流(InputStream)

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

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

文件输入流(FileInputStream)

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

构造方法

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

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

public class FileInputStreamConstructor throws IOException{
    public static void main(String[] args) {
     // 使用File对象创建流对象    
        File file = new File("a.txt");
        FileInputStream fos = new FileInputStream(file);
     
        // 使用文件名称创建流对象
        FileInputStream fos = new FileInputStream("b.txt");
    }
}

读取字节数据

  1. 读取字节:read方法,每次可以读取一个字节的数据,提升为int类型,读取到文件末尾,返回-1,如下:
public class FISRead {
    public static void main(String[] args) throws IOException{
       // 使用文件名称创建流对象  
       FileInputStream fis = new FileInputStream("read.txt"); 
       // 读取数据,返回一个字节  
        int read = fis.read();
        System.out.println((char) read);
        read = fis.read();
        System.out.println((char) read);
        read = fis.read();
        System.out.println((char) read);
        read = fis.read();
        System.out.println((char) read);
        read = fis.read();
        System.out.println((char) read);
       // 读取到末尾,返回‐1  
       read = fis.read(); 
        System.out.println( read);
// 关闭资源        
        fis.close();
    }
}
输出结果:
a
b
c
d
e
‐1

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

public class FISRead {
    public static void main(String[] args) throws IOException{
       // 使用文件名称创建流对象  
       FileInputStream fis = new FileInputStream("read.txt"); 
       // 定义变量,保存数据  
        int b ;
        // 循环读取
        while ((b = fis.read())!=1) {
            System.out.println((char)b);
        }
// 关闭资源        
        fis.close();
    }
}
输出结果:
a
b
c
d
e

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

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

  1. 使用字节数组读取:read(byte[ ] b),每次读取b的长度个字节到数组中,返回读取到的有效字节个数,读取到末尾时,返回-1,代码如下:
public class FISRead {
    public static void main(String[] args) throws IOException{
       // 使用文件名称创建流对象.  
       FileInputStream fis = new FileInputStream("read.txt"); // 文件中为abcde 
       // 定义变量,作为有效个数  
        int len ;
        // 定义字节数组,作为装字节数据的容器  
        byte[] b = new byte[2];
        // 循环读取
        while (( len= fis.read(b))!=1) {
           // 每次读取后,把数组变成字符串打印 
            System.out.println(new String(b));
        }
// 关闭资源        
        fis.close();
    }
}

输出结果:
ab
cd
ed

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

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

输出结果:
ab
cd
e

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

eg.图片复制
复制原理

在这里插入图片描述

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

字节缓冲流(BufferedInputStream)

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

构造方法

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

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

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

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

public class BufferedDemo {
    public static void main(String[] args) throws FileNotFoundException {
        // 记录开始时间
       long start = System.currentTimeMillis();  
// 创建流对象        
        try (
         FileInputStream fis = new FileInputStream("jdk8.exe");    
         FileOutputStream fos = new FileOutputStream("copy.exe")    
        ){
         // 读写数据    
            int b;
            while ((b = fis.read()) !=1) {
                fos.write(b);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
// 记录结束时间        
        long end = System.currentTimeMillis();
        System.out.println("普通流复制时间:"+(end ‐ start)+" 毫秒");
    }
}
十几分钟过去了...

        现在给大家演示一下缓冲流执行相同的内容

public class BufferedDemo {
    public static void main(String[] args) throws FileNotFoundException {
        // 记录开始时间
       long start = System.currentTimeMillis();  
// 创建流对象        
        try (
         BufferedInputStream bis = new BufferedInputStream(new FileInputStream("jdk8.exe"));    
     BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy.exe"));    
        ){
        // 读写数据
            int b;
            while ((b = bis.read()) !=1) {
                            bos.write(b);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
// 记录结束时间        
        long end = System.currentTimeMillis();
        System.out.println("缓冲流复制时间:"+(end ‐ start)+" 毫秒");
    }
}
缓冲流复制时间:8016 毫秒

        没有对比就没有伤害,缓冲流仿佛是别人家的孩子般那么六的一匹;其实,如果再加上使用数组的方式,那么可能就是神人般的存在了。举例如下:

public class BufferedDemo {
    public static void main(String[] args) throws FileNotFoundException {
       // 记录开始时间  
        long start = System.currentTimeMillis();
// 创建流对象        
        try (
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("jdk8.exe"));            
 BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy.exe"));        
        ){
           // 读写数据  
            int len;
            byte[] bytes = new byte[8*1024];
            while ((len = bis.read(bytes)) !=1) {
                bos.write(bytes, 0 , len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
// 记录结束时间        
        long end = System.currentTimeMillis();
        System.out.println("缓冲流使用数组复制时间:"+(end ‐ start)+" 毫秒");
    }
}
缓冲流使用数组复制时间:666 毫秒

        是否被震惊到了呢?
        好了,接下来介绍一下打印流(PrintStream);

打印流(PrintStream)

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

构造方法

        public PrintStream(String fileName):使用指定的文件名创建一个新的打印流
        如下例子:

PrintStream ps = new PrintStream("ps.txt")

        就是将内容输入到一个名为ps的txt文本中去。
        System.out就是PrintStream类型的,只不过它的流向是系统规定的,即打印到控制台上,不过,既然是流对象,我们就可以玩一个“小把戏”,就是将数据输出到指定文本文件中。

public class PrintDemo {
    public static void main(String[] args) throws IOException {
// 调用系统的打印流,控制台直接输出97        
        System.out.println(97);
     
// 创建打印流,指定文件的名称        
        PrintStream ps = new PrintStream("ps.txt");
       
       // 设置系统的打印流流向,输出到ps.txt  
        System.setOut(ps);
       // 调用系统的打印流,ps.txt中输出97  
        System.out.println(97);
    }
}

总结

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

end

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

猜你喜欢

转载自blog.csdn.net/Luojun13Class/article/details/88415925