第十一章 存储&读写数据的方案(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框架

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

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值