第十一章 存储&读写数据的方案(File、IO流)

一、存储数据的方案(内存中和磁盘中)

内存中:
在这里插入图片描述
磁盘中:
在这里插入图片描述

1.1 什么是File?

在这里插入图片描述

1.2 什么是IO流?有什么作用?

由于File只能对文件本身进行操作,不能读写文件里面存储的数据,为了解决这个缺陷,引入了IO流,IO流用于读写数据,可以读写文件以及网络中的数据
在这里插入图片描述

二 、File的创建,常用方法

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

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

import java.io.File;
import java.io.IOException;
public class Test {
    public static void main(String[] args) throws IOException {
          // 创建File对象
        File file = new File("E:\\work\\2025后端工单\\2025-3-31关于优化黄金会员权益次包融合销售页面的工单\\2025.4.2黄金会员+权益产品html\\2025.4.2黄金会员+权益产品html\\images\\icon-1.png");

        // 获取文件路径
        System.out.println(file.getAbsolutePath());
        // 获取文件大小
        System.out.println(file.length());

        // 获取文件名
        System.out.println(file.getName());

        // 创建文件对象,判断文件是否存在,不存在则创建
        File file1 = new File("D:\\study\\text.txt");
        System.out.println(file1.exists());
        System.out.println(file1.createNewFile());

        // 创建文件夹
        File file2 = new File("D:\\study\\images");
        System.out.println(file2.mkdir());

        // 创建多级文件夹
        File file3 = new File("D:\\study\\test\\img\\images");
        System.out.println(file3.mkdirs());

        // 删除文件,删除空文件夹
        File file4 = new File("D:\\study\\text.txt");
        System.out.println(file4.delete());

        // 获取某个目录下的全部一级文件名称
        File file5 = new File("D:\\study");
        String[] list = file5.list();
        for (String s : list) {
            /**
             * 打印结果:
             * images
             * studyJava
             * test
             * typescript
             * **/
            System.out.println(s);
        }

        // 获取某个目录下的全部一级文件对象绝对路径
        File file6 = new File("D:\\study");
        File[] files = file6.listFiles();
        for (File f : files) {
            /**
             * 打印结果:
             * D:\study\images
             * D:\study\studyJava
             * D:\study\test
             * D:\study\typescript
             * **/
            System.out.println(f.getAbsoluteFile()); // 获取文件绝对路径
        }
    }
}

  /**
         * 当主调是文件,或者路径不存在的时候,返回null
         * 当主调是空文件夹,返回长度为0的数组
         * 当主调是一个有内容的文件夹,将里面所有一级文件和文件夹的路径放在File数组中返回
         * 当主调是一个文件夹,且里面有隐藏文件时,将里面所有文件和文件夹的路径放在File数组中返回,包含隐藏文件
         * 当主调是一个文件夹,但是没有权限访问该文件夹时,返回null
         * 
    **/
        // 当主调是文件,或者路径不存在的时候,返回null
        File file7 = new File("D:\\study\\tx.txt");
        System.out.println(file7.exists()); // false
        File[] files1 = file7.listFiles();
        System.out.println(files1); // null

        //当主调是空文件夹,返回长度为0的数组
        File file8 = new File("D:\\study\\images");
        File[] files2 = file8.listFiles();
        System.out.println(Arrays.toString(files2)); // []

        // 当主调是一个有内容的文件夹,将里面所有一级文件和文件夹的路径放在File数组中返回
        File file9 = new File("D:\\study");
        File[] files3 = file9.listFiles();
        // [D:\study\images, D:\study\studyJava, D:\study\test, D:\study\typescript]
        System.out.println(Arrays.toString(files3));

三、递归

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
案例:递归求1-n的和
需求:计算1-n的和的结果,使用递归思想解决。
分析:我们先从数学思维上理解递归的流程和核心点
1)假如我们认为存在一个公式是f(n)=1+2+3+4+5+6+7+.(n-1)+ n;
那么公式等价形式就是:f(n)=f(n-1)+ n
2)递归的终结点:f(1)=1
3)递归方向:
f(5) = f(4)+5
f(4) = f(3)+4
f(3) = f(2)+3
f(2) = f(1)+2
f(1) = 1

public class Digui {
   public static void main(String[] args) {
       System.out.println(sum(5));
   }
   public static int sum(int n) {
       // 递归结束条件
       if (n == 1) {
           return 1;
       }
       // 递归调用
       // sum(n - 1) + n 数学公式
       return sum(n - 1) + n;
   }
}

案例
猴子第一天摘下若干桃子,当即吃了一半,觉得好不过瘾,于是又多吃了一个第二天又吃了前天剩余桃子数量的一半,觉得好不过瘾,于是又多吃了一个以后每天都是吃前天剩余桃子数量的一半,觉得好不过瘾,又多吃了一个等到第10天的时候发现桃子只有1个了。那么第一天总共摘了多少个桃子?
在这里插入图片描述

案例:文件搜索
在这里插入图片描述
在这里插入图片描述

public class Digui2 {
    public static void main(String[] args) {
        // 在D盘下搜索文件名为qq.exe的文件
        // 创建文件
        File file = new File("D:\\");
        searchFile(file,"qq.exe");
    }
    /**
     * @param dir 搜索的目录
     * @param filename 要搜索的文件名
     * **/

    public static void searchFile(File dir,String filename)
    {
        
        // 1.极端情况判断
        if (dir == null || !dir.exists()|| dir.isFile()) {
            return; // 如果dir不存在或者dir是一个文件,直接返回
        }
        // 2.获取目录下所有一级文件或者一级文件夹对象
        File[] files = dir.listFiles();
        
        // 3.判断当前目录下是否存在一级文件对象,存在才可以遍历
        if (files != null && files.length > 0) {
            // 4.遍历一级文件对象
            for (File file : files) {
                // 5.判断当前一级文件对象是否是文件,是文件就进行判断
                if (file.isFile()) {
                    // 6.判断文件名是否是目标文件名
                    if (file.getName().equals(filename)) {
                        System.out.println("找到文件:" + file.getAbsolutePath());
                    }
                } else {
                    // 7.如果当前一级文件对象是文件夹,就递归调用searchFile方法
                    searchFile(file,filename);
                }
            }
        }
    }
}

四、常见字符集

在这里插入图片描述
在这里插入图片描述
由于每个国家都有一套自己的编码方案,不利于通用,美国人为了统一编码于是做了Unicode字符集
在这里插入图片描述
由于Unicode编码每一个字符要4个字节,太占空间,为了解决这个问题,UTF-8出现了

4.1 UTF-8字符集

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

4.2 使用程序对字符进行编码和解码操作

在这里插入图片描述
String(byte[] bytes, String charsetName) 是 Java 中 String 类的一个构造方法:
byte[] bytes:表示一个字节数组,其中存储了以某种字符编码方式编码的字节数据。
String charsetName:表示字符集名称(如 “UTF-8”、“ISO-8859-1”、“GBK” 等)。

byte[ ] getBytes( ): 是 Java 中 String 类的一个方法,用于将字符串按照平台的默认字符集编码为字节数组
在这里插入图片描述

五、IO流

在这里插入图片描述

5.1 io流分类

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

5.2 FileInputStream(文件字节输入流)

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

public class Test {
    public static  void main(String[] args) throws IOException {
        // 创建文件字节输入流管道与源文件接通
        InputStream is = new FileInputStream("03\\src\\tx.txt");
        // 读取文件内容,每次读一个字节
        int b = 0;
//        while ((b = is.read()) != -1) {
//           // System.out.println(b);
//            System.out.println((char)b);
//        }
        // 读取文件内容,每次多个字节
        // 1、定义一个字节数组,每次读3个字节
        byte[] buffer = new byte[3];
        // 定义一个变量len,用于记住每次读取了多少个字节
        int len = 0;
        while ((len = is.read(buffer)) != -1) {
            // 0表示从第一个字节开始读取,len表示读取了多少个字节就输出多少个字节
             String str = new String(buffer,0,len);
             System.out.println(str);
        }
    }
}

5.2.1 FileInputStream缺陷

在这里插入图片描述
**缺陷展示:**假设tx.txt文件的内容为:abc6669我爱你g,每次读取3个字节,第一次读取abc,第二次读取666,第三次读取9我爱的时候就会出问题,原因是9是数字字符只需要1个字节,我爱是汉子,每个字符需要2个字节

 InputStream is = new FileInputStream("03\\src\\tx.txt");
    // 1、定义一个字节数组,每次读3个字节
        byte[] buffer = new byte[3];
        // 定义一个变量len,用于记住每次读取了多少个字节
        int len = 0;
        while ((len = is.read(buffer)) != -1) {
            // 0表示从第一个字节开始读取,len表示读取了多少个字节就输出多少个字节
             String str = new String(buffer,0,len);
             System.out.println(str);
        }

5.2.2 如何解决FileInputStream缺陷问题:一次读取完全部字节

在这里插入图片描述

public class Test2 {
    public static void main(String[] args) throws FileNotFoundException {
         // 创建文件流
        InputStream  is = new FileInputStream("03\\src\\tx2.txt");
        // 读取文件
        // readAllBytes() 方法必须jdk版本9以上
//        byte[] bytes = is.readAllBytes();
//        String rs = new String(bytes);
//        System.out.println(rs);
    }
}

5.2.3 FileOutputStream文件字节输出流

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

public class Test {
       public static void main(String[] args) throws IOException {
           // 1、创建文件字节输出流管道与目标文件接通
             // OutputStream os = new FileOutputStream("03\\src\\txout.txt"); // 覆盖管道
              OutputStream os = new FileOutputStream("03\\src\\txout.txt",true); //内容追加管道

           // 2、写入数据
           os.write(97);
           os.write('b');
           os.write("\r\n".getBytes()); // 换行
           // 3、写一个字节数组的一部分出去
          byte[] bytes = "我爱你中国666".getBytes();
          // 全部写入
          os.write(bytes);
          os.write("\r\n".getBytes()); // 换行
          // 4、写一个字节数组的一部分出去,写3个字节,即:写出了我
         os.write(bytes, 0, 3);
           os.write("\r\n".getBytes());// 换行
           // 关闭流,用完流之后要关闭管道,释放占用的资源
           os.close();
       }
}

5.2.4 案例:文件复制,将D盘的一张图复制到C盘

在这里插入图片描述

public class Test {
    public static  void main(String[] args) throws IOException {
        copyFile("E:\\btn-icon1.png", "D:\\btn-new.png");
    }
    // 复制文件copyFile
    public static  void copyFile(String srcPath,String destPath) throws IOException {
        // 1、创建一个文件字节输入流管道与源文件接通
        InputStream fis = new FileInputStream(srcPath);
        OutputStream fos = new FileOutputStream(destPath);
        // 2、读取一个字节数组,写入一个字节数组
        byte[] buffer = new byte[1024];
        int len;
        while ((len = fis.read(buffer)) != -1){
            // 写入fos中
            fos.write(buffer,0,len); // 读取多少个字节就写入多少个字节
        }
        System.out.println("复制成功!");
    }
}

总结:字节流非常适合做文件的复制操作
任何文件的底层都是字节,字节流做复制,是一字不漏的转移完全部字节,只要复制后的文件格式一致就没问题!

5.2.5 资源释放方案

5.2.5.1 **方案一(try-catch-finally):**缺点:写法过于臃肿,基本已经被放弃这种写法

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

public class Test {
    public static  void main(String[] args) throws IOException {
        copyFile("E:\\btn-icon1.png", "D:\\btn-new.png");
    }
    // 复制文件
    public static  void copyFile(String srcPath,String destPath) {
        InputStream fis = null;
        OutputStream fos = null;
       try{
        // 1、创建一个文件字节输入流管道与源文件接通
       fis = new FileInputStream(srcPath);
       fos = new FileOutputStream(destPath);
        // 2、读取一个字节数组,写入一个字节数组
        byte[] buffer = new byte[1024];
        int len;
        while ((len = fis.read(buffer)) != -1){
            // 写入fos中
            fos.write(buffer,0,len); // 读取多少个字节就写入多少个字节
        }
        System.out.println("复制成功!");
        }catch (IOException e){
            e.printStackTrace();
        }finally {

            // 关闭流,释放资源
           try{
               if(fos != null)   fos.close();
           }catch (Exception e){
               e.printStackTrace();
           }
           try{
               if(fis != null)   fis.close();
           }catch (Exception e){
               e.printStackTrace();
           }
        }
    }
}

5.2.5.2 方案二(try-with-resource)

在这里插入图片描述


public class Test {
    public static  void main(String[] args) throws IOException {
        copyFile("E:\\btn-icon1.png", "D:\\btn-new.png");
    }
    // 复制文件
    public static  void copyFile(String srcPath,String destPath) {

       try(
           // 1、创建一个文件字节输入流管道与源文件接通
            InputStream fis = new FileInputStream(srcPath);
             OutputStream  fos = new FileOutputStream(destPath);
            ){
        // 2、读取一个字节数组,写入一个字节数组
        byte[] buffer = new byte[1024];
        int len;
        while ((len = fis.read(buffer)) != -1){
            // 写入fos中
            fos.write(buffer,0,len); // 读取多少个字节就写入多少个字节
        }
        System.out.println("复制成功!");
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

在这里插入图片描述

5.3 字符流

在这里插入图片描述

5.3.1 文件字符输入流

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

5.3.2 文件字符输出流

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

5.4 缓冲流

在这里插入图片描述

5.4.1 缓冲字节输入流BufferedInputStream

作用:可以提高字节输入流读取数据的性能
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5.4.2 缓冲字符流

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

5.5 其他流

5.5.1 InputStreamReader字符输入转换流

作用:解决不同编码时,字符流读取文本内容乱码的问题
解决思路:先获取文件的原始字节流,再将其按真实的字符集编码转成字符输入流,这样字符输入流中的字符就不乱码了
在这里插入图片描述在这里插入图片描述

5.5.2 PrintStream、PrintWriter打印流

在这里插入图片描述
作用 :打印流可以实现更方便、更高效的打印数据出去,能实现打印啥出去就是啥出去
在这里插入图片描述
在这里插入图片描述

5.5.3 DataInputStream、DataOutputStream(特殊数据流)

在这里插入图片描述

DataOutputStream数据输出流

在这里插入图片描述

DataInputStream输入流

在这里插入图片描述

在这里插入图片描述

5.6 IO框架

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值