IO流的分类与字节流

IO流的分类与字节流:

- 流向:
- 输入流 读取数据
- 输出流 写出数据

- 数据类型:
- 字节流
- 字节输入流 读取数据 InputStream
- 字节输出流 写出数据 OutputStream

- 字符流
- 字符输入流 读取数据 Reader
- 字符输出流 写出数据 Writer

字符流存在的问题
        * 字符流只能操作文本文件,如果操作非文本文件(图片,视频,音频)等文件,会出现数据丢失问题。
        * 如果要操作非文本文件,只能使用字节流,因为字节流可以操作任意类型的文件。

OutputStream类概述

​ * Output:输出 * Stream:字节流 * 是一个字节流。 * 是一个抽象类,不能直接创建该类的对象。 * 是所有字节输出流的父类。

OutputStream类常用的子类
    * FileOutputStream
    * BufferedOutputStream

FileOutputStream类构造方法


* FileOutputStream(String pathname) 根据文件路径创建文件字节输出流对象

* FileOutputStream(File file)  根据文件对象创建文件字节输出流对象

* FileOutputStream(File file, boolean append) 
    
* FileOutputStream(String pathname, boolean append) 
        * 可以通过 append 指定是否是追加输出
        * append:true表示追加,false表示不追加。
        

字节输出流操作步骤:


 *   A:创建字节输出流对象
 //FileOutputStream(File file)
 File file = new File("a.txt");
 FileOutputStream fos = new FileOutputStream(file);

 //FileOutputStream(String name)
 FileOutputStream fos = new FileOutputStream("a.txt");

创建字节输出流对象了做了几件事情:
   1.调用系统功能去创建文件
   2.创建fos对象
   3.把fos对象指向这个文件


 *   B:写数据
  fos.write("hello,IO".getBytes());
  fos.write("12345678".getBytes());

 *   C:释放资源
 //关闭此文件输出流并释放与此流有关的所有系统资源。
  fos.close();
字节输出流写数据
 
 * public void write(int b):写一个字节
 
 * public void write(byte[] b):写一个字节数组
 
 * public void write(byte[] b,int off,int len):
            * 将字节数组b的一部分内容输出到目标文件中
            * off:数组的起始索引
            * len:要输出的字节个数
 

    public static void main(String[] args) throws IOException {

        // 创建字节输出流对象
        FileOutputStream fos = new FileOutputStream("test\\a.txt");

        // public void write(int b):写一个字节
        fos.write(97); // 97 -- 底层二进制数据 -- 通过记事本打开 -- 找97对应的字符值 -- a
        
        fos.write('\r');//\r\n为换行
        fos.write('\n');
        
        fos.write(65);//A

        fos.write(256+66);//B

        // public void write(byte[] b):写一个字节数组

        byte[] bys = { 97, 98, 99, 100, 101 };

        fos.write(bys);

        // public void write(byte[] b,int off,int len):写一个字节数组的一部分
        fos.write(bys, 1, 3);

        // 释放资源
        fos.close();

    }

 * 如何实现数据的换行?
 *   因为不同的系统针对不同的换行符号识别是不一样的?
 *   windows:\r\n
 *   linux:\n
 *   Mac:\r
 
 * 如何实现数据的追加写入?
 *   用构造方法带第二个参数是true的情况即可

加入异常处理的字节输出流操作
public static void main(String[] args) {
        
        // 为了在finally里面能够看到该对象就必须定义到外面,为了访问不出问题,还必须给初始化值
        FileOutputStream fos = null;
        
        try {

            fos = new FileOutputStream("a.txt");
            
            fos.write("java".getBytes());
            
        } catch (FileNotFoundException e) {
            
            e.printStackTrace();
            
        } catch (IOException e) {
            
            e.printStackTrace();
            
        } finally {
            // 如果fos不是null,才需要close()
            if (fos != null) {
                // 为了保证close()一定会执行,就放到这里了
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                    
                }
            }
        }
    }
// 利用字节输出流一次写一个字节数组的方式向C盘的b.txt文件输出内容。
    public static void main(String[] args) throws IOException {
        // 1.创建字节输出流FileOutputStream对象并指定文件路径。
        FileOutputStream fos = new FileOutputStream("c:/b.txt");
        // 2.调用字节输出流的write(byte[] buf)方法写出数据。
        byte[] buf = "i love java".getBytes();
        fos.write(buf);
        // 3.关闭资源
        fos.close();
    }

字节输入流操作步骤:

 * A:创建字节输入流对象
 
 FileInputStream fis = new FileInputStream("a.txt");


 * B:调用read()方法读取数据,并把数据显示在控制台
 int by = 0;
  // 读取,赋值,判断
  while ((by = fis.read()) != -1) {
   System.out.print((char) by);
  }

// 数组的长度一般是1024或者1024的整数倍
  byte[] bys = new byte[1024];
  int len = 0;
  while ((len = fis.read(bys)) != -1) {
   System.out.print(new String(bys, 0, len));
  }

 
 * C:释放资源
 fis.close();

字节输入流读取数据:
 
* abstract int read(); 从流关联的目标文件中读取一个字节,返回读取到的字节

* int read(byte[] b); 
       * 从流关联的目标文件中读取一个字节数组的数据,
       * 返回实际读取到字节个数。
       
* int read(byte[] b, int off, int len) 
         * 将读取到的字节存储到指定的字节数组b中
         * off:存储字节的起始索引
         * len:指定能够存储的字节个数。

 int by = 0;
  // 读取,赋值,判断
  while ((by = fis.read()) != -1) {
   System.out.print((char) by);
  }

// 数组的长度一般是1024或者1024的整数倍
  byte[] bys = new byte[1024];
  int len = 0;
  while ((len = fis.read(bys)) != -1) {
   System.out.print(new String(bys, 0, len));
  }

    /* 用字节流将C盘下的a.png图片复制到D盘下(文件名保存一致)
        要求:一次读写一个字节数组的方式进行复制
    */
    public static void main(String[] args) throws IOException {
        // 创建字节输入流对象并关联文件
        FileInputStream fis = new FileInputStream("c:/a.png");
        // 创建字节输出流对象并关联文件
        FileOutputStream fos = new FileOutputStream("d:/a.png");
        // 定义数据接收读取的字节数
        byte[] buffer = new byte[1024];
        // 定义变量接收读取的字节数
        int len = -1;
        // 循环读取图片数据
        while((len = fis.read(buffer)) != -1) {
            // 将字节数组中的数据写出到目标文件中
            fos.write(buffer,0,len);
        }
        // 关闭流
        fis.close();
        fos.close();
    }

缓冲区类(高效类)


 * 写数据:BufferedOutputStream
 
 * 读数据:BufferedInputStream

 构造方法可以指定缓冲区的大小,但是我们一般用不上,因为默认缓冲区大小就已经足够了。
 
 为什么不传递一个具体的文件或者文件路径,而是传递一个OutputStream对象呢?
 * 原因很简单,字节缓冲区流仅仅提供缓冲区,为高效而设计的。但是呢,真正的读写操作还得靠基本的流对象实现。



 BufferedOutputStream类注意事项
        * 使用缓冲字节输出流输出数据不是直接输出到目标文件中,而是先存储到内部的缓冲区
        数组中,当缓冲区数组满了或调用了flush或close方法,则由FileOutputStream将缓冲
        区数组的数据输出到目标文件中。
    
    记忆技巧
        * BufferedOutputStream的使用方式除了构造方法和FileOutputStream不一样之外,其他完全一样。
 
  
BufferedInputStream类注意事项
        * 字节缓冲输入流读取数据不是直接从目标文件中读取,而是从内部的缓冲区数组中读取,
        * 如果缓冲区数组没有内容或者读完了,则会通过FileInputStream从目标文件中
        一次读取8192个字节数据到缓冲区数组中。
    
    记忆技巧
        * BufferedInputStream的使用方式除了构造方法和FileInputStream不一样之外,其他完全一样。

操作步骤:
 * A:创建对象
BufferedOutputStream bos = new BufferedOutputStream( new FileOutputStream("a.txt"));

BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.txt"));

 * B:读写操作
 //高效字节流一次读写一个字节:
 int by = 0;
  while ((by = bis.read()) != -1) {
   bos.write(by);
  }

 // 高效字节流一次读写一个字节数组:
 byte[] bys = new byte[1024];
  int len = 0;
  while ((len = bis.read(bys)) != -1) {
   bos.write(bys, 0, len);
  }


 * C:释放资源
  bos.close();
  bis.close();

四种文件复制方式的效率比较

    public static void main(String[] args) throws IOException{
        System.out.println("字节流复制文件一次读写一个字节耗时:"+ copy01());
        System.out.println("字节流复制文件一次读写一个字节数组耗时:"+ copy02());
        System.out.println("高效流复制文件一次读写一个字节耗时:"+ copy03());
        System.out.println("高效流复制文件一次读取一个字节数组耗时:"+ copy04());
    }
    // 字节流复制文件一次读写一个字节
    public static long copy01() throws IOException{
        // 获得当前时间毫秒值
        long startTime = System.currentTimeMillis();
        // 创建字节输入流对象并关联文件
        FileInputStream fis = new FileInputStream("aaa.jpg");
        // 创建字节输出流对象并关联文件
        FileOutputStream fos = new FileOutputStream("ttt.jpg");
        // 定义变量接收读取的字节数
        int len = -1;
        // 循环读取图片数据
        while((len = fis.read()) != -1) {
            // 每读取一个字节的数据就写出到目标文件中
            fos.write(len);
        }
        // 关闭流
        fis.close();
        fos.close();
        return System.currentTimeMillis() - startTime;
    }
    
    // 字节流复制文件一次读写一个字节数组
    public static long copy02() throws IOException{
        // 获得当前时间毫秒值
        long startTime = System.currentTimeMillis();
        // 创建字节输入流对象并关联文件
        FileInputStream fis = new FileInputStream("aaa.jpg");
        // 创建字节输出流对象并关联文件
        FileOutputStream fos = new FileOutputStream("eee.jpg");
        // 定义数据接收读取的字节数
        byte[] buffer = new byte[1024];
        // 定义变量接收读取的字节数
        int len = -1;
        // 循环读取图片数据
        while((len = fis.read(buffer)) != -1) {
            // 将字节数组中的数据写出到目标文件中
            fos.write(buffer,0,len);
        }
        // 关闭流
        fis.close();
        fos.close();
        return System.currentTimeMillis() - startTime;
    }
    
    // 高效流复制文件一次读写一个字节
    public static long copy03() throws IOException{
        // 获得当前时间毫秒值
        long startTime = System.currentTimeMillis();
        // 创建字节输入流对象并关联文件路径
        FileInputStream fis = new FileInputStream("aaa.jpg");
        // 利用字节输出流对象创建高效字节输出流对象
        BufferedInputStream bis = new BufferedInputStream(fis);
        // 创建字节输出流对象并指定文件路径。
        FileOutputStream fos = new FileOutputStream("jjj.jpg");
        // 利用字节输出流创建高效字节输出流对象
        BufferedOutputStream bos = new BufferedOutputStream(fos);
        // 定义变量接收读取的字节数
        int len = -1;
        // 循环读取图片数据
        while((len = bis.read()) != -1) {
            // 每读取一个字节的数据就写出到目标文件中
            bos.write(len);
        }
        // 关闭流
        bis.close();
        bos.close();
        return System.currentTimeMillis() - startTime;
    }
    
    // 高效流复制文件一次读取一个字节数组
    public static long copy04() throws IOException{
        // 获得当前时间毫秒值
        long startTime = System.currentTimeMillis();
        // 创建字节输入流对象并关联文件路径
        FileInputStream fis = new FileInputStream("aaa.jpg");
        // 利用字节输出流对象创建高效字节输出流对象
        BufferedInputStream bis = new BufferedInputStream(fis);
        // 创建字节输出流对象并指定文件路径。
        FileOutputStream fos = new FileOutputStream("ddd.jpg");
        // 利用字节输出流创建高效字节输出流对象
        BufferedOutputStream bos = new BufferedOutputStream(fos);
        // 定义字节数组接收读取的字节
        byte[] buffer = new byte[1024];
        // 定义变量接收读取的字节数
        int len = -1;
        // 循环读取图片数据
        while((len = bis.read(buffer)) != -1) {
            // 每读取一个字节的数据就写出到目标文件中
            bos.write(buffer,0,len);
        }
        // 关闭流
        bis.close();
        bos.close();
        return System.currentTimeMillis() - startTime;
    }
  • 结论:推荐使用缓冲流来操作文件。

flush方法和close方法区别

  • flush用来刷新缓冲区,将缓冲区中的数据输出到目标文件中,流还可以继续使用。

  • close用来关闭流释放资源,如果流是带缓冲区,则在关闭流之前会调用flush方法刷新缓冲区,流不可以再次使用。

计算机是如何识别什么时候该把两个字节转换为一个中文呢?

 * 在计算机中中文的存储分两个字节:
 *   第一个字节肯定是负数。
 *   第二个字节常见的是负数,可能有正数。但是没影响。
 
 * String(byte[] bytes, String charsetName):通过指定的字符集解码字节数组
 * byte[] getBytes(String charsetName):使用指定的字符集合把字符串编码为字节数组
 * 
 * 编码:把看得懂的变成看不懂的
 * String -- byte[]
 * 
 * 解码:把看不懂的变成看得懂的
 * byte[] -- String

 
        String s = "好好学习";

        byte[] bys = s.getBytes();

        System.out.println(Arrays.toString(bys));
        
        String ss = new String(bys, "GBK"); 

        System.out.println(ss);

编码读写数据:


 * InputStreamReader(InputStream is):用默认的编码读取数据

 * InputStreamReader(InputStream is,String charsetName):用指定的编码读取数据 

 * OutputStreamWriter(OutputStream out):根据默认编码把字节流的数据转换为字符流
 
 * OutputStreamWriter(OutputStream out,String charsetName):根据指定编码把字节流数据转换为字符流
 
 * 把字节流转换为字符流。
 * 字符流 = 字节流 +编码表。

操作步骤:
 
* A:创建对象

 InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"), "UTF-8");

 OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("a.txt"), "GBK"); 



 * B:读写操作
 //一次读写一个字符:
 int by = 0;
  while ((by = isr.read()) != -1) {
   osw.write(by);
  }

 // 一次读写一个字符数组:
 byte[] bys = new byte[1024];
  int len = 0;
  while ((len = isr.read(bys)) != -1) {
   osw.write(bys, 0, len);
  }


 * C:释放资源
  osw.close();
  isr.close();

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值