File类和IO流

File类和IO流

### 文章目录

  • [File类和IO流](#文章目录 File类和IO流 @TOC 前言 一、java.io.File类&IO流原理及流的分类 1.1 File类及其API 1.2 IO流原理及分类 二、节点流的介绍(字符/字节) 2.1 Reader\Writer--字符IO抽象基类 2.2 FileReader\FileWriter--字符IO节点流 2.3 InputStream\OutputStream--字节IO抽象基类 2.4 FileInputStream/FileOutputStream--字节IO节点流 三、处理流的介绍 3.1 缓冲流Buffered--字符流/字节流 3.2 转换流InputStreamReader/OutputStreamWriter(字符-字节) 3.3 数据流&对象流--字节 3.4 补充:序列化&反序列化机制 四、其他流的使用 4.1 标准输入、输出流 4.2 打印流PrintStream/PrintWriter 4.3 Scanner类 4.4 apache-common包的使用 五、企业真题)
  • [@[TOC](文章目录)](#文章目录 File类和IO流 @TOC 前言 一、java.io.File类&IO流原理及流的分类 1.1 File类及其API 1.2 IO流原理及分类 二、节点流的介绍(字符/字节) 2.1 Reader\Writer--字符IO抽象基类 2.2 FileReader\FileWriter--字符IO节点流 2.3 InputStream\OutputStream--字节IO抽象基类 2.4 FileInputStream/FileOutputStream--字节IO节点流 三、处理流的介绍 3.1 缓冲流Buffered--字符流/字节流 3.2 转换流InputStreamReader/OutputStreamWriter(字符-字节) 3.3 数据流&对象流--字节 3.4 补充:序列化&反序列化机制 四、其他流的使用 4.1 标准输入、输出流 4.2 打印流PrintStream/PrintWriter 4.3 Scanner类 4.4 apache-common包的使用 五、企业真题)
  • [前言](#文章目录 File类和IO流 @TOC 前言 一、java.io.File类&IO流原理及流的分类 1.1 File类及其API 1.2 IO流原理及分类 二、节点流的介绍(字符/字节) 2.1 Reader\Writer--字符IO抽象基类 2.2 FileReader\FileWriter--字符IO节点流 2.3 InputStream\OutputStream--字节IO抽象基类 2.4 FileInputStream/FileOutputStream--字节IO节点流 三、处理流的介绍 3.1 缓冲流Buffered--字符流/字节流 3.2 转换流InputStreamReader/OutputStreamWriter(字符-字节) 3.3 数据流&对象流--字节 3.4 补充:序列化&反序列化机制 四、其他流的使用 4.1 标准输入、输出流 4.2 打印流PrintStream/PrintWriter 4.3 Scanner类 4.4 apache-common包的使用 五、企业真题)
  • [一、java.io.File类&IO流原理及流的分类](#文章目录 File类和IO流 @TOC 前言 一、java.io.File类&IO流原理及流的分类 1.1 File类及其API 1.2 IO流原理及分类 二、节点流的介绍(字符/字节) 2.1 Reader\Writer--字符IO抽象基类 2.2 FileReader\FileWriter--字符IO节点流 2.3 InputStream\OutputStream--字节IO抽象基类 2.4 FileInputStream/FileOutputStream--字节IO节点流 三、处理流的介绍 3.1 缓冲流Buffered--字符流/字节流 3.2 转换流InputStreamReader/OutputStreamWriter(字符-字节) 3.3 数据流&对象流--字节 3.4 补充:序列化&反序列化机制 四、其他流的使用 4.1 标准输入、输出流 4.2 打印流PrintStream/PrintWriter 4.3 Scanner类 4.4 apache-common包的使用 五、企业真题)
  • [1.1 File类及其API](#文章目录 File类和IO流 @TOC 前言 一、java.io.File类&IO流原理及流的分类 1.1 File类及其API 1.2 IO流原理及分类 二、节点流的介绍(字符/字节) 2.1 Reader\Writer--字符IO抽象基类 2.2 FileReader\FileWriter--字符IO节点流 2.3 InputStream\OutputStream--字节IO抽象基类 2.4 FileInputStream/FileOutputStream--字节IO节点流 三、处理流的介绍 3.1 缓冲流Buffered--字符流/字节流 3.2 转换流InputStreamReader/OutputStreamWriter(字符-字节) 3.3 数据流&对象流--字节 3.4 补充:序列化&反序列化机制 四、其他流的使用 4.1 标准输入、输出流 4.2 打印流PrintStream/PrintWriter 4.3 Scanner类 4.4 apache-common包的使用 五、企业真题)
  • [1.2 IO流原理及分类](#文章目录 File类和IO流 @TOC 前言 一、java.io.File类&IO流原理及流的分类 1.1 File类及其API 1.2 IO流原理及分类 二、节点流的介绍(字符/字节) 2.1 Reader\Writer--字符IO抽象基类 2.2 FileReader\FileWriter--字符IO节点流 2.3 InputStream\OutputStream--字节IO抽象基类 2.4 FileInputStream/FileOutputStream--字节IO节点流 三、处理流的介绍 3.1 缓冲流Buffered--字符流/字节流 3.2 转换流InputStreamReader/OutputStreamWriter(字符-字节) 3.3 数据流&对象流--字节 3.4 补充:序列化&反序列化机制 四、其他流的使用 4.1 标准输入、输出流 4.2 打印流PrintStream/PrintWriter 4.3 Scanner类 4.4 apache-common包的使用 五、企业真题)
  • [二、节点流的介绍(字符/字节)](#文章目录 File类和IO流 @TOC 前言 一、java.io.File类&IO流原理及流的分类 1.1 File类及其API 1.2 IO流原理及分类 二、节点流的介绍(字符/字节) 2.1 Reader\Writer--字符IO抽象基类 2.2 FileReader\FileWriter--字符IO节点流 2.3 InputStream\OutputStream--字节IO抽象基类 2.4 FileInputStream/FileOutputStream--字节IO节点流 三、处理流的介绍 3.1 缓冲流Buffered--字符流/字节流 3.2 转换流InputStreamReader/OutputStreamWriter(字符-字节) 3.3 数据流&对象流--字节 3.4 补充:序列化&反序列化机制 四、其他流的使用 4.1 标准输入、输出流 4.2 打印流PrintStream/PrintWriter 4.3 Scanner类 4.4 apache-common包的使用 五、企业真题)
  • [2.1 Reader\Writer--字符IO`抽象基类`](#文章目录 File类和IO流 @TOC 前言 一、java.io.File类&IO流原理及流的分类 1.1 File类及其API 1.2 IO流原理及分类 二、节点流的介绍(字符/字节) 2.1 Reader\Writer--字符IO抽象基类 2.2 FileReader\FileWriter--字符IO节点流 2.3 InputStream\OutputStream--字节IO抽象基类 2.4 FileInputStream/FileOutputStream--字节IO节点流 三、处理流的介绍 3.1 缓冲流Buffered--字符流/字节流 3.2 转换流InputStreamReader/OutputStreamWriter(字符-字节) 3.3 数据流&对象流--字节 3.4 补充:序列化&反序列化机制 四、其他流的使用 4.1 标准输入、输出流 4.2 打印流PrintStream/PrintWriter 4.3 Scanner类 4.4 apache-common包的使用 五、企业真题)
  • [2.2 FileReader\FileWriter--字符IO`节点流`](#文章目录 File类和IO流 @TOC 前言 一、java.io.File类&IO流原理及流的分类 1.1 File类及其API 1.2 IO流原理及分类 二、节点流的介绍(字符/字节) 2.1 Reader\Writer--字符IO抽象基类 2.2 FileReader\FileWriter--字符IO节点流 2.3 InputStream\OutputStream--字节IO抽象基类 2.4 FileInputStream/FileOutputStream--字节IO节点流 三、处理流的介绍 3.1 缓冲流Buffered--字符流/字节流 3.2 转换流InputStreamReader/OutputStreamWriter(字符-字节) 3.3 数据流&对象流--字节 3.4 补充:序列化&反序列化机制 四、其他流的使用 4.1 标准输入、输出流 4.2 打印流PrintStream/PrintWriter 4.3 Scanner类 4.4 apache-common包的使用 五、企业真题)
  • [2.3 InputStream\OutputStream--字节IO`抽象基类`](#文章目录 File类和IO流 @TOC 前言 一、java.io.File类&IO流原理及流的分类 1.1 File类及其API 1.2 IO流原理及分类 二、节点流的介绍(字符/字节) 2.1 Reader\Writer--字符IO抽象基类 2.2 FileReader\FileWriter--字符IO节点流 2.3 InputStream\OutputStream--字节IO抽象基类 2.4 FileInputStream/FileOutputStream--字节IO节点流 三、处理流的介绍 3.1 缓冲流Buffered--字符流/字节流 3.2 转换流InputStreamReader/OutputStreamWriter(字符-字节) 3.3 数据流&对象流--字节 3.4 补充:序列化&反序列化机制 四、其他流的使用 4.1 标准输入、输出流 4.2 打印流PrintStream/PrintWriter 4.3 Scanner类 4.4 apache-common包的使用 五、企业真题)
  • [2.4 FileInputStream/FileOutputStream--字节IO`节点流`](#文章目录 File类和IO流 @TOC 前言 一、java.io.File类&IO流原理及流的分类 1.1 File类及其API 1.2 IO流原理及分类 二、节点流的介绍(字符/字节) 2.1 Reader\Writer--字符IO抽象基类 2.2 FileReader\FileWriter--字符IO节点流 2.3 InputStream\OutputStream--字节IO抽象基类 2.4 FileInputStream/FileOutputStream--字节IO节点流 三、处理流的介绍 3.1 缓冲流Buffered--字符流/字节流 3.2 转换流InputStreamReader/OutputStreamWriter(字符-字节) 3.3 数据流&对象流--字节 3.4 补充:序列化&反序列化机制 四、其他流的使用 4.1 标准输入、输出流 4.2 打印流PrintStream/PrintWriter 4.3 Scanner类 4.4 apache-common包的使用 五、企业真题)
  • [三、处理流的介绍](#文章目录 File类和IO流 @TOC 前言 一、java.io.File类&IO流原理及流的分类 1.1 File类及其API 1.2 IO流原理及分类 二、节点流的介绍(字符/字节) 2.1 Reader\Writer--字符IO抽象基类 2.2 FileReader\FileWriter--字符IO节点流 2.3 InputStream\OutputStream--字节IO抽象基类 2.4 FileInputStream/FileOutputStream--字节IO节点流 三、处理流的介绍 3.1 缓冲流Buffered--字符流/字节流 3.2 转换流InputStreamReader/OutputStreamWriter(字符-字节) 3.3 数据流&对象流--字节 3.4 补充:序列化&反序列化机制 四、其他流的使用 4.1 标准输入、输出流 4.2 打印流PrintStream/PrintWriter 4.3 Scanner类 4.4 apache-common包的使用 五、企业真题)
  • [3.1 缓冲流Buffered--字符流/字节流](#文章目录 File类和IO流 @TOC 前言 一、java.io.File类&IO流原理及流的分类 1.1 File类及其API 1.2 IO流原理及分类 二、节点流的介绍(字符/字节) 2.1 Reader\Writer--字符IO抽象基类 2.2 FileReader\FileWriter--字符IO节点流 2.3 InputStream\OutputStream--字节IO抽象基类 2.4 FileInputStream/FileOutputStream--字节IO节点流 三、处理流的介绍 3.1 缓冲流Buffered--字符流/字节流 3.2 转换流InputStreamReader/OutputStreamWriter(字符-字节) 3.3 数据流&对象流--字节 3.4 补充:序列化&反序列化机制 四、其他流的使用 4.1 标准输入、输出流 4.2 打印流PrintStream/PrintWriter 4.3 Scanner类 4.4 apache-common包的使用 五、企业真题)
  • [3.2 转换流InputStreamReader/OutputStreamWriter(字符-字节)](#文章目录 File类和IO流 @TOC 前言 一、java.io.File类&IO流原理及流的分类 1.1 File类及其API 1.2 IO流原理及分类 二、节点流的介绍(字符/字节) 2.1 Reader\Writer--字符IO抽象基类 2.2 FileReader\FileWriter--字符IO节点流 2.3 InputStream\OutputStream--字节IO抽象基类 2.4 FileInputStream/FileOutputStream--字节IO节点流 三、处理流的介绍 3.1 缓冲流Buffered--字符流/字节流 3.2 转换流InputStreamReader/OutputStreamWriter(字符-字节) 3.3 数据流&对象流--字节 3.4 补充:序列化&反序列化机制 四、其他流的使用 4.1 标准输入、输出流 4.2 打印流PrintStream/PrintWriter 4.3 Scanner类 4.4 apache-common包的使用 五、企业真题)
  • [3.3 数据流&对象流--字节](#文章目录 File类和IO流 @TOC 前言 一、java.io.File类&IO流原理及流的分类 1.1 File类及其API 1.2 IO流原理及分类 二、节点流的介绍(字符/字节) 2.1 Reader\Writer--字符IO抽象基类 2.2 FileReader\FileWriter--字符IO节点流 2.3 InputStream\OutputStream--字节IO抽象基类 2.4 FileInputStream/FileOutputStream--字节IO节点流 三、处理流的介绍 3.1 缓冲流Buffered--字符流/字节流 3.2 转换流InputStreamReader/OutputStreamWriter(字符-字节) 3.3 数据流&对象流--字节 3.4 补充:序列化&反序列化机制 四、其他流的使用 4.1 标准输入、输出流 4.2 打印流PrintStream/PrintWriter 4.3 Scanner类 4.4 apache-common包的使用 五、企业真题)
  • [3.4 补充:序列化&反序列化机制](#文章目录 File类和IO流 @TOC 前言 一、java.io.File类&IO流原理及流的分类 1.1 File类及其API 1.2 IO流原理及分类 二、节点流的介绍(字符/字节) 2.1 Reader\Writer--字符IO抽象基类 2.2 FileReader\FileWriter--字符IO节点流 2.3 InputStream\OutputStream--字节IO抽象基类 2.4 FileInputStream/FileOutputStream--字节IO节点流 三、处理流的介绍 3.1 缓冲流Buffered--字符流/字节流 3.2 转换流InputStreamReader/OutputStreamWriter(字符-字节) 3.3 数据流&对象流--字节 3.4 补充:序列化&反序列化机制 四、其他流的使用 4.1 标准输入、输出流 4.2 打印流PrintStream/PrintWriter 4.3 Scanner类 4.4 apache-common包的使用 五、企业真题)
  • [四、其他流的使用](#文章目录 File类和IO流 @TOC 前言 一、java.io.File类&IO流原理及流的分类 1.1 File类及其API 1.2 IO流原理及分类 二、节点流的介绍(字符/字节) 2.1 Reader\Writer--字符IO抽象基类 2.2 FileReader\FileWriter--字符IO节点流 2.3 InputStream\OutputStream--字节IO抽象基类 2.4 FileInputStream/FileOutputStream--字节IO节点流 三、处理流的介绍 3.1 缓冲流Buffered--字符流/字节流 3.2 转换流InputStreamReader/OutputStreamWriter(字符-字节) 3.3 数据流&对象流--字节 3.4 补充:序列化&反序列化机制 四、其他流的使用 4.1 标准输入、输出流 4.2 打印流PrintStream/PrintWriter 4.3 Scanner类 4.4 apache-common包的使用 五、企业真题)
  • [4.1 标准输入、输出流](#文章目录 File类和IO流 @TOC 前言 一、java.io.File类&IO流原理及流的分类 1.1 File类及其API 1.2 IO流原理及分类 二、节点流的介绍(字符/字节) 2.1 Reader\Writer--字符IO抽象基类 2.2 FileReader\FileWriter--字符IO节点流 2.3 InputStream\OutputStream--字节IO抽象基类 2.4 FileInputStream/FileOutputStream--字节IO节点流 三、处理流的介绍 3.1 缓冲流Buffered--字符流/字节流 3.2 转换流InputStreamReader/OutputStreamWriter(字符-字节) 3.3 数据流&对象流--字节 3.4 补充:序列化&反序列化机制 四、其他流的使用 4.1 标准输入、输出流 4.2 打印流PrintStream/PrintWriter 4.3 Scanner类 4.4 apache-common包的使用 五、企业真题)
  • [4.2 打印流PrintStream/PrintWriter](#文章目录 File类和IO流 @TOC 前言 一、java.io.File类&IO流原理及流的分类 1.1 File类及其API 1.2 IO流原理及分类 二、节点流的介绍(字符/字节) 2.1 Reader\Writer--字符IO抽象基类 2.2 FileReader\FileWriter--字符IO节点流 2.3 InputStream\OutputStream--字节IO抽象基类 2.4 FileInputStream/FileOutputStream--字节IO节点流 三、处理流的介绍 3.1 缓冲流Buffered--字符流/字节流 3.2 转换流InputStreamReader/OutputStreamWriter(字符-字节) 3.3 数据流&对象流--字节 3.4 补充:序列化&反序列化机制 四、其他流的使用 4.1 标准输入、输出流 4.2 打印流PrintStream/PrintWriter 4.3 Scanner类 4.4 apache-common包的使用 五、企业真题)
  • [4.3 Scanner类](#文章目录 File类和IO流 @TOC 前言 一、java.io.File类&IO流原理及流的分类 1.1 File类及其API 1.2 IO流原理及分类 二、节点流的介绍(字符/字节) 2.1 Reader\Writer--字符IO抽象基类 2.2 FileReader\FileWriter--字符IO节点流 2.3 InputStream\OutputStream--字节IO抽象基类 2.4 FileInputStream/FileOutputStream--字节IO节点流 三、处理流的介绍 3.1 缓冲流Buffered--字符流/字节流 3.2 转换流InputStreamReader/OutputStreamWriter(字符-字节) 3.3 数据流&对象流--字节 3.4 补充:序列化&反序列化机制 四、其他流的使用 4.1 标准输入、输出流 4.2 打印流PrintStream/PrintWriter 4.3 Scanner类 4.4 apache-common包的使用 五、企业真题)
  • [4.4 apache-common包的使用](#文章目录 File类和IO流 @TOC 前言 一、java.io.File类&IO流原理及流的分类 1.1 File类及其API 1.2 IO流原理及分类 二、节点流的介绍(字符/字节) 2.1 Reader\Writer--字符IO抽象基类 2.2 FileReader\FileWriter--字符IO节点流 2.3 InputStream\OutputStream--字节IO抽象基类 2.4 FileInputStream/FileOutputStream--字节IO节点流 三、处理流的介绍 3.1 缓冲流Buffered--字符流/字节流 3.2 转换流InputStreamReader/OutputStreamWriter(字符-字节) 3.3 数据流&对象流--字节 3.4 补充:序列化&反序列化机制 四、其他流的使用 4.1 标准输入、输出流 4.2 打印流PrintStream/PrintWriter 4.3 Scanner类 4.4 apache-common包的使用 五、企业真题)
  • [五、企业真题](#文章目录 File类和IO流 @TOC 前言 一、java.io.File类&IO流原理及流的分类 1.1 File类及其API 1.2 IO流原理及分类 二、节点流的介绍(字符/字节) 2.1 Reader\Writer--字符IO抽象基类 2.2 FileReader\FileWriter--字符IO节点流 2.3 InputStream\OutputStream--字节IO抽象基类 2.4 FileInputStream/FileOutputStream--字节IO节点流 三、处理流的介绍 3.1 缓冲流Buffered--字符流/字节流 3.2 转换流InputStreamReader/OutputStreamWriter(字符-字节) 3.3 数据流&对象流--字节 3.4 补充:序列化&反序列化机制 四、其他流的使用 4.1 标准输入、输出流 4.2 打印流PrintStream/PrintWriter 4.3 Scanner类 4.4 apache-common包的使用 五、企业真题)

前言

File及各种流都在java.io包下

知识补充:绝对路径&相对路径

  • 绝对路径:从盘符开始的路径,这是一个完整的路径。
  • 相对路径:相对于项目目录的路径,这是一个便捷的路径,开发中经常使用。
    • IDEA中,main中的文件的相对路径,是相对于"当前工程"
    • IDEA中,单元测试方法中的文件的相对路径,是相对于"当前module"

一、java.io.File类&IO流原理及流的分类

1.1 File类及其API

1、File类的理解:------流的端点

  • File类位于java.io包下,本章中涉及到的相关流也都声明在java.io包下。
  • File类的一个对象,对应与操作系统下的一个文件或一个文件目录(或文件夹)
  • File类中声明了新建、删除、获取名称、重命名、删除等操作并没有涉及到文件内容的读写操作------需要使用IO流
  • File类的对象,通常是作为io流操作的文件的端点出现

2、File的内部构造器&API

(1)构造器------创建File对象

  • public File(String pathname) :以pathname为路径创建File对象,可以是绝对路径或者相对路径,如果pathname是相对路径,则默认的当前路径在系统属性user.dir中存储。
  • public File(String parent, String child) :以parent为父路径,child为子路径创建File对象。
  • public File(File parent, String child) :根据一个父File对象和子文件路径创建File对象

(2)常用方法

  • 获取文件和目录的基本信息:
    • public String getName() :获取名称
    • public String getPath() :获取路径,创建File对象提供的路径
    • public String getAbsolutePath():获取绝对路径(完整)
    • public File getAbsoluteFile():获取绝对路径表示的文件
    • public String getParent():获取上层文件目录路径。若无,返回null
    • public long length() :获取文件长度(即:字节数)。不能获取目录的长度--递归可以。
    • public long lastModified() :获取最后一次的修改时间,毫秒值
java 复制代码
File file1 = new File("abc.txt");
String str1 = file.getParent();//相对路径的上层文件目录为空
String str1 = file.getAbsolutePath().getParent();//先得到绝对路径,再根据绝对路径得到当前文件的上层文件路径
File file2 = new File("src/abc.txt");
String str2 = file.getParent();//上层目录为src
  • 列出文件的下一级:
    • public String[] list() :表示该File目录中的所有子文件或目录。------可以添加过滤器FilenameFilter(),需重写方法public boolean accept(File dir, String name)
    • public File[] listFiles() :表示该File目录中的所有的子文件或目录。
  • File类的重命名功能:
    • public boolean renameTo(File dest):把文件重命名为指定的文件路径。
  • 判断功能的方法:
    • public boolean exists()、isDirectory()、isFile() 、canRead()、canWrite()、isHidden():此File表示的文件或目录是否实际存在、是否为目录、是否为文件、可读、可写、隐藏。
  • 创建或者删除:
    • public boolean createNewFile()、mkdir()、mkdirs()、delete():创建文件,如果已存在则不创建返回false;创建文件目录,如果已存在/上层目录不存在则不创建;创建文件,如果上层不存在则一起创建;删除文件或文件夹(不走回收站,如果是文件目录则里面不能包含文件/文件目录)

判断指定目录下是否有后缀名为.jpg的文件。如果有,就输出该文件名称

java 复制代码
public class FindJPGFileTest {
	//方法1:
	@Test
	public void test1(){
		File srcFile = new File("d:\\code");
		
		String[] fileNames = srcFile.list();
		for(String fileName : fileNames){
			if(fileName.endsWith(".jpg")){
				System.out.println(fileName);
			}
		}
	}
    //方法2:
	@Test
	public void test2(){
		File srcFile = new File("d:\\code");
		
		File[] listFiles = srcFile.listFiles();
		for(File file : listFiles){
			if(file.getName().endsWith(".jpg")){
				System.out.println(file.getAbsolutePath());
			}
		}
	}
    //方法3:
	/*
	 * File类提供了两个文件过滤器方法
	 * public String[] list(FilenameFilter filter)
	 * public File[] listFiles(FileFilter filter)

	 */
	@Test
	public void test3(){
		File srcFile = new File("d:\\code");
		
		File[] subFiles = srcFile.listFiles(new FilenameFilter() {
			
			@Override
			public boolean accept(File dir, String name) {
				return name.endsWith(".jpg");
			}
		});
		
		for(File file : subFiles){
			System.out.println(file.getAbsolutePath());
		}
	}
	
}

遍历指定目录所有文件名称,包括子文件目录中的文件。

拓展1:并计算指定目录占用空间的大小

拓展2:删除指定文件目录及其下的所有文件

java 复制代码
public class ListFilesTest {
	//练习3:(方式1)
    public static void printSubFile(File dir) {
        // 打印目录的子文件
        File[] subfiles = dir.listFiles();
        for (File f : subfiles) {
            if (f.isDirectory()) {// 文件目录
                printSubFile(f);
            } else {// 文件
                System.out.println(f.getAbsolutePath());//输出绝对路径
            }
        }
    }
    // //练习3:(方式2)
    public void listAllSubFiles(File file) {
        if (file.isFile()) {
            System.out.println(file);
        } else {
            File[] all = file.listFiles();
            // 如果all[i]是文件,直接打印
            // 如果all[i]是目录,接着再获取它的下一级
            for (File f : all) {
                listAllSubFiles(f);// 递归调用:自己调用自己就叫递归
            }
        }
    }
    @Test
    public void testListAllFiles(){
        // 1.创建目录对象
        File dir = new File("E:\\teach\\01_javaSE\\_尚硅谷Java编程语言\\3_软件");

        // 2.打印目录的子文件
        printSubFile(dir);
    }

    // 拓展1:求指定目录所在空间的大小
    public long getDirectorySize(File file) {
        // file是文件,那么直接返回file.length()
        // file是目录,把它的下一级的所有file大小加起来就是它的总大小
        long size = 0;
        if (file.isFile()) {
            size = file.length();
        } else {
            File[] all = file.listFiles();// 获取file的下一级
            // 累加all[i]的大小
            for (File f : all) {
                size += getDirectorySize(f);// f的大小;
            }
        }
        return size;
    }

    // 拓展2:删除指定的目录
    public void deleteDirectory(File file) {
        // 如果file是文件,直接delete
        // 如果file是目录,先把它的下一级干掉,然后删除自己
        if (file.isDirectory()) {
            File[] all = file.listFiles();
            // 循环删除的是file的下一级
            for (File f : all) {// f代表file的每一个下级
                deleteDirectory(f);
            }
        }
        // 删除自己
        file.delete();
    }
}

1.2 IO流原理及分类

1、Java IO流原理:

Java程序中,对于数据的输入/输出操作以"流(stream)" 的方式进行,可以看做是一种数据的流动。

I/O流中的I/O是Input/Output的缩写, I/O技术是非常实用的技术,用于处理设备之间的数据传输。如读/写文件,网络通讯等。

  • 输入input:读取外部数据(磁盘、光盘等存储设备的数据)到程序(内存)中。
  • 输出output:将程序(内存)数据输出到磁盘、光盘等存储设备中。

2、流的分类

  • 按数据的流向不同分为:输入流输出流
    • 输入流 :把数据从其他设备上读取到内存中的流。
    • 输出流 :把数据从内存 中写出到其他设备上的流。
  • 按操作数据单位的不同分为:字节流(8bit)字符流(16bit)
    • 字节流 :以字节为单位,读写数据的流。
    • 字符流 :以字符为单位,读写数据的流。
  • 根据IO流的角色不同分为:节点流处理流
    • 节点流:直接从数据源或目的地读写数据
    • 处理流 :不直接连接到数据源或目的地,而是"连接"在已存在的流(节点流或处理流)之上,通过对数据的处理为程序提供更为强大的读写功能。

3、流的API

流的API理解:字符流可以是输入/输出流,也可以是节点流/处理流,字节流同样也是。

节点流可以是字符流/字节流,处理流也是

  • 4个抽象基类:以其父类名作为子类名后缀
抽象基类 抽象基类 节点流 缓冲流(处理流的一种) 转换流 对象流
字节输入 InputStream FileInputStream BufferedInputStream ObjectInputStream
字节输出 OutputStream FileOutputStream BufferedOutputStream ObjecOutputStream
字符输入 Reader FileReader BufferedReader InputStreamReader
字符输出 Writer FileWriter BufferedWriter OutputStreamWriter

上述处理流连接每一行对应的节点流/处理流。

  • 常用的节点流:
    • 文件流: FileInputStream、FileOutputStrean、FileReader、FileWriter
    • 字节/字符数组流: ByteArrayInputStream、ByteArrayOutputStream、CharArrayReader、CharArrayWriter
    • 对数组进行处理的节点流(对应的不再是文件,而是内存中的一个数组)。
  • 常用处理流:
    • 缓冲流:BufferedInputStream、BufferedOutputStream、BufferedReader、BufferedWriter
      • 作用:增加缓冲功能,避免频繁读写硬盘,进而提升读写效率。
    • 转换流:InputStreamReader、OutputStreamReader
      • 作用:实现字节流和字符流之间的转换。
    • 对象流:ObjectInputStream、ObjectOutputStream
      • 作用:提供直接读写Java对象功能

二、节点流的介绍(字符/字节)

1、字符流说明:Java提供一些字符流类,以字符为单位读写数据,专门用于处理文本文件。不能操作图片,视频等非文本文件。

常见的文本文件有如下的格式:.txt、.java、.c、.cpp、.py等。注意:.doc、.xls、.ppt这些都不是文本文件。

2、字节流说明:非文本文件,必须使用字节流。如图片

FileReader、FileWriter本质上调用的还是FileInputStream、FileOutputStream字节流

2.1 Reader\Writer--字符IO抽象基类

1、java.io.Reader抽象类:用于读取字符流的所有类的父类,可以读取字符信息到内存中。定义了字符输入流的基本共性功能方法。

  • public int read(): 从输入流读取一个字符。 虽然读取了一个字符,但是会自动提升为int类型。返回该字符的Unicode编码值。如果已经到达流末尾了,则返回-1。
  • public int read(char[] cbuf): 从输入流中读取一些字符,并将它们存储到字符数组 cbuf中 。每次最多读取cbuf.length个字符。返回实际读取的字符个数。如果已经到达流末尾,没有数据可读,则返回-1。
  • public int read(char[] cbuf,int off,int len):从输入流中读取一些字符,并将它们存储到字符数组 cbuf中,从cbuf[off]开始的位置存储。每次最多读取len个字符。返回实际读取的字符个数。如果已经到达流末尾,没有数据可读,则返回-1。
  • public void close() :关闭此流并释放与此流相关联的任何系统资源。 释放系统资源,否则会造成内存泄漏。

2、java.io.Writer 抽象类:用于写出字符流的所有类的超类,将指定的字符信息写出到目的地。定义了字节输出流的基本共性功能方法。

  • public void write(int c) :写出单个字符。
  • public void write(char[] cbuf) :写出字符数组。
  • public void write(char[] cbuf, int off, int len) :写出字符数组的某一部分。off:数组的开始索引;len:写出的字符个数。
  • public void write(String str) :写出字符串。
  • public void write(String str, int off, int len) :写出字符串的某一部分。off:字符串的开始索引;len:写出的字符个数。
  • public void flush() :刷新该流的缓冲。
  • public void close() :关闭此流。

2.2 FileReader\FileWriter--字符IO节点流

FileReader:文件不存在读取不了

FileWriter:文件不存在会自动创建一个写入,如果已经存在-追加?覆盖?------可以设置

1、执行步骤:

  • 第1步:创建读取或写出的File类的对象
  • 第2步:创建输入流或输出流
  • 第3步:具体的读入或写出的过程。
    • 读入:read(char[] cbuffer)//造小车 / read()//一个一个读
    • 写出:write(string str) / write(char[] cbuffer,0,len)
  • 第四步:关闭流资源,避免内存泄漏

2、注意点

  • 因为涉及到流资源的关闭操作,所以出现异常的话,需要使用try-catch-finally的方式来处理异常
  • 对于输入流来讲,要求File类的对象对应的物理磁盘上的文件必须存在。否则,会报FileNotFoundException
  • 对于输出流来讲,File类的对象对应的物理磁盘上的文件可以不存在。
    • 如果此文件不存在,则在输出的过程中,会自动创建此文件,并写出数据到此文件中。
    • 如果此文件存在,使用 FileWriter(File file)或 FileWriter(File file,false):输出数据过程中,会新建同名的文件对现有的文件进行覆盖。FileWriter(File file,true):输出数据过程中,会在现有的文件的末尾追加写出内容

3、Java.io.FileReader & java.io.FileWriter的API

  • java.io.FileReader 类用于读取字符文件,构造时使用系统默认的字符编码和默认字节缓冲区。
    • FileReader(File file): 创建一个新的 FileReader ,给定要读取的File对象。
    • FileReader(String fileName): 创建一个新的 FileReader ,给定要读取的文件的名称。
  • java.io.FileWriter:写出字符到文件,构造时使用系统默认的字符编码和默认字节缓冲区
    • FileWriter(File file): 创建一个新的 FileWriter,给定要读取的File对象。
    • FileWriter(String fileName): 创建一个新的 FileWriter,给定要读取的文件的名称。
    • FileWriter(File file,boolean append): 创建一个新的 FileWriter,指明是否在现有文件末尾追加内容。

4、flush(刷新)

内置缓冲区,FileWriter只有关闭输出流,才可将写字符写出到文件中。flush()方法可以实现既不关闭流,又可以写出数据。

  • flush() :刷新缓冲区,流对象可以继续使用。
  • close():先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了。

读取hello.txt文件中的字符数据,并显示在控制台上------小车是每次读取/输出覆盖,最后每次读取/输出指定当前轮次的长度,避免最后覆盖不了

写入字符数据

java 复制代码
public class FileReaderWriterTest {
//实现方式3:调用read(char[] cbuf),每次从文件中读取多个字符
    @Test
    public void test3() {
        FileReader fr = null;//避免文件不存在得到的是nul对象
        try {
            //1. 创建File类的对象,对应着物理磁盘上的某个文件
            File file = new File("hello.txt");
            //2. 创建FileReader流对象,将File类的对象作为参数传递到FileReader的构造器中
            fr = new FileReader(file);
            //3. 通过相关流的方法,读取文件中的数据
            char[] cbuf = new char[5];//造小车,每次读取5个字符
            /*
             * read(char[] cbuf) : 每次将文件中的数据读入到cbuf数组中,并返回读入到数组中的
             * 字符的个数。
             * */
            int len; //记录每次读入的字符的个数
            while ((len = fr.read(cbuf)) != -1) {
                //处理char[]数组即可
                //错误:最后不足5个字符的小车没有完全覆盖前5个
//                for(int i = 0;i < cbuf.length;i++){
//                    System.out.print(cbuf[i]);
//                }
                //错误:同样的道理
//                String str = new String(cbuf);
//                System.out.print(str);
                //正确:长度使用当前循环轮次read的长度
//                for(int i = 0;i < len;i++){
//                    System.out.print(cbuf[i]);
//                }
                //正确:和上面是一样的
                String str = new String(cbuf, 0, len);
                System.out.print(str);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //4. 关闭相关的流资源,避免出现内存泄漏
            try {
                if (fr != null)
                    fr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    @Test
    public void test04(){
        FileWriter fw = null;
        try {
            //1. 创建File的对象
            File file = new File("personinfo.txt");
            //2. 创建FileWriter的对象,将File对象作为参数传递到FileWriter的构造器中
            //如果输出的文件已存在,则会对现有的文件进行覆盖
            fw = new FileWriter(file);
//            fw = new FileWriter(file,false);
            //如果输出的文件已存在,则会在现有的文件末尾写入数据
//            fw = new FileWriter(file,true);

            //3. 调用相关的方法,实现数据的写出操作
            //write(String str) / write(char[] cbuf)
            fw.write("I love you,");
            fw.write("you love him.");
            fw.write("so sad".toCharArray());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //4. 关闭资源,避免内存泄漏
            try {
                if (fw != null)
                    fw.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

2.3 InputStream\OutputStream--字节IO抽象基类

1、java.io.InputStream 抽象类:字节输入流的所有类的超类,读取字节信息到内存中。它定义了字节输入流的基本共性功能方法。

  • public int read(): 从输入流读取一个字节。返回读取的字节值。虽然读取了一个字节,但是会自动提升为int类型。如果已经到达流末尾,没有数据可读,则返回-1。
  • public int read(byte[] b): 从输入流中读取一些字节数,并将它们存储到字节数组 b中 。每次最多读取b.length个字节。返回实际读取的字节个数。如果已经到达流末尾,没有数据可读,则返回-1。
  • public int read(byte[] b,int off,int len):从输入流中读取一些字节数,并将它们存储到字节数组 b中,从b[off]开始存储,每次最多读取len个字节 。返回实际读取的字节个数。如果已经到达流末尾,没有数据可读,则返回-1。
  • public void close() :关闭此输入流并释放与此流相关联的任何系统资源。

2、java.io.OutputStream 抽象类:字节输出流的所有类的超类,将指定的字节信息写出到目的地。它定义了字节输出流的基本共性功能方法。

  • public void write(int b) :将指定的字节输出流。虽然参数为int类型四个字节,但是只会保留一个字节的信息写出。
  • public void write(byte[] b):将 b.length字节从指定的字节数组写入此输出流。
  • public void write(byte[] b, int off, int len) :从指定的字节数组写入 len字节,从偏移量 off开始输出到此输出流。
  • public void flush() :刷新此输出流并强制任何缓冲的输出字节被写出。
  • public void close():关闭此输出流并释放与此流相关联的任何系统资源。

2.4 FileInputStream/FileOutputStream--字节IO节点流

1、执行步骤

  • 第1步:创建读取或写出的File类的对象
  • 第2步:创建输入流或输出流
  • 第3步:具体的读入或写出的过程。读入:read(byte[] buffer)写出:write(byte[] buffer,0,len)
  • 第4步:关闭流资源,避免内存泄漏

2、注意点:和FileReader、FileWriter基础之上

  • 字符流只能处理文本文件,非文本文件不行
    字节流通常用来处理非文本文件,但是如果涉及到文本文件的复制也可以。

3、输入/输出节点流的API:

  • java.io.FileInputStream :文件输入流,从文件中读取字节。
    • FileInputStream(File file)`: 通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的 File对象 file命名。
    • FileInputStream(String name): 通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的路径名 name命名。
  • java.io.FileOutputStream :文件输出流,用于将数据写出到文件。
    • public FileOutputStream(File file):创建文件输出流,写出由指定的 File对象表示的文件。
    • public FileOutputStream(String name): 创建文件输出流,指定的名称为写出文件。
    • public FileOutputStream(File file, boolean append): 创建文件输出流,指明是否在现有文件末尾追加内容。

使用FileInputStream\FileOutputStream,实现对文件txt的复制

问题:如果读取/写入编码不一样,可能存在乱码。下面这个复制没有问题,但是如果输出到控制台上就可能会出现乱码

java 复制代码
public class FOSWrite {
	@Test
    public void test05() {
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            //1. 造文件-造流
            //复制图片:成功
//            fis = new FileInputStream(new File("pony.jpg"));
//            fos = new FileOutputStream(new File("pony_copy1.jpg"));

            //复制文本文件:成功
            fis = new FileInputStream(new File("hello.txt"));
            fos = new FileOutputStream(new File("hello1.txt"));

            //2. 复制操作(读、写)
            byte[] buffer = new byte[1024];
            int len;//每次读入到buffer中字节的个数
            while ((len = fis.read(buffer)) != -1) {
                fos.write(buffer, 0, len);
//                String str = new String(buffer,0,len);
//                System.out.print(str);
            }
            System.out.println("复制成功");
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            //3. 关闭资源
            try {
                if (fos != null)
                    fos.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            try {
                if (fis != null)
                    fis.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

三、处理流的介绍

3.1 缓冲流Buffered--字符流/字节流

1、缓冲流介绍:不直接连接到数据源或目的地,而是"连接"在已存在的流(节点流或处理流)之上,通过对数据的处理为程序提供更为强大的读写功能。

针对字符/字节有不同的分类处理方式。

提升文件读写的效率,减少与磁盘交互的次数。

2、缓冲流分类

  • 处理非文本文件的字节流:如:FileInputStream、FileOutputStream
    • BufferedInputStream:read(bytel] buffer)
    • BufferedOutputStream:write(bytel] buffer,0,len)
  • 处理文本文件的字符流:如:FileReader、FileWriter
    • BufferedReader:read(char[] cBuffer)、readLine()//返回字符串--每次读取一行文本中数据,返回的字符串不包含换行符
    • BufferedWriter:write(char[] cBuffer,0,len)、public void newLine()// 写一行行分隔符,由系统属性定义符号。

3、构造器:处理现有流(如:节点流,不是File对象!!!)

  • public BufferedInputStream(InputStream in) :创建一个 新的字节型的缓冲输入流。
  • public BufferedOutputStream(OutputStream out): 创建一个新的字节型的缓冲输出流。
  • public BufferedReader(Reader in) :创建一个 新的字符型的缓冲输入流。
  • public BufferedWriter(Writer out): 创建一个新的字符型的缓冲输出流。

4、实现步骤

  • 第1步:创建File的对象、流的对象(包括文件流、缓冲流)
  • 第2步:使用缓冲流实现 读取数据 或 写出数据的过程(重点)
    • 读取:int read(char[] cbuf / byte[] buffer):每次将数据读入到cbuf / buffer数组中,并返回读入到数组中
    • 写出:void write(string str) / write(char[] cbuf):将str或cbuf写出到文件中
      void write(byte[] buffer)将byte[]写出到文件中
  • 第3步:关闭资源。
    说明:处理流(外层流)的关闭会自动对内层流的关闭操作,因此只需要关闭外层流即可。

测试缓冲流的效率提升:查询API,缓冲流读写方法与基本的流是一致的,我们通过复制大文件(375MB),测试它的效率。

FileInputStream\FileOutputStream及BufferedInputStream\BufferedOuputStream

java 复制代码
//方法1:使用FileInputStream\FileOutputStream实现非文本文件的复制
public void copyFileWithFileStream(String srcPath,String destPath){
    FileInputStream fis = null;
    FileOutputStream fos = null;
    try {
        //1. 造文件-造流
        fis = new FileInputStream(new File(srcPath));
        fos = new FileOutputStream(new File(destPath));

        //2. 复制操作(读、写)
        byte[] buffer = new byte[100];
        int len;//每次读入到buffer中字节的个数
        while ((len = fis.read(buffer)) != -1) {
            fos.write(buffer, 0, len);
        }
        System.out.println("复制成功");
    } catch (IOException e) {
        throw new RuntimeException(e);
    } finally {
        //3. 关闭资源
        try {
            if (fos != null)
                fos.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        try {
            if (fis != null)
                fis.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

@Test
public void test1(){
    String srcPath = "C:\\Users\\shkstart\\Desktop\\01-复习.mp4";
    String destPath = "C:\\Users\\shkstart\\Desktop\\01-复习2.mp4";

    long start = System.currentTimeMillis();

    copyFileWithFileStream(srcPath,destPath);

    long end = System.currentTimeMillis();

    System.out.println("花费的时间为:" + (end - start));//7677毫秒

}

//方法2:使用BufferedInputStream\BufferedOuputStream实现非文本文件的复制
public void copyFileWithBufferedStream(String srcPath,String destPath){
    FileInputStream fis = null;
    FileOutputStream fos = null;
    BufferedInputStream bis = null;
    BufferedOutputStream bos = null;
    try {
        //1. 造文件
        File srcFile = new File(srcPath);
        File destFile = new File(destPath);
        //2. 造流
        fis = new FileInputStream(srcFile);
        fos = new FileOutputStream(destFile);

        bis = new BufferedInputStream(fis);
        bos = new BufferedOutputStream(fos);

        //3. 读写操作
        int len;
        byte[] buffer = new byte[100];
        while ((len = bis.read(buffer)) != -1) {
            bos.write(buffer, 0, len);//先暂存,一次性write到文件中
        }
        System.out.println("复制成功");
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        //4. 关闭资源(如果有多个流,我们需要先关闭外面的流,再关闭内部的流)
        try {
            if (bos != null)
                bos.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        try {
            if (bis != null)
                bis.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }
}
@Test
public void test2(){
    String srcPath = "C:\\Users\\shkstart\\Desktop\\01-复习.mp4";
    String destPath = "C:\\Users\\shkstart\\Desktop\\01-复习2.mp4";

    long start = System.currentTimeMillis();

    copyFileWithBufferedStream(srcPath,destPath);

    long end = System.currentTimeMillis();

    System.out.println("花费的时间为:" + (end - start));//415毫秒

}

3.2 转换流InputStreamReader/OutputStreamWriter(字符-字节)

回顾编码知识:

字符编码:字符、字符串、字符数组------>字节、字节数组(看得懂------>看不懂)

字符节码:字节、字节数组------>字符、字符串、字符数组(看不懂------>看得懂)

存储在文件中:UTF-8英文1字节,中文3字节;GBK中文2字节;ASCII全部1字节,其他字符集都兼容。

在内存中的字符:

char占用2个字节。在内存中使用的字符集是Unidoce字符集------统一码,万国码
注意:这里所说的占用几个字节?
编码方式指的是存储在文件中时占用的字节。而对于内存中的占用几个字节和这个又不一样 ------ 一个字符(char)占用2个字节,举例:'a'、'中':都表示一个字符在内存中都是占用2个字节,当存储到文件中时就根据编码方式占用n个字节(所有编码方式兼容ASCII字符集,因此对于所有的英文字母占1个字节,对于中文采用GBK占用2个字节,采用UTF-8占用3个字节)。

问题:

idea项目编码UTF-8,windows创建的文本文件编码GBK,导入内存就会乱码

使用字节流读入文本文件,数据显示在控制台上(也有自己的编码方式),此时会出现乱码

------解码使用的字符集必须与当初编码时使用的字符集的相同。

1、转换流介绍及其构造器

  • InputStreamReader:Reader的子类,输入型的字节流---指定解码方式--->输入型的字符流。指定字符集方式:指定名称、接受平台的默认字符集。
    • InputStreamReader(InputStream in):创建一个使用默认字符集的字符流。
    • InputStreamReader(InputStream in, String charsetName):创建一个指定字符集的字符流。
  • OutputStreamWriter:Writer的子类,输出型的字符流---指定编码方式--->输出型的字节流。
    • OutputStreamWriter(OutputStream in):创建一个使用默认字符集的字符流。
    • OutputStreamWriter(OutputStream in,String charsetName):创建一个指定字符集的字符流。

转换流InputStreamReader/OutputStreamWriter的使用示例

解码方式必须和文件编码方式一致,即采用字节方式读取,然后解码为字符。

java 复制代码
//使用默认字符集------idea指定的
InputStreamReader isr1 = new InputStreamReader(new FileInputStream("in.txt"));
//使用指定字符集:字节流方式读取文件,使用GBK解码字节,得到输入型的字符流
InputStreamReader isr2 = new InputStreamReader(new FileInputStream("in.txt") , "GBK");

//使用默认字符集
OutputStreamWriter isr = new OutputStreamWriter(new FileOutputStream("out.txt"));
//使用指定的字符集
OutputStreamWriter isr2 = new OutputStreamWriter(new FileOutputStream("out.txt") , "GBK");

把当前module下的《康师傅的话.txt》字符编码为GBK,复制到电脑桌面目录下的《寄语.txt》,字符编码为UTF-8。

思路:以字节流的方式读取gbk格式文件,使用InputStreamReader指定解码格式gbk得到输入型的字符流,再使用OutputStreamWriter将字符流以指定编码uft-8格式转换为字节流存储文件.

java 复制代码
/**
 * @author 尚硅谷-宋红康
 * @create 9:06
 */
public class InputStreamReaderDemo {

    @Test
    public void test() {
        InputStreamReader isr = null;
        OutputStreamWriter osw = null;
        try {
            isr = new InputStreamReader(new FileInputStream("康师傅的话.txt"),"gbk");

            osw = new OutputStreamWriter(new FileOutputStream("C:\\Users\\shkstart\\Desktop\\寄语.txt"),"utf-8");

            char[] cbuf = new char[1024];
            int len;
            while ((len = isr.read(cbuf)) != -1) {
                osw.write(cbuf, 0, len);
                osw.flush();
            }
            System.out.println("文件复制完成");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (isr != null)
                    isr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (osw != null)
                    osw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

}

3.3 数据流&对象流--字节

为什么需要数据流、对象流?将内存中定义的变量(包括基本数据类型或引用数据类型)保存在文件中。

java 复制代码
Student stu = new Student("张三",23,89);

1、数据流、对象流介绍

  • 数据流:缺点:支持基本数据类型、字符串,不支持其它Java对象的类型。
    • DataInputStream:文件中保存的数据还原为内存中的基本数据类型、String类型的变量。
    • DataOutputStream:内存中的变量------》输出流中
  • 对象流:可以把Java中的对象写入到数据源中,也能把对象从数据源中还原回来。
    • ObjectInputStream:还原之前写出的基本数据类型的数据和对象进行读入操作,保存在内存中。------反序列化
    • ObjectOutputStream:将 Java 基本数据类型和对象写入字节输出流中。------序列化

2、对象流构造器&API

public ObjectInputStream(InputStream in) : 创建一个指定的ObjectInputStream。

public ObjectOutputStream(OutputStream out) : 创建一个指定的ObjectOutputStream。

ObjectInputStream中的方法:

java 复制代码
public boolean readBoolean():读取一个 boolean 值
public byte readByte():读取一个 8 位的字节
public short readShort():读取一个 16 位的 short 值
public char readChar():读取一个 16 位的 char 值
public int readInt():读取一个 32 位的 int 值
public long readLong():读取一个 64 位的 long 值
public float readFloat():读取一个 32 位的 float 值
public double readDouble():读取一个 64 位的 double 值
public String readUTF():读取 UTF-8 修改版格式的 String
public void readObject(Object obj):读入一个obj对象
public void close() :关闭此输入流并释放与此流相关联的任何系统资源

ObjectOutputStream中的方法:

java 复制代码
public void writeBoolean(boolean val):写出一个 boolean 值。
public void writeByte(int val):写出一个8位字节
public void writeShort(int val):写出一个16位的 short 值
public void writeChar(int val):写出一个16位的 char 值
public void writeInt(int val):写出一个32位的 int 值
public void writeLong(long val):写出一个64位的 long 值
public void writeFloat(float val):写出一个32位的 float 值。
public void writeDouble(double val):写出一个64位的 double 值
public void writeUTF(String str):将表示长度信息的两个字节写入输出流,后跟字符串 s 中每个字符的 UTF-8 修改版表示形式。根据字符的值,将字符串 s 中每个字符转换成一个字节、两个字节或三个字节的字节组。注意,将 String 作为基本数据写入流中与将它作为 Object 写入流中明显不同。 如果 s 为 null,则抛出 NullPointerException。
public void writeObject(Object obj):写出一个obj对象
public void close() :关闭此输出流并释放与此流相关联的任何系统资源

3.4 补充:序列化&反序列化机制

1、对象序列化机制:使用ObjectOutputStream实现,将内存中的java对象保存在文件中或者通过网络传输出去。

把内存中的Java对象转换成平台无关的二进制流,从而允许把这种二进制流持久地保存在磁盘上,或通过网络将这种二进制流传输到另一个网络节点。//当其它程序获取了这种二进制流,就可以恢复成原来的Java对象。

  • 序列化过程:用一个字节序列可以表示一个对象,该字节序列包含该对象的类型和对象中存储的属性等信息。字节序列写出到文件之后,相当于文件中持久保存了一个对象的信息。
    实现方式:用ObjectOutputStream类保存基本类型数据或对象的机制。方法为:public final void writeObject (Object obj) : 将指定的对象写出。
  • 反序列化过程:该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化。对象的数据、对象的类型和对象中存储的数据信息,都可以用来在内存中创建对象。
    实现方式:反序列化:用ObjectInputStream类读取基本类型数据或对象的机制。方法为:public final Object readObject ():读取一个对象。


2、为什么需要序列化?

序列化是 RMI(Remote Method Invoke、远程方法调用)过程的参数和返回值都必须实现的机制,而 RMI 是 JavaEE 的基础。因此序列化机制是 JavaEE 平台的基础。

序列化的好处,在于可将任何实现了Serializable接口的对象转化为字节数据,使其在保存和传输时可被还原。

Serializable:是一个标记接口,不实现此接口的类将不会使任何状态序列化或反序列化,会抛出NotSerializableException。

3、自定义类实现序列化机制需要满足的条件?

  • 类必须实现java.io.Serializable 接口,使得对象所属的类及其属性是可序列化,即对象支持序列化机制;
  • 要求自定义类声明一个全局常量:static final long serialVersionUID = 42234234L;------唯一标识当前的类。
  • 要求自定义类的各个属性也必须是可序列化的:
    • 基本数据类型的属性默认是可序列化的,无需序列化就是瞬态的,使用transient关键字修饰。
    • 引用类型的属性:实现Serializable 接口。
    • 静态(static)变量的值不会序列化。因为静态变量的值不属于某个对象。

4、反序列化失败问题

  • 如果不声明全局常量serialVersionUID ,系统会自动生成一个针对于当前类的serialVersionUID ,如果修改此类会导致serialVersionUID发生改变,进而导致反序列化时,出现InvalidClassException异常。
    解决方法:显式声明serialVersionUID,如果声明了serialVersionUID,即使在序列化完成之后修改了类导致类重新编译,则原来的数据也能正常反序列化,只是新增的字段值是默认值而已。
  • 对于JVM可以反序列化对象,它必须是能够找到class文件的类。如果找不到该类的class文件,则抛出一个 ClassNotFoundException 异常。

5、使用场景:

网络中的数据传输:要求对象可序列化。

一般情况不会传输自定义的类,而是json字符串(特殊格式的字符串)

只要涉及到对象就需要序列化、反序列化。

四、其他流的使用

4.1 标准输入、输出流

1、系统标准的输入和输出设备:

  • System.in:键盘(默认)------》内存,类型InputStream
  • System.out:内存------》显示器(默认),类型PrintStream,OutputStream的子类FilterOutputStream 的子类。

2、修改默认设备:System类的setIn,setOut方法

  • public static void setIn(InputStream in)
  • public static void setOut(PrintStream out)------结合打印流可以改变

3、System类中有三个常量对象:System.out、System.in、System.err

提问:final声明的常量一旦赋值就不能修改,那么null会空指针异常吗?为什么要小写?set是如何修改这三个的值的?

答:final声明的常量在java的语法体系中不能修改,但是他们是由c/c++等系统函数进行初始化和修改的,所以没有大写,也有set方法。

java 复制代码
public final static InputStream in = null;
public final static PrintStream out = null;
public final static PrintStream err = null;

源码解析:常量能修改的原因

java 复制代码
public static void setOut(PrintStream out) {
    checkIO();
    setOut0(out);
}
public static void setErr(PrintStream err) {
    checkIO();
    setErr0(err);
}
public static void setIn(InputStream in) {
    checkIO();
    setIn0(in);
}
private static void checkIO() {
    SecurityManager sm = getSecurityManager();
    if (sm != null) {
        sm.checkPermission(new RuntimePermission("setIO"));
    }
}
private static native void setIn0(InputStream in);
private static native void setOut0(PrintStream out);
private static native void setErr0(PrintStream err);

从键盘输入字符串,要求将读取到的整行字符串转成大写输出。然后继续进行输入操作,直至当输入"e"或者"exit"时,退出程序。

java 复制代码
System.out.println("请输入信息(退出输入e或exit):");
// 把"标准"输入流(键盘输入------读入到内存中的流)这个字节流包装成字符流(处理流之转换流),再包装成缓冲流
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String s = null;
try {
    while ((s = br.readLine()) != null) { // 读取用户输入的一行数据 --> 阻塞程序
        if ("e".equalsIgnoreCase(s) || "exit".equalsIgnoreCase(s)) {
            System.out.println("安全退出!!");
            break;
        }
        // 将读取到的整行字符串转成大写输出
        System.out.println("-->:" + s.toUpperCase());
        System.out.println("继续输入信息");
    }
} catch (IOException e) {
    e.printStackTrace();
} finally {
    try {
        if (br != null) {
            br.close(); // 关闭过滤流时,会自动关闭它包装的底层节点流
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

4.2 打印流PrintStream/PrintWriter

1、打印流作用:基本数据类型------》字符串输出

  • 可以输出多种数据类型:提供了一系列重载的print()和println()方法
  • PrintStream和PrintWriter的输出不会抛出IOException异常
  • PrintStream和PrintWriter有自动flush功能
  • PrintStream 打印的所有字符都使用平台的默认字符编码转换为字节。在需要写入字符而不是写入字节的情况下,应该使用 PrintWriter 类。
  • System.out返回的是PrintStream的实例

2、打印流的构造器

  • PrintStream(File file) :创建具有指定文件且不带自动行刷新的新打印流。
  • PrintStream(File file, String csn):创建具有指定文件名称和字符集且不带自动行刷新的新打印流。
  • PrintStream(OutputStream out) :创建新的打印流。
  • PrintStream(OutputStream out, boolean autoFlush):创建新的打印流。 autoFlush如果为 true,则每当写入 byte 数组、调用其中一个 println 方法或写入换行符或字节 ('\n') 时都会刷新输出缓冲区。
  • PrintStream(OutputStream out, boolean autoFlush, String encoding) :创建新的打印流。
  • PrintStream(String fileName):创建具有指定文件名称且不带自动行刷新的新打印流。
  • PrintStream(String fileName, String csn) :创建具有指定文件名称和字符集且不带自动行刷新的新打印流。

使用示例:自定义一个日志工具

java 复制代码
/*
日志工具
 */
public class Logger {
    /*
    记录日志的方法。
     */
    public static void log(String msg) {
        try {
            // 指向一个日志文件
            PrintStream out = new PrintStream(new FileOutputStream("log.txt", true));
            // 改变输出方向
            System.setOut(out);
            // 日期当前时间
            Date nowTime = new Date();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
            String strTime = sdf.format(nowTime);

            System.out.println(strTime + ": " + msg);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
}

测试日志工具

java 复制代码
public class LogTest {
    public static void main(String[] args) {
        //测试工具类是否好用
        Logger.log("调用了System类的gc()方法,建议启动垃圾回收");
        Logger.log("调用了TeamView的addMember()方法");
        Logger.log("用户尝试进行登录,验证失败");
    }
}

4.3 Scanner类

1、构造方法

  • Scanner(File source) :构造一个新的 Scanner,它生成的值是从指定文件扫描的。
  • Scanner(File source, String charsetName) :构造一个新的 Scanner,它生成的值是从指定文件扫描的。
  • Scanner(InputStream source) :构造一个新的 Scanner,它生成的值是从指定的输入流扫描的。
  • Scanner(InputStream source, String charsetName) :构造一个新的 Scanner,它生成的值是从指定的输入流扫描的。

2、常用方法:

  • boolean hasNextXxx(): 如果通过使用nextXxx()方法,此扫描器输入信息中的下一个标记可以解释为默认基数中的一个 Xxx 值,则返回 true。
  • Xxx nextXxx(): 将输入信息的下一个标记扫描为一个Xxx
java 复制代码
package com.atguigu.systemio;

import org.junit.Test;

import java.io.*;
import java.util.Scanner;

public class TestScanner {

    @Test
    public void test01() throws IOException {
        Scanner input = new Scanner(System.in);
        PrintStream ps = new PrintStream("1.txt");
        while(true){
            System.out.print("请输入一个单词:");
            String str = input.nextLine();
            if("stop".equals(str)){
                break;
            }
            ps.println(str);
        }
        input.close();
        ps.close();
    }
    
    @Test
    public void test2() throws IOException {
        Scanner input = new Scanner(new FileInputStream("1.txt"));
        while(input.hasNextLine()){
            String str = input.nextLine();
            System.out.println(str);
        }
        input.close();
    }
}

4.4 apache-common包的使用

1、作用:IO技术的工具类commonsIO,简化IO开发。

Oracle第一方,我们自己第二方,其他都是第卅安防

2、使用方式:导入commons-io-2.5.jar包,使用内部的API。

  • IOUtils类的使用
    • 静态方法:IOUtils.copy(InputStream in,OutputStream out)传递字节流,实现文件复制。
    • 静态方法:IOUtils.closeQuietly(任意流对象)悄悄的释放资源,自动处理close()方法抛出的异常。
  • FileUtils类的使用
    • 静态方法:void copyDirectoryToDirectory(File src,File dest):整个目录的复制,自动进行递归遍历
      参数:
      src:要复制的文件夹路径
      dest:要将文件夹粘贴到哪里去
    • 静态方法:void writeStringToFile(File file,String content):将内容content写入到file中
    • 静态方法:String readFileToString(File file):读取文件内容,并返回一个String
    • 静态方法:void copyFile(File srcFile,File destFile):文件复制

IOUtils类的使用

java 复制代码
public class Test01 {
    public static void main(String[] args)throws Exception {
        //- 静态方法:IOUtils.copy(InputStream in,OutputStream out)传递字节流,实现文件复制。
        IOUtils.copy(new FileInputStream("E:\\Idea\\io\\1.jpg"),new FileOutputStream("E:\\Idea\\io\\file\\柳岩.jpg"));
        //- 静态方法:IOUtils.closeQuietly(任意流对象)悄悄的释放资源,自动处理close()方法抛出的异常。
       /* FileWriter fw = null;
        try {
            fw = new FileWriter("day21\\io\\writer.txt");
            fw.write("hahah");
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
           IOUtils.closeQuietly(fw);
        }*/
    }
}

FileUtils类的使用

java 复制代码
public class Test02 {
    public static void main(String[] args) {
        try {
            //- 静态方法:void copyDirectoryToDirectory(File src,File dest);
            FileUtils.copyDirectoryToDirectory(new File("E:\\Idea\\io\\aa"),new File("E:\\Idea\\io\\file"));


            //- 静态方法:writeStringToFile(File file,String str)
            FileUtils.writeStringToFile(new File("day21\\io\\commons.txt"),"柳岩你好");

            //- 静态方法:String readFileToString(File file)
            String s = FileUtils.readFileToString(new File("day21\\io\\commons.txt"));
            System.out.println(s);
            //- 静态方法:void copyFile(File srcFile,File destFile)
            FileUtils.copyFile(new File("io\\yangm.png"),new File("io\\yangm2.png"));
            System.out.println("复制成功");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

五、企业真题

1、谈谈Java IO里面的常用类,字节流,字符流

File、字符流、字节流的抽象基类。

2、Java 中有几种类型的流?JDK为每种类型的流提供一些抽象类以供继承,请说出他们分别是哪些类?

InputStream \ OutputStream \ Reader \ Writer

3、流一般需不需要关闭?如果关闭的话用什么方法?处理流是怎么关闭的?

需要。close()

处理流在关闭过程中,也会关闭内部的流。

4、OutputStream里面的write()是什么意思?

数据写出的意思。理解为从内存写出到文件中

5、BufferedReader属于哪种流?他主要是用来做什么的?

缓冲流,作用:不直接连接到数据源或目的地,而是"连接"在已存在的流(节点流或处理流)之上,通过对数据的处理为程序提供更为强大的读写功能。提升文件读写的效率,减少与磁盘交互的次数。

6、什么是缓冲区?有什么作用?

内部提供了一个数组,将读取或要写出的数据,现在此数组中缓存。达到一定程度时,集中性的写出。

作用:减少与磁盘的交互,进而提升读写效率。

7、字节流和字符流是什么?怎么转换?

字节流:二进制流,字符流:一个一个字符

InputStreamReader、OutputStreamWriter

输入型字节流------》输入型字符流

输出型字符流------》输出型字节流

8、什么是Java序列化,如何实现

对象序列化机制允许把内存中的Java对象转换成平台无关的二进制流,从而允许把这种二进制流持久地保存在磁盘上,

或通过网络将这种二进制流传输到另一个网络节点。//当其它程序获取了这种二进制流,就可以恢复成原来的Java对象。

9、Java有些类中为什么需要实现Serializable接口?

便于此类的对象实现序列化操作。标记接口,显式声明,当反序列化时回去找该对象,以便能够正确反序列化,如果不显式声明的化,那么当修改类后生成不同的class文件的uid会发生改变,导致反序列化不成功。

相关推荐
虫小宝25 分钟前
如何在Java中实现PDF生成
java·开发语言·pdf
菜鸡且互啄691 小时前
在线教育平台,easyexcel使用案例
java·开发语言
八月林城1 小时前
JAVA导出数据库字典到Excel
java·数据库·excel
电饭叔2 小时前
《python程序语言设计》2018版第5章第52题利用turtle绘制sin函数
开发语言·python
weixin_452600692 小时前
如何为老化的汽车铅酸电池充电
开发语言·单片机·安全·汽车·电机·电源模块·充电桩
浅念同学3 小时前
算法-常见数据结构设计
java·数据结构·算法
Java资深爱好者3 小时前
如何在std::map中查找元素
开发语言·c++
YCCX_XFF213 小时前
ImportError: DLL load failed while importing _imaging: 操作系统无法运行 %1
开发语言·python
哥廷根数学学派4 小时前
基于Maximin的异常检测方法(MATLAB)
开发语言·人工智能·深度学习·机器学习
杰哥在此5 小时前
Java面试题:讨论持续集成/持续部署的重要性,并描述如何在项目中实施CI/CD流程
java·开发语言·python·面试·编程