Java IO流

IO流

1.概述

1.1 什么是 IO 流?

  存储和读取数据的解决方案
  I : input
  O : output
  流:像水流一样传输数据

1.2 IO 流的作用?

  用于读写数据 ( 本地文件,网络 )

1.3 IO 流的分类?
1. IO 流按照**流向**可以分类哪两种流?==主体是程序==
	  输出流 : 程序  =>  文件
	  输入流 : 文件  => 程序
2.  IO 流按照**操作文件**的类型可以分类哪两种流?
	  字节流 : 可以操作所有类型的文件
	  字符流 : 只能操作纯文本文件
1.4 什么是纯文本文件?

用 windows 系统自带的记事本打开并且能读懂的文件 txt 文件,md文件,xml 文件,lrc 文件等。

1.5 IO 流的体系结构

IO流的体系结构

2.字节流

字节流的系统架构

2.1 FileOutputStream
  1. FileOutputStream的书写细节

    package com.str.box;
    
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class demo01 {
        public static void main(String[] args) throws IOException {
        /*
        * 字节输出流 FileOutputStream
        * 实现需求:写出一段文字到本地文件中 (暂时不写中文)
        * 实现步骤:
        *        1.创建对象
        *           细节1:参数是字符串表示的路径或者是File对象都是可以的。
        *           细节2:如果文件不存在会创建一个新的文件,但是要保证父级路径是存在的
        *           细节3:如果文件已经存在,则会清空文件
        *        2.写出数据
        *           细节:write方法的参数是整数,但是实际上写到本地文件中的是整数在ASCII上对应的字符
        *        3.释放资源
        *           细节:每次使用完流之后都要释放资源
        * */
    
            // 1.创建对象:指定文件的相对路径
            FileOutputStream fos = new FileOutputStream("D:\\笔记\\Java笔记\\JavaSE\\IO流\\ByteStreamDemo01\\a.txt");
    
            // 2.写出数据
            fos.write(97);
            fos.write(57);
            fos.write(55);
            // 3.释放资源
            fos.close();
        }
    }
    
  2. FileOutputStream写数据的3种方式
    字节输出流的方法

 package com.str.box;
 
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
 
 public class demo02 {
     public static void main(String[] args) throws IOException {
 
         // 1.创建对象
         FileOutputStream fos = new FileOutputStream("D:\\笔记\\Java笔记\\JavaSE\\IO流\\ByteStreamDemo01\\a.txt");
         // 2.写出数据
         fos.write(97);  //a
         fos.write(98);  //b
 
         byte[] bytes = {97,98,99,100,101};
         fos.write(bytes);
         fos.write(bytes,0,2);
         // 3.释放资源
         fos.close();
     }
 }
  1. 换行写、续写
 package com.str.box;
   
   import java.io.FileNotFoundException;
   import java.io.FileOutputStream;
   import java.io.IOException;
   
   public class demo04 {
       public static void main(String[] args) throws IOException {
   
           /*换行写:再次写出一次换行符即可
           * Windows: \r\n
           * Linux:    \n
           * Mac:     \r
           * 细节:
           *       在windows操作系统当中,java对回车换行进行了优化,
           *       虽然完整的是\r\n,但是我们写其中一个\r或者\n,
           *       java也可以实现换行,因为java在底层会补全
           * 建议: 不要省略,还是写全。
           * */
           /*
           * 续写(追加写入):
           *       如果想要续写,打开续写开关即可开关位置:创建对象的第二个参数默认
           *       false:表示关闭续写,此时创建对象会清空文件
           *       手动传递true:表示打开续写,此时创建对象不会清空文件
           * */
   
           // 1.创建对象
           FileOutputStream fos = new FileOutputStream("D:\\笔记\\Java笔记\\JavaSE\\IO流\\ByteStreamDemo01\\a.txt",true);
           // 2.写出数据
           String str = "kankelaoyezuishuai";
           byte[] bytes1 = str.getBytes();
           fos.write(bytes1);
           
           String wrap = "\r\n";
           byte[] bytes = wrap.getBytes();
           fos.write(bytes);
   
           String str2 = "666";
           byte[] bytes2 = str2.getBytes();
           fos.write(bytes2);
           // 3.释放资源
           fos.close();
       }
   }
2.2 FileInputStream

操作本地文件的字节输入流,可以把本地文件中的数据读取到程序中。

package com.str.box.FileIntputStream;

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

public class demo01 {
    public static void main(String[] args) throws IOException {
        /*
        * 字节输入流 FileInputStream
        * 实现需求:读取文件中的数据(暂时不写中文)
        * 实现步骤:
        *       创建对象;读取数据;释放资源
        * */

        FileInputStream fis = new FileInputStream("D:\\笔记\\Java笔记\\JavaSE\\IO流\\ByteStreamDemo01\\a.txt");
        int b1 = fis.read();
        System.out.println(b1);
        System.out.println((char) b1);
        fis.close();

    }
}
  1. 字节输入流的细节
  1. 创建字节输入流对象
      细节1 : 如果文件不存在,就直接报错;Java为什么会这么设计呢?
      输出流 : 不存在,创建文件并把数据写到文件当中
      输入流 : 不存在,因为创建出来的文件是没有数据的,没有读取的意义。所以Java就没有设计这种无意义的逻辑,文件不存在直接报错。
  2. 写数据
    细节1 : 一次读一个宁节,读出来的是数据在ASCII上对应的数
    细节2 : 读到文件末尾了,read方法返回 -1
  3. 释放资源
    细节:每次使用完流之后都要释放资源
  1. FileInputStream的循环读取
   package com.str.box.FileIntputStream;
   
   import java.io.FileInputStream;
   import java.io.FileNotFoundException;
   import java.io.IOException;
   
   public class demo02 {
       public static void main(String[] args) throws IOException {
           FileInputStream fis = new FileInputStream("D:\\笔记\\Java笔记\\JavaSE\\IO流\\ByteStreamDemo01\\a.txt");
           // 2. 循环读取
           int b;
           while ((b = fis.read()) != -1){
               System.out.print((char) b);
           }
           /*read:表示读取数据,而且是读取一个数据就移动一次指针
           * */
           
           fis.close();
       }
   }
2.3 文件拷贝
  1. 文件拷贝的基本代码
package com.str.box.FileIntputStream;
   
   import java.io.FileInputStream;
   import java.io.FileNotFoundException;
   import java.io.FileOutputStream;
   import java.io.IOException;
   
   public class demo03 {
       public static void main(String[] args) throws IOException {
           /*
           * 文件拷贝
           * 把D:\练习\电赛\预览效果.mp4拷贝到当前模块下
           *
           * 注意:
           *     选择一个比较小的文件,不要太大。大文件拷贝看下一个demo
           * */
   
           // 1.创建对象
           FileInputStream fis = new FileInputStream("D:\\练习\\电赛\\预览效果.mp4");
           FileOutputStream fos = new FileOutputStream("D:\\笔记\\Java笔记\\JavaSE\\IO流\\ByteStreamDemo01\\copy.mp4");
   
           // 2.拷贝
           // 核心思想:边读边写
           int b;
           while ((b = fis.read()) != -1){
               fos.write(b);
           }
   
           // 3.释放资源
           // 规则:先开的最后关闭
           fos.close();
           fis.close();
       }
   }
  1. FileInputStream

  2. FileInputStream

  3. package com.str.box.FileIntputStream;
    
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class demo05 {
        public static void main(String[] args) throws IOException {
            /* demo03改进版
             * 文件拷贝
             * 把D:\练习\电赛\预览效果.mp4拷贝到当前模块下
             *
             * 注意:
             *     选择一个比较小的文件,不要太大。大文件拷贝看下一个demo
             * */
    
            long start = System.currentTimeMillis();
    
            // 1.创建对象
            FileInputStream fis = new FileInputStream("D:\\练习\\电赛\\预览效果.mp4");
            FileOutputStream fos = new FileOutputStream("D:\\笔记\\Java笔记\\JavaSE\\IO流\\ByteStreamDemo01\\copy.mp4");
    
            // 2.拷贝
            int len;
            byte[] bytes = new byte[1024 * 1024 * 5];
            while ((len = fis.read(bytes)) != -1){
                fos.write(bytes,0,len);
            }
    
            // 3.释放资源
            fos.close();
            fis.close();
    
            long end = System.currentTimeMillis();
            // 拷贝时间
            System.out.println(end-start);
        }
    }
    
2.4 IO 流中不同的JDK版本捕获异常的方法
  1. try....catch
    try

  2. package com.str.box.FileIntputStream;
    
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class demo06 {
        public static void main(String[] args){
            /*
            * 利用try...catch...finally捕获拷贝文件中代码出现的异常
            * */
            FileInputStream fis = null;
            FileOutputStream fos = null;
    
            try {
                // 1.创建对象
                fis = new FileInputStream("D:\\练习\\电赛\\预览效果.mp4");
                fos = new FileOutputStream("D:\\笔记\\Java笔记\\JavaSE\\IO流\\ByteStreamDemo01\\copy.mp4");
                // 2.拷贝
                int len;
                byte[] bytes = new byte[1024 * 1024 * 5];
                while ((len = fis.read(bytes)) != -1){
                    fos.write(bytes,0,len);
                }
            }catch (IOException e){
                e.printStackTrace();
            }finally {
                // 3.释放资源
                if (fos != null){
                    try {
                        fos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (fis != null){
                    try {
                        fis.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    
  • 接口:AutoCloseable
  • 特点:特定情况下,可以自动释放资源
    异常处理

3. 字符集

3.1 字节流读取中文会出现乱码
  • 计算机存储:最小存储单元:字节
  • 读取数据时未读完整个汉字(字节流一次读取一个字节,汉字在字符集中为三个或者2个字节)
  • 编码和解码时的方式不统一
  • 字节流读取中文会乱码,但是拷贝的时候为什么不会乱码?(因为没有丢失数据,同时记事本使用同一种字符集)
3.2 ASCII字符集

在这里插入图片描述

2.3 GB*字符集

在这里插入图片描述
在这里插入图片描述在这里插入图片描述在这里插入图片描述

2.4 Unicode 字符集

Unicode : 万国码
研发方 : 统一码联盟(也叫Unicode组织)
总部位置 : 美国加州
研发时间 : 1990年
发布时间 : 1994年发布1.0版本,期间不断添加新的文字
最新的版本是2022年9月13日发布的15.0版本
联盟组成,世界各地主要的电脑制造商、软件开发商、数据库开发商、政府部门、研究机构、国际机构、及个人组成
Unicode

UTF-8不是一个字符集,是Unicode的一种编码方式。

  • Unicode 字符集的 UTF-8 编码格式
  • 一个英文占一个字节,二进制第一位是0,转成十进制是正数
  • 一个中文占三个字节,二进制第一位是1,第一个字节转成十进制是负数
2.5 Java中编码和解码的代码实现
  1. package com.str.box.Charset;
    
    import java.io.UnsupportedEncodingException;
    import java.util.Arrays;
    
    public class demo01 {
        public static void main(String[] args) throws UnsupportedEncodingException {
            /*
            * Java中编码的方法
                public byte[] getBytes()                        使用默认方式进行编码
                public byte[] getBytes(String charsetName)      使用指定方式进行编码
    
            Java中解码的方法
                    String(byte[] bytes)                        使用默认方式进行解码
                    String(byte[] bytes, string charsetName)    使用指定方式进行解码
            * */
    
            // 1.编码
            String str = "bala巴拉";
            byte[] bytes1 = str.getBytes();
            System.out.println(Arrays.toString(bytes1));
    
            byte[] bytes2 = str.getBytes("GBK");
            System.out.println(Arrays.toString(bytes2));
    
            // 2.解码
            String str2 = new String(bytes1);
            System.out.println(str2);
    
            String str3 = new String(bytes1,"GBK");
            System.out.println(str3);
        }
    }
    

4. 字符流

4.1 字符流的概述

在这里插入图片描述

4.2 字符流的体系架构

字符流体系架构
在这里插入图片描述

4.3 FileReader
  1. package com.str.box.FileReader;
    
    import java.io.FileNotFoundException;
    import java.io.FileReader;
    import java.io.IOException;
    
    public class demo01 {
        public static void main(String[] args) throws IOException {
    
            // 1.创建对象关联读取本地文件
            FileReader fileReader = new FileReader("D:\\笔记\\Java笔记\\JavaSE\\IO流\\ByteStreamDemo01\\a.txt");
            // 2.读取数据 read()
            // 字符流的底层也是字节流,默认一个字节一个字节的读取的,如果遇到中文就会一次读取多个字节;
            // GBK字符集:一次读取两个字节;UTF_8:一次读取三个字节
            
            /* read的细节
            *  1.read():默认也是一个字节一个字节读取的,如果遇到中文就会一次性的读取多个
            *  2.在读取之后,read方法的底层还会进行解码并转出十进制
            *   最终把这个十进制的数据也表示在字符集上的数字
            *  3.想看到中文的汉字,就要把这些十进制数据在进行强转即可。
            * */
            int ch;
            while ((ch = fileReader.read())!= -1){
                System.out.print((char) ch);
            }
            // 3.释放资源
            fileReader.close();
    
        }
    }
    
  2. package com.str.box.FileReader;
    
    import java.io.FileNotFoundException;
    import java.io.FileReader;
    import java.io.IOException;
    
    public class demo02 {
        public static void main(String[] args) throws IOException {
    
            // 1.创建对象关联读取本地文件
            FileReader fileReader = new FileReader("D:\\笔记\\Java笔记\\JavaSE\\IO流\\ByteStreamDemo01\\a.txt");
            // 2.读取数据
            // read(char):读取数据,解码,强转三步合并了,把强转之后的字符放到数组当中
            char[] chars = new char[2];
            int len;
            while ((len=fileReader.read(chars)) != -1){
                // 把数组中的数据变成字符串在进行打印
                System.out.print(new String(chars,0,len));
            }
        }
    }
    
    
4.4 FileWriter

构造方法
成员方法

  package com.str.box.FileWriter;
  
  import java.io.FileWriter;
  import java.io.IOException;
  
  public class demo01 {
      public static void main(String[] args) throws IOException {
  
          // 1.构造
          FileWriter fileWriter = new FileWriter("D:\\笔记\\Java笔记\\JavaSE\\IO流\\ByteStreamDemo01\\a.txt");
          //fileWriter.write(25105);
          //fileWriter.write("白日依山尽,");
          char[] chars = {'白','日','依','山','尽'};
          fileWriter.write(chars);
          fileWriter.close();
      }
  }
  1. 内存有缓存区,每次从缓冲区读取数据,增加读取速率。
    字符流原理
 package com.str.box.FileWriter;
 
 import java.io.FileNotFoundException;
 import java.io.FileReader;
 import java.io.FileWriter;
 import java.io.IOException;
 
 public class demo02 {
     public static void main(String[] args) throws IOException {
 
         FileReader fileReader = new FileReader("D:\\笔记\\Java笔记\\JavaSE\\IO流\\ByteStreamDemo01\\a.txt");
         fileReader.read();      // 会把文件中的数据放到缓冲区当中
 
         // 清空文件
         FileWriter fileWriter = new FileWriter("D:\\笔记\\Java笔记\\JavaSE\\IO流\\ByteStreamDemo01\\a.txt");
 
         // 请问,如果我再次使用fileReader进行读取,会读取到数据嘛?
         // 正确答案:会,但是只能读取到缓存区中的数据,文件中剩余的数据无法再次读取。
         int  ch;
         while ((ch = fileReader.read()) != -1){
             System.out.println((char) ch);
         }
 
         fileWriter.close();
         fileReader.close();
     }
 }
  1. flush()和close()的区别
    flush和close方法

5. 字节流和字符流的应用场景

应用场景

  • package com.str.box.FileWriter;
    
    import java.io.*;
    
    public class demo03 {
        public static void main(String[] args) throws IOException {
            // 拷贝一个文件夹,考虑子文件夹
    
            // 1.创建对象表示数据源
            File src = new File("D:\\笔记\\Java笔记\\JavaSE\\IO流\\ByteStreamDemo01\\src");
            // 2.创建对象表示目的地
            File dest = new File("D:\\笔记\\Java笔记\\JavaSE\\IO流\\ByteStreamDemo01\\dest");
    
            // 3.调用方法开始拷贝
            copydir(src,dest);
        }
    
        /*
        * 作用:拷贝文件夹
        * 参数一:数据源
        * 参数二:目的地
        * */
        private static void copydir(File src, File dest) throws IOException {
            dest.mkdir();
            // 递归
            // 1.进入数据源
            File[] files = src.listFiles();
            // 2.遍历数组
            for (File file : files) {
                if (file.isFile()){
                    // 3.判断文件,拷贝,文件开始,文件结束
                    FileInputStream fis = new FileInputStream(file);
                    FileOutputStream fos = new FileOutputStream(new File(dest,file.getName()));
                    byte[] bytes = new byte[1024];
                    int len;
                    while ((len = fis.read(bytes)) != -1){
                        fos.write(bytes,0,len);
                    }
                    fos.close();
                    fis.close();
                }else {
                    // 4.pd文件夹,递归
                    copydir(file,new File(dest,file.getName()));
                }
            }
        }
    }
    
  • 文件加密
    为了保证文件的安全性,就需要对原始文件进行加密存储,再使用的时候再对其进行解密处理
    加密原理:
      对原始文件中的每一个字节数据进行更改,然后将更改以后的数据存储到新的文件中
    解密原理:
      读取加密之后的文件,按照加密的规则反向操作,变成原始文件

  • package com.str.box.FileWriter;
    
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class demo04 {
        public static void main(String[] args) throws IOException {
    
            /*
            *  ^ 异或
            *  两边相同:false 0
            *  两边不同:TRUE  1
            *
            *
            System.out.println(100^10); // 110
            System.out.println(110^10); // 100
            * */
    
    /*      FileInputStream fis = new FileInputStream("D:\\笔记\\Java笔记\\JavaSE\\IO流\\ByteStreamDemo01\\1.png");
            FileOutputStream fos = new FileOutputStream("D:\\笔记\\Java笔记\\JavaSE\\IO流\\ByteStreamDemo01\\ency.png");
           */
            FileInputStream fis = new FileInputStream("D:\\笔记\\Java笔记\\JavaSE\\IO流\\ByteStreamDemo01\\ency.png");
            FileOutputStream fos = new FileOutputStream("D:\\笔记\\Java笔记\\JavaSE\\IO流\\ByteStreamDemo01\\redu.png");
    
            int b;
            while ((b= fis.read()) != -1){
                fos.write(b^2);
            }
    
            fos.close();
            fis.close();
        }
    }
    

练习:修改文件中的数据
文本文件中有以下的数据 : 2-1-9-4-7-8
将文件中的数据进行排序,变成以下的数据 : 1-2-4-7-8-9

  • package com.str.box.FileWriter;
    
    import java.io.FileReader;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.Collections;
    
    public class demo05 {
        public static void main(String[] args) throws IOException {
    
            // 1.读取数据
            FileReader reader = new FileReader("D:\\笔记\\Java笔记\\JavaSE\\IO流\\ByteStreamDemo01\\a.txt");
            StringBuilder sb = new StringBuilder();
            int ch;
            while ((ch = reader.read()) != -1){
                sb.append((char) ch);
            }
            reader.close();
            System.out.println(sb);
    
            // 2.排序
            String str = sb.toString();
            String[] arrStr = str.split("-");
            ArrayList<Integer> list = new ArrayList<>();
            for (String s : arrStr) {
                int i = Integer.parseInt(s);
                list.add(i);
            }
            Collections.sort(list);
            System.out.println(list);
    
            // 3.写入
            FileWriter fw = new FileWriter("D:\\笔记\\Java笔记\\JavaSE\\IO流\\ByteStreamDemo01\\a.txt");
            for (int i = 0; i < list.size(); i++) {
                if (i == list.size()-1){
                    fw.write(list.get(i)+"");
                }else {
                    fw.write(list.get(i)+"-");
                }
            }
            fw.close();
        }
    }
    
  • 改进版:

    package com.str.box.FileWriter;
    
    import java.io.FileReader;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.util.Arrays;
    import java.util.stream.Stream;
    
    public class demo06 {
        public static void main(String[] args) throws IOException {
            // 1.读取数据
            FileReader fr = new FileReader("D:\\笔记\\Java笔记\\JavaSE\\IO流\\ByteStreamDemo01\\a.txt");
            StringBuilder sb = new StringBuilder();
            int ch;
            while ((ch = fr.read()) != -1){
                sb.append((char) ch);
            }
            fr.close();
            System.out.println(sb);
    
            // 2.排序
            Integer[] arr = Arrays.stream(sb.toString()
                            .split("-"))
                            .map(Integer::parseInt)
                            .sorted().
                            toArray(Integer[]::new);
            System.out.println(Arrays.toString(arr));
    
            // 3.写入
            FileWriter fw = new FileWriter("D:\\笔记\\Java笔记\\JavaSE\\IO流\\ByteStreamDemo01\\a.txt");
            String s = Arrays.toString(arr).replace(",","-");
            String result = s.substring(1,s.length()-1);
            fw.write(result);
            fw.close();
        }
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值