File、IO流

news2024/11/26 6:21:02

File、IO流(一)

存储数据的方案

1

以上都是内存中的数据容器(记住程序正在处理的数据,能快速运算),它们记住的数据,在断电,或者程序终止时会丢失
  • 程序在内存中处理后的数据想长久的保存起来
    • 文件是非常重要的存储方式,在计算机硬盘中
    • 即便断电了,或者程序终止了,存储在硬盘文件中的数据也不会丢失

File

  • File是java.io包下的类,File类的对象,用于代表当前操作系统的文件(可以是文件,或文件夹)
  • 获取文件信息(大小、文件名、修改时间)
  • 判断文件的类型
  • 创建文件 / 文件夹
  • 删除文件 / 文件夹…
注意:File类只能对文件本身进行操作,不能读写文件里面存储的数据

IO流

  • 用于读写数据的(可以读写文件,或网络中的数据…)

目录

  • 创建对象
    • 常用方法1:判断文件类型,获取文件信息
    • 常用方法2:创建文件、删除文件
    • 常用方法3:遍历文件夹
  • 前置知识:方法递归
  • 前置知识:字符集
  • IO流
  • IO流 —— 字节流
  • IO流 —— 资源释放的方法

1、创建File类的对象

构造器说明
Public File(String pathname)根据文件路径创建文件对象
Public File(String parent,String child)根据父路径和子路径的名字创建对象
Public File(File parent,String child)根据父路径对应文件对象和子路径的名字创建对象
**
 * 目标:掌握File创建对象,代表具体文件的方案
 */
public class FileTest1 {
    public static void main(String[] args) {
        // 1.创建一个File对象,指代某个具体的文件
        // 路径分隔符
            File f1 = new File("D:/reSource/a.txt");
//          File f2 = new File("D:\\reSource\\a.txt"); // 要用'\'转义
//          File f3 = new File("D:" + File.separator + "reSource" + File.separator + "a.txt"); // 系统自带的分隔符
          System.out.println(f1.length()); // 文件大小(字节)

        File f2 = new File("D:/reSource");
        System.out.println(f2.length()); // 文件夹本身大小(字节)

        // 注意:File对象可以指代一个不存在的文件路径
        File f3 = new File("D:/reSource/aa.txt");
        System.out.println(f3.length()); // 0
        System.out.println(f3.exists()); // false

        // 现在要定位的文件是在模块中,应该怎么定位呢?
        // 绝对路径 :带盘符的
//        File f4 = new File("D:\\code\\ATM-system\\src\\File1.txt");
        // 相对路径(重点):不带盘符,默认是直接去工程下寻找文件的
        File f4 = new File("src\\File1.txt");
        System.out.println(f4.length());
    }
}
注意:File对象既可以代表文件,也可以代表文件夹,File封装的对象仅仅是一个路径名,这个路径可以是存在的,也允许是不存在的
绝对路径、相对路径
  • 绝对路径:从盘符开始

File file1 = new File(“D:\reSource\a.txt”);

  • 相对路径:不带盘符,默认直接到当前工程下的目录寻找文件

File file2 = new File(“src\a.txt”);

常用方法1:File提供的判断文件类型,获取文件信息功能

方法名称说明
public boolean exisit()判断当前文件对象,对应的文件路径是否存在,存在返回true
public boolean isFile()判断当前文件对象指代的是否是文件,是文件返回true,反之
public boolean isDirectory()判断当前文件对象指代的是否是文件夹,是文件夹返回true,反之
public String getName()获取文件的名称(包含后缀)
public long length()获取文件的大小,返回字节个数
public long lastModified()获取文件的最后修改时间(返回的是时间毫秒值)
public String getPath()获取创建文件对象时,使用的路径
public String getAbsolutePath()获取绝对路径
public class FileTest2 {
    public static void main(String[] args) {
        // 1.创建文件对象,指代某个文件
        File f1 = new File("D:/reSource/a.txt");

        // 2、public boolean exisit() : 判断当前文件对象,对应的文件路径是否存在,存在返回true
        System.out.println(f1.exists()); // true

        // 3、public boolean isFile() : 判断当前文件对象指代的是否是文件,是文件返回true,反之
        System.out.println(f1.isFile()); // true

        // 4、public boolean isDirectory() : 判断当前文件对象指代的是否是文件夹,是文件夹返回true,反之
        System.out.println(f1.isDirectory()); // false

        // 5、public String getName() : 获取文件的名称(包含后缀)
        System.out.println(f1.getName()); // a.txt

        // 6、public long length() : 获取文件的大小,返回字节个数
        System.out.println(f1.length());

        // 7、public long lastModified() : 获取文件的最后修改时间(返回的是时间毫秒值)
        long time = f1.lastModified();
        System.out.println(time); // 1717432910058
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        System.out.println(sdf.format(time)); //2024/06/04 00:41:50

        // 8、public String getPath() : 获取创建文件对象时,使用的路径
        File f2 = new File("D:/reSource/a.txt");
        File f3 = new File("src\\File1.txt");
        System.out.println(f2.getPath()); // D:\reSource\a.txt
        System.out.println(f3.getPath()); // src\File1.txt

        // 9、public String getAbsolutePath() : 获取绝对路径
        System.out.println(f2.getAbsolutePath()); // D:\reSource\a.txt
        System.out.println(f3.getAbsolutePath()); // D:\code\javasepro\src\File1.txt (把相对路径转成绝对路径的形式)
    }
}

常用方法2:创建文件、删除文件

File类创建文件的功能

方法名说明
public boolean createNewFile()创建一个新文件(文件内容为空),创建成功返回true,反之
public boolean mkdir()用于创建文件夹,注意:只能创建一级文件夹
public boolean mkdirs()用于创建文件夹,注意:可以创建多级文件夹

File类删除文件的功能

方法名说明
public boolean delete()可以删除文件,或者空文件夹,注意:不能删除非空文件夹
public class FileTest3 {
    public static void main(String[] args) throws IOException {
        // 1、public boolean createNewFile() : 创建一个新文件(文件内容为空),创建成功返回true,反之
        File f1 = new File("D:/reSource/abc.txt");
        System.out.println(f1.createNewFile()); // 第一次创建是返回true,如果文件已经存在,则返回false

        // 2、public boolean mkdir() : 用于创建文件夹,注意:只能创建一级文件夹
        File f2 = new File("D:/reSource/aaa");
        System.out.println(f2.mkdir()); // true

        // 3、public boolean mkdirs() : 用于创建文件夹,注意:可以创建多级文件夹
        File f3 = new File("D:/reSource/bbb/ccc/ddd");
        System.out.println(f3.mkdirs()); // true

        // 4、public boolean delete() : 可以删除文件,或者空文件夹,注意:不能删除非空文件夹
        System.out.println(f1.delete()); // true
        System.out.println(f2.delete()); // true
        File f4 = new File("D:/reSource");
        System.out.println(f4.delete()); // false
    }
}

常用方法3:遍历文件夹

File类提供的遍历文件夹的功能

方法名说明
public String[] list()获取当前目录下的所有的“一级文件名称”到一个字符串数组中去返回
public File[] listFiles()获取当前目录下所有的“一级文件对象”到一个文件数组中去返回(重点)
public class FileTest4 {
    public static void main(String[] args) {
        // 1、public String[] list() : 获取当前目录下的所有的“一级文件名称”到一个字符串数组中去返回
        File f1 = new File("D:\\course\\javase");
        String[] names = f1.list();
        for (String name : names) {
            System.out.println(name);
        }

        // 2、public File[] listFiles() : (重点)获取当前目录下所有的“一级文件对象”到一个文件数组中去返回(重点)
        File[] files = f1.listFiles();
        for (File file : files) {
            System.out.println(file.getAbsolutePath()); // 打印遍历到的每个文件的绝对路径
        }

        // 当路径不存在时,返回 null
        File f2 = new File("D:\\course\\javase");
        File[] files2 = f2.listFiles();
        System.out.println(Arrays.toString(files2)); // null

        // 当主调是空文件夹时,返回一个长度为0的数组
        File f3 = new File("D:\\reSource\\aaa");
        File[] files3 = f3.listFiles();
        System.out.println(Arrays.toString(files3)); // []
    }
}
使用listFiles方法时的注意事项
  • 当主调是文件,或者路径不存在时,返回null
  • 当主调是空文件夹时,返回一个长度为0的数组
  • 当主调是一个有内容的文件夹时,将里面所有的一级文件和文件夹的路径放在File数组中返回
  • 当主调是一个文件夹时,且里面有隐藏文件时,将里面所有的一级文件和文件夹的路径放在File数组中返回,包含隐藏文件
  • 当主调是一个文件夹,但是没有权限访问该文件夹时,返回null

前置知识:方法递归

什么是方法递归?

  • 方法递归是一种算法,在程序设计语言中广泛应用
  • 从形式上说:方法调用自身的形式称为方法递归(recursion)

使用方法递归时需要注意的问题

  • 如果递归没有控制好终止,会出现递归死循环,导致栈内存溢出错误
递归经典案例:猴子吃桃问题
  • 猴子第一天摘下若干桃子,当即吃了一半,觉得好不过瘾,于是又多吃了一个,第二天又吃了昨天剩余桃子数量的一半,决定好不过瘾,于是又多吃了一个,以后每天都是吃昨天剩余桃子数量的一半,觉得好不过瘾,又多吃一个,等到第10天的时候,发现桃子只有一个了,求猴子第一天摘了多少桃子?
public class RecursionTest1 {
    public static void main(String[] args) {
        // 目标:猴子吃桃问题
        // 终结点 : f(10) = 1
        // 公式:f(x) - f(x) /2 -1 = f(x+1)
        // 变形: 2 * f(x) -f(x)-2 = 2 * f(x+1)
        // 变形2: f(x) = 2 * f(x+1) +2
        System.out.println(f(1));
    }

    public static int f(int x) {
        if(x == 10){
            return 1;
        } else {
            return 2 * f(x+1) + 2;
        }
    }
}
案例1:文件搜索

需求:从D:盘中,搜索“QQ.exe”这个文件,找到后输出其位置

分析:

  1. 先找出D:盘下的所有一级文件对象
  2. 遍历全部一级文件对象,判断是否是文件
  3. 如果是文件,判断是否是自己想要找的文件
  4. 如果是文件夹,需要继续进入到该文件夹,重复上述过程
/**
 * 目标:掌握文件搜索的实现
 */
public class RecursionTest1 {
    public static void main(String[] args) throws Exception {
        searchFile(new File("D:\\Program Files\\Tencent\\QQNT"),"QQ.exe");
    }

    /**
     * 去目录(文件夹)下搜索某个文件
     * @param dir 目录(文件夹)
     * @param fileName 要搜索的文件名称
     */
    public static void searchFile(File dir,String fileName) throws IOException {
        // 1、把非法的情况都拦截住
        if(dir == null || !dir.exists() || dir.isFile()) {
            return; // 代表无法搜索
        }

        // 2、dir不是null,存在,一定是目录对象(文件夹对象)
        // 获取当前目录(文件夹)下的全部一级文件对象
        File[] files = dir.listFiles();

        // 3、判断当前目录下是否存在一级文件对象(文件夹里是否为空),以及是否可以拿到一级文件对象(是否有权限)
        if(files != null && files.length > 0) { // 存在一级文件对象,并且有权限
            // 4、遍历全部一级文件对象
            for (File f : files) {
                // 5、判断文件对象 -> 是否是文件,还是文件夹
                if(f.isFile()) {
                    // 一定是文件,判断这个文件的文件名是否是要找的
                    if(f.getName().equals(fileName)) {
                        System.out.println("该文件的绝对路径是:" + f.getAbsoluteFile());
                        Runtime r = Runtime.getRuntime();
                        r.exec(f.getAbsolutePath()); // 启动QQ程序
                    } else {
                        // 一定是文件夹,继续重复这个过程(递归)
                        searchFile(f,fileName);
                    }
                }
            }
        }

    }
}
案例2:删除非空文件夹
/**
 * 目标:掌握删除非空文件夹
 */
public class RecursionTest2 {
	public static void main(String[] args) {
		// 目标:删除非空文件夹,独立功能独立成方法
		File dir = new File("D:\\reSource\\照片");
		if(deletedir(dir) == -1) {
			System.out.println("异常终止");
		} else {
			System.out.println("成功删除");
		}
	}
	
	public static int deletedir(File dir) {
		if(dir == null || !dir.exists()) {
			return -1;
		}
		
		if(dir.isFile()) {
			dir.delete();
			return 0;
		}
		
		// 1、dir存在且是文件夹,拿里面的一级文件对象
		File[] files = dir.listFiles();
		if(files == null) { // 没有访问权限
			return -1;
		}
		
		if(files.length == 0) {
			dir.delete(); // 代表空文件夹直接删除
			return 0;
		}
		
		// 这是一个有内容的文件夹,删掉里面的内容,再删掉自己
		for(File file : files) {
			if(file.isFile()) { // 是文件直接删除
				file.delete();
			}else { // 是文件夹,重复上述过程
				deletedir(file);
			}
		}
		
		// 把自己的内容删完了,最后要把自己删除
		dir.delete();
		return 0;
	}
}
案例3:

需求:改变某个文件夹下文件的序号,要求从19开始

public class RecursionTest3 {
	  public static void main(String[] args) {
	        // 目标:改变某个文件夹下视频的序号,要求从19开始
	        File dir = new File("D://reSource//视频");

	        // 1、拿到视频目录下面全部的视频对象 ——>一级文件对象
	        File[] videos = dir.listFiles();

	        // 2、遍历一个一个的文件对象
	        for (File video : videos) {
	            // 3、拿到它的名字,改成新名字
	            String name = video.getName(); // "10、封装、继承...."
	            String index = name.substring(0, name.indexOf("、")); // 包前不包后
	            String lastName = name.substring(name.indexOf("、"));
	            String newName = (Integer.valueOf(index) + 18 ) + lastName;

	        // 4、正式改名
	            // video.getParent() : 拿到video的父路径 ——> dir
//	            video.renameTo(new File(video.getParent(),newName));
	            video.renameTo(new File(dir,newName));
	        }
	    }
}
案例4:

啤酒问题:啤酒2元一瓶,4个盖子可以换一瓶,2个空瓶可以换一瓶,请问10元可以喝多少瓶?

public class RecursionTest4 {
    public static int totalNumber; // 总酒数
    public static int lastCoverNumber; // 剩余的瓶盖数
    public static int lastBottleNumber; // 剩余的瓶子数

    public static void main(String[] args) {
        // 啤酒问题:啤酒2元一瓶,4个盖子可以换一瓶,2个空瓶可以换一瓶,请问10元可以喝多少瓶?
        buy(10);
        System.out.println("总数:" + totalNumber);
        System.out.println("剩余盖子数:" + lastCoverNumber);
        System.out.println("剩余瓶子数:" + lastBottleNumber);
    }

    public static void buy(int money) {
        // 1、先买
        int buyNumber = money / 2;
        totalNumber = totalNumber + buyNumber;

        // 2、把瓶子和盖子换算成钱继续买酒
        int allBottleNumber = buyNumber + lastBottleNumber;
        int allCoverNumber = buyNumber + lastCoverNumber;

        int allMoney = 0;
        if (allBottleNumber >= 2) {
            allMoney = (allBottleNumber / 2) * 2;
        }
        lastBottleNumber = (allBottleNumber % 2);

        if (allCoverNumber >= 4) {
            allMoney += (allCoverNumber / 4) * 2;
        }
        lastCoverNumber = (allCoverNumber % 4);

        if (allMoney >= 2) {
            buy(allMoney);
        }
    }
}

前置知识:字符集

  • 常见字符集介绍
  • 字符集的编码、解码操作

标准ASCII字符集

  • ASCII:美国标准信息交换代码,包含了英文、符号等
  • 标准ASCII使用1个字节存储一个字符,首位是0,总共可表示128个字符

GBK(汉字内码扩展规范,国标码)

  • 汉字编码字符集,包含了2万多个汉字字符,GBK中一个中文字符编码成两个字节的形式存储
  • GBK兼容了ASCII字符集

Unicode字符集(UTF-8字符集,统一码,也叫万国码)

  • Unicode是国际组织制定的,可以容纳世界上所有的文字,符号的字符集
  • 英文字符、数字等只占一个字节(兼容ASCII编码),汉字字符占用3个字节
小结
  • ASCII字符集:只有英文、数字、符号等,占1个字节
  • GBK字符集:汉字占2个字节,英文、数字占1个字节
  • UTF-8字符集:汉字占3个字节,英文、数字占1个字节

注意1:字符编码时使用的字符集,和解码时使用的字符集一致,否则会出现乱码

注意2:英文,数字一半不会乱码,因为很多字符集都兼容了ASCII编码

字符集的编码,解码操作

  • 编码:把字符按照指定字符集编码成字节
  • 解码:把字节按照指定字符集解码成字符
java代码完成对字符的编码

String类提供了如下方法

方法名说明
byte[] getBytes()使用平台的默认字符将该String编码为一系列字节,将结果存储到新的字节数组中
byte[] getBytes(String charSetName)使用指定的字符集将该String编码为一系列字节,将结果存储到新的字节数组中
java代码完成对字符的解码

String类提供了如下方法

方法名说明
String(byte[] bytes)通过使用平台默认字符集解码指定的字节数组来构造新的String
String(byte[] bytes,String charSetName)通过指定的字符集解码指定的字节数组来构造新的String

IO流概述

  • I 值 Input,称为输入流:负责把数据读到内存中去
  • O 指 Output,称为输出流,负责写数据出去(磁盘 / 网络…)
IO流的分类

8

IO流总体来说就有四大流
  1. 字节输入流
  2. 字节输出流
  3. 字符输入流
  4. 字符输出流
总结流的四大类
  • 字节输入流:以内存为基准,来自磁盘文件 / 网络中的数据,以字节的形式读入到内存中去的流
  • 字节输出流:以内存为基准,把内存中的数据以字节的形式写出到磁盘或者网络中去的流
  • 字符输入流:以内存为基准,来自磁盘文件 / 网络中的数据,以字符的形式读入到内存中去的流
  • 字符输出流:以内存为基准,把内存中的数据以字符写出到磁盘文件或者网络介质中去的流
IO流的体系
  • Java.io包下

5

IO流 —— 字节流

  • 文件字节输入流:每次读取一个字节
  • 文件字节输入流:每次读取多个字节
  • 文件字节输入流:一次读取完全部字节
  • 文件字节输出流:写字节出去
  • 案例:文件复制
FileInputStream(文件字节输入流)
  • 作用:以内存为基准,可以把磁盘文件中的数据以字节的形式读入到内存中去
构造器说明
Public FileInputStream(File file)创建字节输入流管道与源文件接通
Public FileInputStream(String Pathname)创建字节输入流管道与源文件接通
方法名称说明
Public int read()每次读取一个字节返回,如果发现没有数据可读会返回-1
Public int read(byte[] buffer)每次用一个字节数组去读取数据,返回字节数组读取了多少个字节,如果发现没有数据可读,会返回-1
1. 文件字节输入流:每次读取一个字节
public class FileInputStreamTest1 {
	public static void main(String[] args) throws IOException {
        // 1、创建文件字节输入流管道,与源文件接通
//      InputStream is = new FileInputStream(new File("src\\ab.txt"));

      // 简化写法,推荐使用
      InputStream is = new FileInputStream("src\\ab.txt");

      // 2、开始读取文件的字节数据
      // public int read() : 每次读取一个字节返回,如果没有数据了, 返回-1
//      int b1 = is.read();
//      System.out.println(b1); // 97
//      System.out.println((char)b1); // a
//      
//      int b2 = is.read();
//      System.out.println(b2); // 98
//      System.out.println((char)b2); // b
//      
//      int b3 = is.read();
//      System.out.println(b3); // -1
      
      // 3、使用循环改造上述代码
      int b; // 用于记住读取的字节
      while((b = is.read()) != -1 ) {
    	  System.out.print((char) b);
      } 
      
      // 读取数据的性能很差!
      // 读取汉字输出会乱码,无法避免
      // 流使用完毕之后,必须关闭!释放系统资源
      
      is.close();
	}
}
注意事项:
  • 使用FileInputStream每次读取一个字节,读取性能较差,并且读取汉字输出会乱码
  • 流使用完毕之后,必须关闭,释放系统资源
2. 文件字节输入流:每次读取多个字节
/**
 * 目标:掌握使用FileInputStream 每次读取多个字节
 */
public class FileInputStreamTest2 {
	public static void main(String[] args) throws Exception {
		// 1、创建一个字节输入流对象代表字节输入流管道与源文件接通
	InputStream is =  new FileInputStream("src/abc66.txt");
	
	// 2、开始读取文件中的字节数据,每次读取多个字节
	//   public int read(byte b[]) throws IOException
	// 每次读取多个字节到字节数组中去,返回读取的字节数量,读取完毕会返回-1
//		byte[] buffer = new byte[3];
//		int len = is.read(buffer);
//		String rs = new String(buffer);
//		System.out.println(rs); // abc
//		System.out.println("当次读取的字节数量:" + len ); // 3
//		
//		// buffer = [abc];
//		// buffer = [66c]
//		int len2 = is.read(buffer);
//		
		String rs2 = new String(buffer);
		System.out.println(rs2); // 66c
//		
//		// 注意:读取多少,倒出多少
//		String rs2 = new String(buffer,0,len2);
//		System.out.println(rs2); // 66
//		System.out.println("当次读取的字节数量:" + len ); // 2
//	
//		int len3 = is.read(buffer);
//		System.out.println(len3); // -1
	
	// 使用循环改造
		byte[] buffer = new byte[3];
		int len; // 记住每次读取了多少字节
		while( (len = is.read(buffer)) != -1 ) {
			// 注意:读取多少,倒出多少
			String rs = new String(buffer,0,len);
			System.out.println(rs); 
		}
		
	// 性能得到了明显的提升!
	// 这种方案也不能避免读取汉字输出乱码的问题
		
		is.close(); // 关闭流,释放系统资源
	}
}
注意事项:
  • 使用FileInputStream每次读取多个字节,读取性能得到了提升,但读取汉字输出还是会乱码
  • 使用字节流读取中文,如何保证输出不会乱码,怎么解决?
    • 定义一个与文件一样大的字节数组,一次性读取完文件的全部字节
3. 文件字节输入流:一次读取完全部字节
  • 方式一:自己定义一个字节数组与被读取的文件大小一样大,然后使用该字节数组,一次性读完文件的全部字节
方法名称说明
Public int read(byte[] buffer)每次用一个字节数组去读取,返回字节数组读取了多少个字节,如果发现没有数据可读会返回-1
public class FileInputStreamTest3 {
	public static void main(String[] args) throws Exception {
		// 1、一次性读取完文件的全部字节到一个字节数组中去
		// 创建一个字节输入流管道与源文件接通
		InputStream is = new FileInputStream("src/File1");
		
		// 2、方式一:准备一个字节数组,大小与文件的大小正好一样大
		File f = new File("src/File1");
		long size = f.length();
		byte[] buffer = new byte[(int)size];
		
		int len = is.read(buffer);
		String rs = new String(buffer);
		System.out.println(rs);
		
		System.out.println(size); // 14 
		System.out.println(len); // 14
	}
}

  • 方式二:java官方为InputStream提供了如下方法,可以直接把文件的全部字节,读取到一个字节数组中返回
方法名称说明
Public byte[] readAllBytes() throw IoException直接将当前字节输入流对应的文件对象的字节数据装到一个字节数组返回
public class FileInputStreamTest3 {
	public static void main(String[] args) throws Exception {
		// 1、一次性读取完文件的全部字节到一个字节数组中去
		// 创建一个字节输入流管道与源文件接通
		InputStream is = new FileInputStream("src/File1");
		
		// 方式二:
		byte[] buffer = is.readAllBytes();
		System.out.println(new String(buffer));
	}
}
小结:

直接把文件数据全部读取到一个字节数组可以避免乱码,是否存在问题?

  • 如果文件过大,创建的字节数组也会过大,可能引起内存溢出
  • 读写文本内容更适合用字符流
  • 字节流适合做数据的转移,如:文件复制等
4. 文件字节输出流:写字节出去

FileOutoutStream(文件字节输出流)

  • 作用:以内存为基准,把内存中的数据以字节的形式写出到文件中去
构造器说明
Public FileOutputStream(File file)创建字节输出流管道与源文件对象接通
Public FileOutputStream(String filepath)创建字节输出流管道与源文件路径接通
Public FileOutputStream(File file,boolean append)创建字节输出流管道与源文件对象接通,可追加数据
Public FileOutputStream(String filepath,boolean append)创建字节输出流管道与源文件路径接通,可追加数据
方法名称说明
Public void Write(int a)写一个字节出去
Public void Write(byte[] buffer)写一个字节数组出去
Public void Write(byte[] buffer,int pos,int len)写一个字节数组的一部分出去
Public void close() throws IoException关闭流
/**
 * 目标:掌握文件字节输出流FileOutputStream的使用
 */
public class FileInputStreamTest4 {
	public static void main(String[] args) throws Exception {
		// 1、创建一个字节输出流管道与目标文件接通
		// 覆盖管道:覆盖之前的数据
//		OutputStream os = new FileOutputStream("src/out1.txt");
		
		// 追加数据的管道
		OutputStream os = new FileOutputStream("src/out1.txt",true);
		
		// 2、开始写字节数据出去
		os.write(97); // 97就是一个字节,代表a
		os.write('b'); // 'b'也是一个字节
		
//		os.write('张'); // UTF-8里一个中文占3个字节,这里默认只能写出去一个字节,所以会乱码
	
		byte[] bytes = "我爱你中国abc".getBytes();
		os.write(bytes);
		
		os.write(bytes, 0, 15); // "我爱你中国"
		
		// 换行符
		os.write("\r\n".getBytes());
		
		os.close(); // 关闭流
	}
}
案例:文件复制

4

/**
 * 目标:使用字节流完成对文件的复制操作
 */
public class CopyTest5 {
	public static void main(String[] args) throws Exception {
		// 需求:复制照片
		// 1、创建一个字节输入流管道与源文件接通
		InputStream is = new FileInputStream("‪D:/reSource/logo.png");
		
		// 2、创建一个字节输出流管道与目标文件接通
		OutputStream os = new FileOutputStream("C:/data/logo.png");
		
		// 3、创建一个字节数组,负责转移字节数据
		byte[] buffer = new byte[1024]; // 1KB
		
		// 4、从字节输入流中读取字节数据,写出去到字节输出流中,读多少写出去多少
		int len; // 记住每次读取了多少个字节
		while((len = is.read(buffer)) != -1) {
			os.write(buffer,0,len);
		}
		
		os.close();
		is.close();
		System.out.println("复制完成");
	}
}

IO流 —— 资源释放的方法

  • Try —— catch —— finally
  • Try —— with —— resource
try {
	...
} catch(IoException e) {
	e.printStackTrace();
} finally {
	...
}
/**
 * 目标:认识try-catch-finally
 */
public class Test1 {
	public static void main(String[] args) {
		try {
			System.out.println(10/0);
			return; // 跳出方法的执行
		} catch(Exception e) {
			e.printStackTrace();
		}finally {
			System.out.println("=====finally执行了一次====");
		}
	}
}
// 输出 =====finally执行了一次====
  • finally代码区的特点无论try中的程序是正常执行,还是出现了异常,最后都一定会执行finally区,除非JVM虚拟机终止
注意:

finally代码块内一定不能返回数据

public class Test1 {
	public static void main(String[] args) {
		try {
			System.out.println(10/0);
			return; // 跳出方法的执行
		} catch(Exception e) {
			e.printStackTrace();
		}finally {
			System.out.println("=====finally执行了一次====");
		}
		
		System.out.println(chu(10 , 2)); // 输出了11
	}
	
	public static int chu(int a,int b) {
		try {
			return a / b;
		} catch(Exception e){
			e.printStackTrace();
			return -1; // 代表的是出现异常
		} finally {
			// 千万不要在finally中返回数据!
			return 11;
		}
	}
}
// 最后会输出11(X)
  • finally一般用于在程序执行完成后进行资源释放操作(专业级做法)
/**
 * 目标:掌握finally的常用方法
 */
public class Test2 {
	public static void main(String[] args){		
		InputStream is = null;
		OutputStream os = null;
		try {
			System.out.println(10 / 0);
			
			// 1、创建一个字节输入流管道与源文件接通
			is = new FileInputStream("‪D:/reSource/logo.png");
			// 2、创建一个字节输出流管道与目标文件接通
			os = new FileOutputStream("C:/data/logo.png");
			
			System.out.println(10 / 0);
			
			// 3、创建一个字节数组,负责转移字节数据
			byte[] buffer = new byte[1024]; // 1KB
			// 4、从字节输入流中读取字节数据,写出去到字节输出流中,读多少写出去多少
			int len; // 记住每次读取了多少个字节
			while ((len = is.read(buffer)) != -1) {
				os.write(buffer, 0, len);
			}
			System.out.println("复制完成");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// 释放资源的操作
			
			try {
				if (os != null)
					os.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
			
			try {
				if (is != null)
					is.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}
JDK7开始提供了更简单的资源释放方案:try —— with —— resource
try( 定义资源1; 定义资源2;...) {
	可能出现异常的代码;
} catch(异常类名 变量名) {
	异常的处理代码;
}

该资源使用完毕后,会自动调用close()方法,完成对资源的释放

/**
 * 目标:掌握更简单的资源释放方案:try - with - resource
 */
public class Test3 {
	public static void main(String[] args){		
		try(
				// 1、创建一个字节输入流管道与源文件接通
				InputStream is = new FileInputStream("‪D:/reSource/logo.png");
				
				// 2、创建一个字节输出流管道与目标文件接通
				OutputStream os = new FileOutputStream("C:/data/logo.png");
				
				// 注意:这里只能放置资源对象
				// 什么是资源对象呢? 资源都是会实现AutoCloseable接口
				// 资源都会有一个close方法,并且资源放到()里,用完之后
				// 会被自动调用其close方法完成资源的释放操作
				
				){
			
			// 3、创建一个字节数组,负责转移字节数据
			byte[] buffer = new byte[1024]; // 1KB
			// 4、从字节输入流中读取字节数据,写出去到字节输出流中,读多少写出去多少
			int len; // 记住每次读取了多少个字节
			while ((len = is.read(buffer)) != -1) {
				os.write(buffer, 0, len);
			}
			System.out.println("复制完成");
		} catch (Exception e) {
			e.printStackTrace();
		} 
	}
}
验证资源用完之后,是否会自动调用其close方法完成资源的释放操作
public class Test4 {
	public static void main(String[] args){		
		try(
				// 1、创建一个字节输入流管道与源文件接通
				InputStream is = new FileInputStream("src/out1.txt");
				// 2、创建一个字节输出流管道与目标文件接通
				OutputStream os = new FileOutputStream("src/out2.txt");
				
				// 自己创建一个资源对象
				MyConnection conn = new MyConnection();
				
				){
			
			// 3、创建一个字节数组,负责转移字节数据
			byte[] buffer = new byte[1024]; // 1KB
			// 4、从字节输入流中读取字节数据,写出去到字节输出流中,读多少写出去多少
			int len; // 记住每次读取了多少个字节
			while ((len = is.read(buffer)) != -1) {
				os.write(buffer, 0, len);
			}
			
			System.out.println(conn); // 用一下这个资源对象,用完后好自动释放资源
			
			System.out.println("复制完成");
		} catch (Exception e) {
			e.printStackTrace();
		} 
	}
}

// 输出以下语句:
// 复制完成
// 释放了与某个硬件的连接释放~~~
---------------------------------------------------------------------------------------------
public class MyConnection implements AutoCloseable{ // 实现AutoCloseable接口

	@Override // 要重写AutoCloseable接口里的close方法
	public void close() throws Exception {
		System.out.println("释放了与某个硬件的连接释放~~~");
	}
}
注意:
  • ( ) 中只能放置资源,否则报错
  • 什么是资源呢? 资源一般指的是最终实现了AutoCloseable接口

Public abstract class InputStream implements Closeable{ };

Public abstract class OutputStream implements Closeable,Flushable{ };

Public interface Closeable extends AutoCloseable{ };

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1816835.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Maven增强插件助你开发快人一步

因为之前的工作中一直用的Maven进行jar包管理,每次新加依赖都要去中央仓库上搜索下坐标,这里为了方便以SerchEveryWhere为入口,增加了一个Maven的搜索tab,输入你想要找的包名即可在idea中直接显示最新版对应的坐标以及cve数&#…

镜舟科技与千丁数科开展战略洽谈,探索智慧空间与数据的深度融合

数据作为当下最重要的生产要素之一,数据分析与智慧空间科技的结合正成为推动企业发展的新引擎 。 5 月 15 日,镜舟科技与千丁数科在北京开展战略合作洽谈。本次会议旨在探索双方在智慧空间科技和数据分析领域的合作潜力,共同推进数字经济的新…

LVS+Keepalived NGINX+Keepalived 高可用群集实战部署

Keepalived及其工作原理 Keepalived 是一个基于VRRP协议来实现的LVS服务高可用方案,可以解决静态路由出现的单点故障问题。 VRRP协议(虚拟路由冗余协议) 是针对路由器的一种备份解决方案由多台路由器组成一个热备组,通过共用的…

WEB基础--TOMCAT服务器

服务器概述 什么是服务器 服务器:就是一个提供为人民服务的机器,这里的服务器主要指计算机服务器,分为两种:服务器软件和硬件服务器; 服务器分类 1、硬件服务器:安装了服务器软件的主机。就相当于高配的…

dijkstra 算法为什么高效?

最短路径算法中,dijkstra(i,j,k 颇有遍历意味) 算法时间效能很好,而 floyd,bellman-ford 算法则优在处理负权重。但这是为什么? 从算法过程看,dijkstra 算法确定了某点最短路径后,它…

单目标应用:基于红嘴蓝鹊优化器RBMO的微电网优化(MATLAB代码)

一、微电网模型介绍 微电网多目标优化调度模型简介_vmgpqv-CSDN博客 参考文献: [1]李兴莘,张靖,何宇,等.基于改进粒子群算法的微电网多目标优化调度[J].电力科学与工程, 2021, 37(3):7 二、红嘴蓝鹊优化器求解微电网 2.1算法简介 红嘴蓝鹊优化器(R…

Sharding-JDBC 使用 Nacos 作为配置中心 【下 代码实战】

Sharding-JDBC 使用 Nacos 作为配置中心 【下 代码实战】 1. 实现 ShardingSphereDriverURLProvider 由上一篇博文我们已经知道了 Sharding-JDBC 是基于 Java SPI 机制去加载 并实例化 ShardingSphereDriverURLProvider 的实现类 public interface ShardingSphereDriverURLP…

3个月搞定计算机二级C语言!高效刷题系列进行中

文章目录 前言备考计算机二级C语言为什么考二级C语言?刷题总结后发布系列文章后记免责声明 前言 大家好,我是梁国庆。 计算机二级应该是每一位大学生的必修课,相信很多同学的大学flag中都会有它的身影。 我在大学里也不止一次的想要考计算…

如何下载iSlide软件及详细安装步骤

iSlide插件是一款能够支持PPT和WPS的ppt插件,旨在让每一个人都能够轻松制作出精美的ppt,能够在职场收到更多的关注,而该软件的口号正是「让 PPT 设计简单起来」,该插件是由原来NT插件升级改良过来的,在功能上面进行了全…

代码随想录算法训练营第51天:股票2

代码随想录算法训练营第51天:股票2 ‍ 123.买卖股票的最佳时机III 力扣题目链接(opens new window) 给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。 设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。 注意&a…

01 Pytorch 基础

1.数据处理 1.取一个数据,以及计算大小 (剩下的工作,取batch,pytorch会自动做好了) 2.模型相关 如何得到结果 3.模型训练/模型验证: 代码剖析 1.配置文件yaml (字典) #参数配置config {"train_path"…

centos7.6使用飞鱼FlyFish的docker镜像

参考教程: 飞鱼的docker镜像使用教程: doc/FlyFish_docker镜像使用指南.md 云智慧/FlyFish - Gitee.com centos的docker安装教程: CentOS下 Docker、Docker Compose 的安装教程_centos安装docker-compose_centos 安装docker-compose-CSDN…

ER实体关系图与数据库模型图绘制

属性分析 1、用户表(user)、用户钱包表(user_wallet)(与user是1对1关系)、用户钱包交易日志表(user_wallet_log)(与user是1对多关系)。 user:用户表通常包含用户的基本信息,例如用户ID(主键)、用户名、密码(通常加密…

C++ 12 之 指针引用

c12指针引用.cpp #include <iostream>using namespace std;struct students12 {int age; };int main() {students12 stu;students12* p &stu; // 结构体指针students12* &pp p; // 结构体指针起别名pp->age 20;// (*pp).age 22;cout << "…

C++并发之锁(std::lock_guard,std::unique_lock)

目录 1 概述2 使用实例3 接口使用3.1 lock_guard3.2 adopt_lock3.3 defer_lock3.4 try_to_lock3.5 try_lock3.6 release3.7 lock3.8 call_one1 概述 锁保护是通过使互斥对象始终处于锁定状态来管理互斥对象的对象。。   在构造时,互斥对象被调用线程锁定,在析构时,互斥被解…

STM32的FreeRtos的学习

首先就是去官网下载一个源文件&#xff1a;FreeRtos官网 下载下来的是一个zip文件&#xff0c;解压缩了。 然后再工程文件夹中创建个文件夹&#xff1a; 在这个文件夹中创建3个文件夹&#xff1a; 然后开始把下载下来的文件夹中的文件挑选出来放到我们的工程文件夹中&#xff1…

uniapp中u-input点击事件失效

当给u-input设置了disabled/readonly属性后&#xff0c;pc浏览器中点击事件失效&#xff0c;但是app/移动端h5中却仍有效 解决办法 给外边包上一个盒子设置点击事件&#xff0c;给input加上css属性&#xff1a;pointer-events&#xff1a;none pointer-events CSS 属性指定在什…

【APP移动端自动化测试】第二节.Appium介绍和常用命令代码实现

文章目录 前言一、Appium介绍和安装二、python代码功能实现 2.1 hello appium 参数详解 2.2 在脚本内启动其他app 2.3 获取app的包名和界面名 2.4 关闭app和驱动对象 2.5 安装和卸载以及是否安装app 2.6 将应用置于后台总结 前言 一、Appium介绍…

[AI资讯·0612] AI测试高考物理题,最高准确率100%,OpenAI与苹果合作,将ChatGPT融入系统中,大模型在物理领域应用潜力显现

AI资讯 国产AI大战高考物理&#xff0c;第1题全对&#xff0c;第2题开始放飞终于放大招了&#xff0c;2024WWDC&#xff0c;苹果开启AI反击战苹果一夜重塑iPhone&#xff01;GPT-4o加持Siri&#xff0c;AI深入所有APPOpenAI确认苹果集成ChatGPT 还任命了两位新高管GPT-4搞不定…

GUI编程(Python)

本章&#xff0c;我们将学习GuI (Graphics User Interface) ,即图形用户界面编程&#xff0c;我们可以通过python提供的丰富的组件&#xff0c;快速的实现使用图形界面和用户交互. GUI编程类似于“搭积木”&#xff0c;将一个个组件(Widget)放到窗口中&#xff0e;如下是 windo…