yday10【File类、递归、IO流、字节流、字符流】
今日内容
- File类----->重点掌握
- 概述
- 构造方法
- 成员方法
- 递归------>理解
- 如何递归(实现)
- 分析递归程序的执行流程
- IO流的概述和分类---->了解
- 输入和输出的概念
- IO流的分类
- 字节流----->重点掌握
- 字节输入流: 读数据
- 字节输出流: 写数据
- 字符流----->重点掌握
- 字符输入流: 读数据
- 字符输出流: 写数据
第一章 File类
1.1 File类的概述和构造方法
File类的概述
java.io.File
类是用来表示文件或者文件夹路径,可以用于对文件和文件夹的创建、查找和删除等操作。
File类的构造方法
-
public File(String pathname)
:通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例。 -
public File(String parent, String child)
:从父路径名字符串和子路径名字符串创建新的 File实例。 -
public File(File parent, String child)
:从父抽象路径名和子路径名字符串创建新的 File实例。 -
注意:
- 创建File对象时,如果传入的文件或者文件夹路径不存在,依然不影响File对象的创建
-
构造举例,代码如下:
public class Test { public static void main(String[] args) { // 文件或者文件夹真实存在 // 需求: 创建一个File对象表示G:\szitheima112\day10\aaa\hb.jpg // - public File(String pathname) :通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例。 File f1 = new File("G:\\szitheima112\\day10\\aaa\\hb.jpg"); // - public File(String parent, String child) :从父路径名字符串和子路径名字符串创建新的 File实例。 //File f2 = new File("G:\\szitheima112\\day10\\aaa", "hb.jpg"); File f2 = new File("G:\\szitheima112\\day10", "aaa\\hb.jpg"); // - public File(File parent, String child) :从父抽象路径名和子路径名字符串创建新的 File实例。 File parent = new File("G:\\szitheima112\\day10"); File f3 = new File(parent, "aaa\\hb.jpg"); System.out.println("f1:" + f1); System.out.println("f2:" + f2); System.out.println("f3:" + f3); // 文件或者文件夹不存在 File f4 = new File("G:\\szitheima112\\day10\\aaa\\a.txt"); System.out.println("f4:" + f4); File f5 = new File("G:\\szitheima112\\day10\\aaa\\bbb"); System.out.println("f5:" + f5); } }
1.2 File类常用方法
绝对路径和相对路径
- 绝对路径:从盘符开始的路径,这是一个完整的路径。
- 相对路径:相对于项目目录的路径,这是一个便捷的路径,开发中经常使用。
- 举例:
-
生活中的例子: 你现在在中粮商务公园2栋607,你朋友在中粮商务公园,他问你在哪?
- 绝对路径: 中国广东省深圳市宝安区留仙二路中粮商务公园2栋607
- 相对路径: 2栋607
-
程序中的例子: hb.jpg文件
- 绝对路径: G:\szitheima112\day10\aaa\hb.jpg
- 相对路径: day10\aaa\hb.jpg
-
public class Test {
public static void main(String[] args) {
/*
- 绝对路径:从盘符开始的路径,这是一个完整的路径。
- 相对路径:相对于项目目录的路径,这是一个便捷的路径,开发中经常使用。
*/
// 绝对路径:
File f1 = new File(“G:\szitheima112\day10\aaa\hb.jpg”);
// 相对路径:
File f2 = new File("day10\\aaa\\hb.jpg");
}
}
```
获取功能的方法
-
public String getAbsolutePath()
:返回此File的绝对路径名字符串。 -
public String getPath()
:将此File转换为路径名字符串。 构造路径 -
public String getName()
:返回由此File表示的文件或目录的名称。 -
public long length()
:返回由此File表示的文件的长度。 不能获取目录的长度。方法演示,代码如下:
public class Test { public static void main(String[] args) { // 创建File对象 File f1 = new File("G:\\szitheima112\\day10\\aaa\\hb.jpg"); File f2 = new File("day10\\aaa\\hb.jpg"); // - public String getAbsolutePath() :返回此File的绝对路径名字符串。 System.out.println("绝对路径:" + f1.getAbsolutePath()); System.out.println("绝对路径:" + f2.getAbsolutePath()); // - public String getPath() :将此File转换为路径名字符串。构造路径 System.out.println("构造路径:" + f1.getPath()); System.out.println("构造路径:" + f2.getPath()); // - public String getName() :返回由此File表示的文件或目录的名称。 System.out.println("文件名:" + f2.getName()); // - public long length() :返回由此File表示的文件的长度。 不能获取文件夹的长度。 System.out.println("文件的字节大小:" + f2.length());// 24666 File f3 = new File("day10\\aaa"); System.out.println("文件夹的字节大小:" + f3.length());// 0,不能获取文件夹的字节大小,只能获取文件的字节大小 } }
判断功能的方法
-
public boolean exists()
:此File表示的文件或目录是否实际存在。 -
public boolean isDirectory()
:此File表示的是否为目录。 -
public boolean isFile()
:此File表示的是否为文件。 -
注意: 如果File对象表示的路径不存在,以上三个方法的返回值都是false
方法演示,代码如下:
public class Test { public static void main(String[] args) { // 文件或文件夹是真实存在的 // 创建File对象 File f1 = new File("day10\\aaa\\hb.jpg"); File f2 = new File("day10\\aaa"); //- public boolean exists() :此File表示的文件或目录是否实际存在。 System.out.println("f1表示的文件是否存在: " + f1.exists());// true System.out.println("f2表示的文件夹是否存在: " + f2.exists());// true System.out.println("========"); //- public boolean isDirectory() :此File表示的是否为目录。 System.out.println("f1表示的是否是文件夹:" + f1.isDirectory());// false System.out.println("f2表示的是否是文件夹:" + f2.isDirectory());// true System.out.println("========"); //- public boolean isFile() :此File表示的是否为文件。 System.out.println("f1表示的是否是文件:" + f1.isFile());// true System.out.println("f2表示的是否是文件:" + f2.isFile());// false System.out.println("========"); // 文件或文件夹不是真实存在的 File f = new File("day10\\aaa\\a.txt"); System.out.println("f表示的文件是否真实存在:" + f.exists());// false System.out.println("f表示的是否是文件夹:" + f.isDirectory());//false System.out.println("f表示的是否是文件:" + f.isFile());// false } }
创建删除功能的方法
-
public boolean createNewFile()
:当且仅当具有该名称的文件尚不存在时,创建一个新的空文件。 -
public boolean delete()
:删除由此File表示的文件或目录。 删除文件,或者删除空文件夹, 不能删除非空文件夹 -
public boolean mkdir()
:创建由此File表示的目录。 -
public boolean mkdirs()
:创建由此File表示的目录,包括任何必需但不存在的父目录。方法演示,代码如下:
public class Test { public static void main(String[] args) throws IOException { //- public boolean createNewFile() :当且仅当具有该名称的文件尚不存在时,创建一个新的空文件。 // File f1 = new File("day10\\aaa\\b.txt"); // boolean res1 = f1.createNewFile(); // System.out.println("res1:" + res1); // 注意: 这里会创建一个未知文件类型的bbb文件 // File f2 = new File("day10\\aaa\\bbb"); // boolean res2 = f2.createNewFile(); // System.out.println("res2:" + res2); //- public boolean delete() :删除由此File表示的文件或目录。 不能删除非空文件夹 // 注意: delete删除的文件不在回收站,注意使用 // File f3 = new File("day10\\aaa\\b.txt"); // boolean res3 = f3.delete(); // System.out.println("res3:" + res3); // File f4 = new File("day10\\aaa\\bbb"); // boolean res4 = f4.delete(); // System.out.println("res4:" + res4); // 注意: 不能删除非空文件夹 //File f5 = new File("day10\\aaa"); //boolean res5 = f5.delete(); //System.out.println("res5:" + res5); // 注意: 可以删除空文件夹 // File f6 = new File("day10\\bbb"); // boolean res6 = f6.delete(); // System.out.println("res6:" + res6); //- public boolean mkdir() :创建由此File表示的目录。 // File f7 = new File("day10\\ccc"); // boolean res7 = f7.mkdir(); // System.out.println("res7:" + res7); //- public boolean mkdirs() :创建由此File表示的目录,包括任何必需但不存在的父目录。 File f8 = new File("day10\\ccc\\aaa\\bbb\\ccc\\ddd"); boolean res8 = f8.mkdirs(); System.out.println("res8:" + res8); } }
遍历目录方法
-
public String[] list()
:获取File目录中的所有子文件或子目录的名称。 -
public File[] listFiles()
:获取File目录中的所有子文件或子目录的路径。 -
结论; 循环遍历返回的数组之前,建议做非空判断,避免空指针异常
public class Test { public static void main(String[] args) { // 创建File对象 File f = new File("day10"); //- public String[] list() :获取File目录中的所有子文件或子目录的名称。 String[] arr1 = f.list(); for (String name : arr1) { System.out.println("name:" + name); } //- public File[] listFiles() :获取File目录中的所有子文件或子目录的路径。 File[] arr2 = f.listFiles(); for (File pathFile : arr2) { System.out.println("pathFile:" + pathFile); } System.out.println("-------"); // 注意: 文件夹不存在,返回null File f1 = new File("day10\\bbb"); File[] arr3 = f1.listFiles();// 返回的null // 增强程序的健壮性,应该判断 if (arr3 != null) { for (File file : arr3) { System.out.println("file:" + file); } } // 注意: 文件夹没有访问权限,返回null File f2 = new File("H:\\System Volume Information"); File[] arr4 = f2.listFiles();// 返回的null // 增强程序的健壮性,应该判断 if (arr4 != null) { for (File file : arr4) { System.out.println("file:" + file); } } // 注意: 文件夹为空,返回的是长度为0的数组 File f3 = new File("day10\\ddd"); File[] arr5 = f3.listFiles();// 返回的是长度为0的数组 for (File file : arr5) { System.out.println("file:" + file); } } }
第二章 递归
2.1 递归的概述
-
概述:
- 生活中的递归: 放羊–>赚钱–>盖房子–>娶媳妇–>生娃–>放羊–>赚钱–>盖房子–>娶媳妇–>生娃–>放羊…
- 程序中的递归: 方法自己调用自己
- 注意:
- 1.递归没有出口,就会报栈内存溢出错误StackOverflowError
- 2.出口不能太晚了,否则也会报栈内存溢出错误StackOverflowError
-
案例
public class Test { static int count = 0; public static void main(String[] args) { method1(); } public static void method1(){ count++; // 出口--递归结束 if (count > 10000){ return; } // 调用method1方法 method1(); System.out.println("method1方法..."); } }
2.2 递归累和
需求
- 定义一个方法,使用递归计算1 ~ n的累加和
分析
- 什么时候递归------->规律
- 什么时候结束递归---->出口
- n的累加和 = 1 + 2 + 3 + … + n-1 + n
- n-1的累加和= 1 + 2 + 3 + … + n-1
- …
- 规律: 一个数的累加和 = 前一个数的累加和 + 当前这个数
- n的累加和 = n + (n-1)的累加和
实现
public class Test {
public static void main(String[] args) {
// 需求:定义一个方法,使用递归计算1 ~ n的累加和
System.out.println(getSum(5));// 15
}
/**
* 计算一个数的累加和
* @param n
* @return sum
*/
public static int getSum(int n){
// 出口
if (n == 1){
return 1;
}
// 规律
return n + getSum(n - 1);
}
}
代码执行图解
2.3 递归求阶乘
需求
- 计算n的阶乘
分析
- 阶乘:所有小于及等于该数的正整数的积。
n的阶乘:n! = n * (n-1) *...* 3 * 2 * 1
n的阶乘 = n * (n1)的阶乘,所以可以把阶乘的操作定义成一个方法,递归调用。
推理得出:n! = n * (n-1)!
实现
public class Test {
public static void main(String[] args) {
System.out.println(jieCheng(5));// 120
}
/**
* 计算阶乘的方法
* @param n
* @return 阶乘
*/
public static int jieCheng(int n){
// 出口
if (n == 1){
return 1;
}
// 规律
return n * jieCheng(n-1);
}
}
2.4 文件搜索
需求
- 输出day10目录中的所有.java文件的绝对路径。
分析
- 获取文件夹中所有的子文件和子文件夹
- 循环遍历所有的子文件和子文件夹
- 如果遍历出来的是文件,就判断该文件是否是.java文件,如果是就直接打印输出该文件的绝对路径
- 如果遍历出来的是文件夹,就递归
实现
public class Test {
public static void main(String[] args) {
File file = new File("day10");
//findFile(file,".java");
findFile(file,"jpg");
}
/**
* 查找文件
*
* @param file
*/
public static void findFile(File file,String type) {
//1. 获取文件夹中所有的子文件和子文件夹
File[] arr = file.listFiles();
//2. 循环遍历所有的子文件和子文件夹
if (arr != null) {
for (File file1 : arr) {
//3. 如果遍历出来的是文件,就判断该文件是否是.java文件,如果是就直接打印输出该文件的绝对路径
if (file1.isFile() && file1.getName().endsWith(type)){
System.out.println("绝对路径:"+file1.getAbsolutePath());
}
//4. 如果遍历出来的是文件夹,就递归
if (file1.isDirectory()){
findFile(file1,type);
}
}
}
}
/**
* 查找文件
*
* @param file
*/
public static void findFile(File file) {
//1. 获取文件夹中所有的子文件和子文件夹
File[] arr = file.listFiles();
//2. 循环遍历所有的子文件和子文件夹
if (arr != null) {
for (File file1 : arr) {
//3. 如果遍历出来的是文件,就判断该文件是否是.java文件,如果是就直接打印输出该文件的绝对路径
if (file1.isFile() && file1.getName().endsWith(".java")){
System.out.println("绝对路径:"+file1.getAbsolutePath());
}
//4. 如果遍历出来的是文件夹,就递归
if (file1.isDirectory()){
findFile(file1);
}
}
}
}
}
第三章 IO概述
IO的概述
- I : Input 输入 从其他存储设备读数据到内存中就是输入
- O : Output 输出 从内存中写数据到其他存储设备
IO的分类
- 按照类型分: 字节流和字符流
- 字节流: 以字节为基本单位,进行读写数据
- 字节输入流: 以字节为基本单位,进行读数据
- 字节输出流: 以字节为基本单位,进行写数据
- 字符流: 以字符为基本单位,进行读写数据
- 字符输入流: 以字符为基本单位,进行读数据
- 字符输出流: 以字符为基本单位,进行写数据
- 字节流: 以字节为基本单位,进行读写数据
- 按流向分: 输入流和输出流
- 输入流:
- 字节输入流: 以字节为基本单位,进行读数据
- 字符输入流: 以字符为基本单位,进行读数据
- 输出流:
- 字节输出流: 以字节为基本单位,进行写数据
- 字符输出流: 以字符为基本单位,进行写数据
- 输入流:
IO的顶层父类
- 字节输入流: 顶层父类是InputStream,抽象类
- 字节输出流: 顶层父类是OutputStream,抽象类
- 字符输入流: 顶层父类是Reader,抽象类
- 字符输出流: 顶层父类是Writer,抽象类
注意事项
- utf8编码一个中文占3个字节,gbk编码一个中文占2个字节
- 如果存储和解析的编码不一致就会乱码
- idea默认编码是utf8
第四章 字节流
4.1 字节输出流【OutputStream】
OutputStream类的概述
-
概述:
java.io.OutputStream
抽象类是表示字节输出流的所有类的父类 -
作用:
- 将指定的字节信息写出到目的地文件中。
- 它定义了所有字节输出流的基本共性功能方法。(所有类都继承了OutputStream)
OutputStream类的常用方法
public void close()
:关闭此输出流并释放与此流相关联的任何系统资源。public abstract void write(int b)
:写出一个字节数据到目的地文件中。public void write(byte[] b)
:将 b.length字节写出到目的地文件中。public void write(byte[] b, int off, int len)
:从指定的字节数组写入 len字节,从偏移量 off开始输出到此输出流。
小贴士:
close方法,当完成流的操作时,必须调用此方法,释放系统资源。
4.2 FileOutputStream类
-
概述: java.io.FileOutputStream类继承了OutputStream类,所以也是表示字节输出流,可以用来写出数据到目的地文件中.
-
构造方法
-
public FileOutputStream(File fPath) 创建一个字节输出流对象,关联的文件通过参数来指定
-
public FileOutputStream(String path) 创建一个字节输出流对象,关联的文件通过参数来指定
-
注意:
- 如果关联的文件不存在,就会自动创建一个新的空文件
- 如果关联的文件存在,就会清空源文件中的数据
-
案例:
public class Test { public static void main(String[] args)throws Exception { // 文件存在 FileOutputStream fos1 = new FileOutputStream(new File("day10\\eee\\a.txt")); // 文件不存在 FileOutputStream fos2 = new FileOutputStream("day10\\eee\\b.txt"); } }
-
-
写出数据的方法
-
写一个字节:
public void write(int b)
:写出一个字节数据到目的地文件中。public class Test1_写一个字节 { public static void main(String[] args) throws Exception{ // 创建字节输出流对象,关联目的地文件路径 FileOutputStream fos = new FileOutputStream("day10\\eee\\c.txt"); // 写出数据 fos.write(97); fos.write('b'); // 关闭流,释放资源 fos.close(); } } 文件: ab
-
写字节数组:
public void write(byte[] b)
:将 b.length字节写出到目的地文件中。public class Test2_写字节数组 { public static void main(String[] args) throws Exception{ // 创建字节输出流对象,关联目的地文件路径 FileOutputStream fos = new FileOutputStream("day10\\eee\\d.txt"); // 写出数据 byte[] bys = {97,98,99}; fos.write(bys); // 关闭流,释放资源 fos.close(); } } 文件: abc
-
写指定长度字节数组:
public void write(byte[] b, int off, int len)
:从指定的字节数组写入 len字节,从偏移量 off开始输出到此输出流。public class Test3_写指定长度字节数组 { public static void main(String[] args) throws Exception{ // 创建字节输出流对象,关联目的地文件路径 FileOutputStream fos = new FileOutputStream("day10\\eee\\e.txt"); // 写出数据 byte[] bys = {97,98,99,100,101,102}; fos.write(bys,1,3); // 关闭流,释放资源 fos.close(); } } 文件: bcd
-
追加续写---->创建字节输出流对象的时候,不要清空源文件中的数据
-
public FileOutputStream(File fPath,boolean append) 创建一个字节输出流对象,关联的文件通过参数来指定
-
public FileOutputStream(String path,boolean append) 创建一个字节输出流对象,关联的文件通过参数来指定
-
注意:
- 如果关联的文件不存在,就会自动创建一个新的空文件
- 如果关联的文件存在,并且第二个参数设置为true,就不清空源文件中的数据,否则就清空(false)
-
案例
public class Test4_追加续写 { public static void main(String[] args) throws Exception{ // 创建字节输出流对象,关联目的地文件路径 FileOutputStream fos = new FileOutputStream("day10\\eee\\a.txt",true); // 写出数据 fos.write(97); // 关闭流,释放资源 fos.close(); } } 执行前: abcdef 执行后: abcdefa
-
-
写出换行
-
回车符
\r
和换行符\n
:- 回车符:回到一行的开头(return)。
- 换行符:下一行(newline)。
-
系统中的换行:
- Windows系统里,每行结尾是
回车+换行
,即\r\n
; - Unix系统里,每行结尾只有
换行
,即\n
; - Mac系统里,每行结尾是
回车
,即\r
。从 Mac OS X开始与Linux统一。
public class Test5_写出换行 { public static void main(String[] args) throws Exception{ /* 看这风景美如画 本想吟诗赠天下 奈何本人没文化 一句我操浪好大 */ // 创建字节输出流对象,关联目的地文件路径 FileOutputStream fos = new FileOutputStream("day10\\eee\\f.txt"); // 写出数据 fos.write("看这风景美如画\r\n".getBytes()); fos.write("本想吟诗赠天下\r\n".getBytes()); fos.write("奈何本人没文化\r\n".getBytes()); fos.write("一句我操浪好大\r\n".getBytes()); // 关闭流,释放资源 fos.close(); } }
- Windows系统里,每行结尾是
-
-
4.3 字节输入流【InputStream】
InputStream类的概述
java.io.InputStream
抽象类是表示字节输入流的所有类的超类,可以读取字节信息到内存中。它定义了字节输入流的基本共性功能方法。
InputStream类的常用方法
public void close()
:关闭此输入流并释放与此流相关联的任何系统资源。public abstract int read()
: 读一个字节。public int read(byte[] b)
: 读一个字节数组
小贴士:
close方法,当完成流的操作时,必须调用此方法,释放系统资源。
4.4 FileInputStream类
-
概述: java.io.FileInputStream类继承InputStream类,也表示字节输入流,可以用来读字节数据到内存中.
-
构造方法
-
public FileInputStream(File fPath); 创建字节输入流对象,通过参数关联数据源文件路径.
-
public FileInputStream(String path); 创建字节输入流对象,通过参数关联数据源文件路径.
-
注意:
- 如果关联的文件路径不存在,就会报文件找不到异常
public class Test { public static void main(String[] args) throws Exception{ //- public FileInputStream(File fPath); 创建字节输入流对象,通过参数关联数据源文件路径. //- public FileInputStream(String path); 创建字节输入流对象,通过参数关联数据源文件路径. FileInputStream fis1 = new FileInputStream(new File("day10\\fff\\a.txt"));// 文件存在 FileInputStream fis2 = new FileInputStream("day10\\fff\\a.txt");// 文件存在 //FileInputStream fis3 = new FileInputStream("day10\\fff\\b.txt");// 文件存在,报文件找不到异常 } }
-
-
读取数据
-
读一个字节:
public int read()
: 读一个字节,读到文件的末尾返回-1。public class Test1_读一个字节 { public static void main(String[] args) throws Exception { // 创建字节输入流对象,关联数据源文件路径 FileInputStream fis = new FileInputStream("day10\\fff\\a.txt"); // 读数据 int b1 = fis.read(); System.out.println("b1:"+b1);// 97 int b2 = fis.read(); System.out.println("b2:"+b2);// 98 int b3 = fis.read(); System.out.println("b3:"+b3);// 99 int b4 = fis.read(); System.out.println("b4:"+b4);// 100 int b5 = fis.read(); System.out.println("b5:"+b5);// 101 int b6 = fis.read(); System.out.println("b6:"+b6);// -1 --->说明读取到文件的末尾返回的是-1 // 关闭流,释放资源 fis.close(); } } 文件中的数据是: abcde
-
发现可以使用循环改进读取数据的代码
public class Test2_读一个字节 { public static void main(String[] args) throws Exception { // 创建字节输入流对象,关联数据源文件路径 FileInputStream fis = new FileInputStream("day10\\fff\\a.txt"); // 定义一个int变量,用来存储读取到的字节数据 int b; // 循环读数据: fis读取一个字节数据复制给b,然后拿b和-1进行比较 while ((b = fis.read()) != -1){ System.out.println("读到的数据是:"+ (char)b); } // 关闭流,释放资源 fis.close(); } }
-
-
读一个字节数组:
public int read(byte[] b)
: 读一个字节数组,读到的字节数据存储在byte数组中,返回读取到的字节个数,如果读取到文件的末尾,就返回-1public class Test3_读一个字节数组 { public static void main(String[] args) throws Exception { // public int read(byte[] b): 读一个字节数组 // 创建字节输入流对象,关联数据源文件路径 FileInputStream fis = new FileInputStream("day10\\fff\\a.txt"); // 定义一个byte数组,用来存储读取到的字节数据 byte[] bys = new byte[2]; // 读数据 int len1 = fis.read(bys);// 返回的是读取到的字节个数 System.out.println("len1:" + len1);// len1:2 System.out.println("bys:" + Arrays.toString(bys));// bys:[97, 98] int len2 = fis.read(bys);// 返回的是读取到的字节个数 System.out.println("len2:" + len2);// len2:2 System.out.println("bys:" + Arrays.toString(bys));// bys:[99, 100] int len3 = fis.read(bys);// 返回的是读取到的字节个数 System.out.println("len3:" + len3);// len3:1 System.out.println("bys:" + Arrays.toString(bys));// bys:[101, 100] int len4 = fis.read(bys);// 返回的是读取到的字节个数 System.out.println("len4:" + len4);// len4:-1 System.out.println("bys:" + Arrays.toString(bys));// bys:[101, 100] // 关闭流,释放资源 fis.close(); } }
-
循环改进:
public class Test4_读一个字节数组 { public static void main(String[] args) throws Exception { // public int read(byte[] b): 读一个字节数组 // 创建字节输入流对象,关联数据源文件路径 FileInputStream fis = new FileInputStream("day10\\fff\\a.txt"); // 定义一个byte数组,用来存储读取到的字节数据 byte[] bys = new byte[2]; // 读数据 // 定义一个int变量,用来存储读取到的字节数据 int len; // 循环读取数据 while ( (len = fis.read(bys)) != -1){ // 读到多少个字节,就把多少个字节转换为字符串 System.out.println("bys:"+ new String(bys,0,len)); } // 关闭流,释放资源 fis.close(); // byte[] byes = {97,98,99,100}; // String str1 = new String(byes,0,2);// 把97,98转换为字符串 } }
-
-
4.5 拷贝图片练习
需求
- 使用字节流拷贝一张图片
分析
一次读写一个字节拷贝文件:
1.创建字节输入流对象,关联数据源文件路径
2.创建字节输出流对象,关联目的地文件路径
3.定义一个int变量,用来存储读取到的字节数据
4.循环读取字节数据
5.在循环中,写出字节数据
6.关闭流,释放资源
一次读写一个字节数组拷贝文件:
1.创建字节输入流对象,关联数据源文件路径
2.创建字节输出流对象,关联目的地文件路径
3.定义一个byte数组,用来存储读取到的字节数据
3.定义一个int变量,用来存储读取到的字节个数
4.循环读取字节数据
5.在循环中,写出字节数据
6.关闭流,释放资源
实现
复制图片文件,代码使用演示:
public class Test1_一次读写一个字节拷贝文件 {
public static void main(String[] args) throws Exception {
// 1.创建字节输入流对象,关联数据源文件路径
FileInputStream fis = new FileInputStream("day10\\aaa\\hb.jpg");
// 2.创建字节输出流对象,关联目的地文件路径
FileOutputStream fos = new FileOutputStream("day10\\fff\\hbCopy1.jpg");
// 3.定义一个int变量,用来存储读取到的字节数据
int b;
// 4.循环读取字节数据
while ((b = fis.read()) != -1) {
// 5.在循环中,写出字节数据
fos.write(b);
}
// 6.关闭流,释放资源
fos.close();
fis.close();
}
}
public class Test2_一次读写一个字节数组拷贝文件 {
public static void main(String[] args) throws Exception {
// 1.创建字节输入流对象,关联数据源文件路径
FileInputStream fis = new FileInputStream("day10\\aaa\\hb.jpg");
// 2.创建字节输出流对象,关联目的地文件路径
FileOutputStream fos = new FileOutputStream("day10\\fff\\hbCopy2.jpg");
// 3.定义一个byte数组,用来存储读取到的字节数据
byte[] bys = new byte[8192];// 8192*4+100
// 3.定义一个int变量,用来存储读取到的字节个数
int len;
// 4.循环读取字节数据
while ((len = fis.read(bys)) != -1) {
// 5.在循环中,写出字节数据
fos.write(bys,0,len);
}
// 6.关闭流,释放资源
fos.close();
fis.close();
}
}
第五章 字符流
5.1 字节流读文本文件的问题
当使用字节流读取文本文件时,可能会有一个小问题。就是遇到中文字符时,可能不会显示完整的字符,那是因为一个中文字符可能占用多个字节存储。所以Java提供一些字符流类,以字符为单位读写数据,专门用于处理文本文件。
public class Test {
public static void main(String[] args) throws Exception {
// 需求: 使用字节流读取day10\ggg\a.txt文件中的数据,打印到控制台
// 1.创建字节输入流对象,关联数据源文件路径
FileInputStream fis = new FileInputStream("day10\\ggg\\a.txt");
// 2.定义一个int变量,用来存储读取到的字节数据
int b;
// 3.循环读取
while ((b = fis.read()) != -1) {
System.out.println("b:" + (char)b);// 乱码
}
// 4.关闭流,释放资源
fis.close();
}
}
5.2 字符输入流【Reader】
字符输入流Reader类的概述
java.io.Reader
抽象类是表示用于读取字符流的所有类的超类,可以读取字符信息到内存中。它定义了字符输入流的基本共性功能方法。
字符输入流Reader类的常用方法
public void close()
:关闭此流并释放与此流相关联的任何系统资源。public int read()
: 从输入流读取一个字符,读取文件的末尾返回-1。public int read(char[] cbuf)
: 从输入流中读取一些字符,并将它们存储到字符数组 cbuf中,返回读取到的字符个数,读取到文件的末尾返回-1 。
5.3 FileReader类
-
概述: java.io.FileReader类继承Reader类,也表示字符输入流,可以用读字符数据到内存中
-
构造方法:
public FileReader(File fPath);创建字符输入流对象,通过参数关联数据源文件路径
public FileReader(String Path);创建字符输入流对象,通过参数关联数据源文件路径
- 注意:
- 如果传入的文件路径不存在,就报文件找不到异常FileNotFountException
-
读数据的方法
-
读一个字符:
public int read()
: 从输入流读取一个字符,读取文件的末尾返回-1。public class Test1_读一个字符 { public static void main(String[] args) throws Exception { // public int read(): 从输入流读取一个字符,读取文件的末尾返回-1。 // 创建字符输入流对象,关联数据源文件路径 FileReader fr = new FileReader("day10\\ggg\\a.txt"); // 读数据 // 定义一个int变量,用来存储读取到的字符数据 int c; // 循环读取 while ((c = fr.read()) != -1) { System.out.println("c:" + (char) c); } // 关闭流,释放资源 fr.close(); } }
-
读一个字符数组:
public int read(char[] cbuf)
: 从输入流中读取一些字符,并将它们存储到字符数组 cbuf中,返回读取到的字符个数,读取到文件的末尾返回-1 。public class Test2_读一个字符数组 { public static void main(String[] args) throws Exception{ // public int read(char[] cbuf): 从输入流中读取一些字符,并将它们存储到字符数组 cbuf中,返回读取到的字符个数,读取到文件的末尾返回-1 。 // 创建字符输入流对象,关联数据源文件路径 FileReader fr = new FileReader("day10\\ggg\\a.txt"); // 读数据 // 定义一个char数组,用来存储读取到的字符数据 char[] chs = new char[4]; // 定义一个int变量,用来存储读取到的字符个数 int len; // 循环读取 while ((len = fr.read(chs)) != -1){ System.out.println("数据:"+new String(chs,0,len)); } // 关闭流,释放资源 fr.close(); } }
-
5.4 字符输出流【Writer】
字符输出流Writer类的概述
java.io.Writer
抽象类是表示用于写出字符流的所有类的超类,将指定的字符信息写出到目的地。它定义了字符输出流的基本共性功能方法。
字符输出流Writer类的常用方法
public abstract void close()
:关闭此输出流并释放与此流相关联的任何系统资源。public abstract void flush()
:刷新此输出流并强制任何缓冲的输出字符被写出。public void write(int c)
:写出一个字符。public void write(char[] cbuf)
:将 b.length字符从指定的字符数组写出此输出流。public abstract void write(char[] b, int off, int len)
:从指定的字符数组写出 len字符,从偏移量 off开始输出到此输出流。public void write(String str)
:写出一个字符串。public void write(String str,int off,int len)
:写出一个字符串的一部分。
5.5 FileWriter类
-
概述: java.io.FileWriter类继承Writer类,也表示一个字符输出流,可以用来写出字符数据到目的地文件中
-
构造方法:
-
public FileWriter(File fpath); 创建字符输出流对象,通过参数关联目的地文件路径
-
public FileWriter(String path); 创建字符输出流对象,通过参数关联目的地文件路径
-
public FileWriter(File fpath,boolean append); 创建字符输出流对象,通过参数关联目的地文件路径
-
public FileWriter(String path,boolean append); 创建字符输出流对象,通过参数关联目的地文件路径
-
注意:
-
以上4个构造方法, 如果路径表示的文件不存在,就会自动创建一个新的空文件
-
前面2个构造方法,如果路径表示的文件存在,就会清空文件中的数据
-
后面2个构造方法,如果第二个参数为true,就不清空文件中的数据,如果为false,就清空文件中的数据
public class Test { public static void main(String[] args)throws Exception { //FileWriter fw1 = new FileWriter("day10\\hhh\\a.txt");// 清空 //FileWriter fw2 = new FileWriter("day10\\hhh\\a.txt",true);// 不清空 FileWriter fw3 = new FileWriter("day10\\hhh\\b.txt");// 创建新的空文件 } }
-
-
-
写出数据:
-
写一个字符:
public void write(int c)
:写出一个字符。public class Test1_写一个字符 { public static void main(String[] args) throws Exception { // 创建字符输出流对象,关联目的地文件路径 FileWriter fw = new FileWriter("day10\\hhh\\c.txt"); // 写出数据 fw.write(97); fw.write('b'); // 关闭流,释放资源 fw.close(); } } 文件: ab
-
写字符数组:
public void write(char[] cbuf)
:将 b.length字符从指定的字符数组写出此输出流。public class Test2_写一个字符数组 { public static void main(String[] args) throws Exception { // 创建字符输出流对象,关联目的地文件路径 FileWriter fw = new FileWriter("day10\\hhh\\d.txt"); // 写出数据 char[] chs = {'a','b','c','d','e','f'}; fw.write(chs); // 关闭流,释放资源 fw.close(); } } // 文件: abcdef
-
写指定长度字符数组:
public abstract void write(char[] b, int off, int len)
:从指定的字符数组写出 len字符,从偏移量 off开始输出到此输出流。public class Test3_写指定长度的字符数组 { public static void main(String[] args) throws Exception { // 创建字符输出流对象,关联目的地文件路径 FileWriter fw = new FileWriter("day10\\hhh\\e.txt"); // 写出数据 char[] chs = {'a','b','c','d','e','f'}; fw.write(chs,0,3); // 关闭流,释放资源 fw.close(); } } // 文件; abc
-
写字符串:
public void write(String str)
:写出一个字符串。public class Test4_写一个字符串 { public static void main(String[] args) throws Exception { // 创建字符输出流对象,关联目的地文件路径 FileWriter fw = new FileWriter("day10\\hhh\\f.txt"); // 写出数据 fw.write("看这风景美如画\r\n"); fw.write("本想吟诗赠天下\r\n"); fw.write("奈何本人没文化\r\n"); fw.write("一句我操浪好大\r\n"); // 关闭流,释放资源 fw.close(); } }
-
写指定长度字符串:
public void write(String str,int off,int len)
:写出一个字符串的一部分。public class Test5_写指定长度的字符串 { public static void main(String[] args) throws Exception { // 创建字符输出流对象,关联目的地文件路径 FileWriter fw = new FileWriter("day10\\hhh\\g.txt"); // 写出数据 fw.write("看这风景美如画",2,2); // 关闭流,释放资源 fw.close(); } }
-
-
关闭和刷新
-
public abstract void close()
:关闭此输出流并释放与此流相关联的任何系统资源。 -
public abstract void flush()
:刷新此输出流并强制任何缓冲的输出字符被写出。 -
区别:
-
关闭: 关闭流之前会刷新,关闭之后流就不能再使用了
-
刷新: 刷新之后流还可以继续使用
public class Test { public static void main(String[] args) throws Exception{ // 创建字符输出流对象,关联目的地文件路径 FileWriter fw = new FileWriter("day10\\hhh\\h.txt"); // 写出数据 fw.write('刷'); // 刷新 fw.flush(); // 写出数据 fw.write('新'); // 刷新 fw.flush(); // 写出数据 fw.write("关"); // 关闭 fw.close(); // 写出数据 // fw.write("闭");// 报IOException异常 // 关闭 // fw.close(); } }
-
-
总结
必须练习:
1.一次读写一个字节拷贝文件
2.一次读写一个字节数组拷贝文件
3.一次读写一个字符拷贝文本文件
4.一次读写一个字符数组拷贝文本文件
以上4个案例必须写5遍----> 20遍---->脱离笔记,能够自己独立写出来
5.追加续写
6.搜索指定类型的文件--->递归,File类
- 能够说出File对象的创建方式
public File(String pathname);
public File(String parent,String child);
public File(File parent,String child);
- 能够使用File类常用方法
public String getAbsolutePath() :返回此File的绝对路径名字符串。
public String getPath() :获取构造路径(构造方法中传入的路径)
public String getName() :返回由此File表示的文件或目录的名称。
public long length() :返回由此File表示的文件的字节大小。 不能获取目录的字节大小
public boolean exists() :此File表示的文件或目录是否实际存在。
public boolean isDirectory() :此File表示的是否为目录。
public boolean isFile() :此File表示的是否为文件。
public boolean createNewFile() :当且仅当具有该名称的文件尚不存在时,创建一个新的空文件。
public boolean delete() :删除由此File表示的文件或目录。注意,只能删除空文件夹
public boolean mkdir() :创建由此File表示的目录。
public boolean mkdirs() :创建由此File表示的目录,包括任何必需但不存在的父目录。
public String[] list() :获取File目录中的所有子文件或子目录的名称。
public File[] listFiles() :获取File目录中的所有子文件或子目录的路径。
- 能够辨别相对路径和绝对路径
相对路径: 相对于项目路径而言的路径
绝对路径: 以盘符开始的完整路径
- 能够遍历文件夹
listFiles()
- 能够解释递归的含义
方法自己调用自己
规律--出口
- 能够使用递归的方式计算5的阶乘
public static int jieCheng(int n){
if(n == 1){return 1;}
return n * jieCheng(n-1);
}
- 能够说出使用递归会内存溢出隐患的原因
递归没有出口,或者递归的出口太晚了,造成方法没有弹栈,栈就满了
- 能够说出IO流的分类和功能
字节流:以字节为基本单位进行读写数据
字符流:以字符为基本单位进行读写数据
- 能够使用字节输出流写出数据到文件
FileOutputStream:
write(int b);----常用 写一个字节
write(byte[] bys,int off,int len);----常用 写一个字节数组
- 能够使用字节输入流读取数据到程序
FileInputStream:
int read(); 读一个字节
int read(byte[] bys);读一个字节数组
- 能够理解读取数据read(byte[] bys)方法的原理
读取数组长度个字节数据存储到字节数组中,返回读取到的字节个数,如果不够数组长度个字节数据,那么有多少个就读多少个
- 能够使用字节流完成文件的复制
查看笔记思路
一次读写一个字节拷贝文件
一次读写一个字节数组拷贝文件
- 能够使用FileWriter写数据的5个方法
write(int len);---- 常用 写一个字符
write(char[] chs,int off,int len)---- 常用 写一个字符数组
write(char[] chs);
write(String str);
write(String str,int off,int len)
- 能够使用FileReader读数据一次一个字符
int read() 读一个字符
- 能够使用FileReader读数据一次一个字符数组
int read(char[] chs) 读一个字符数组
- 能够说出FileWriter中关闭和刷新方法的区别
关闭: 关闭流,刷新缓冲区,流不能再使用
刷新: 刷新缓冲区,流可以继续使用
- 能够使用FileWriter写数据实现换行和追加写
public FileWriter(String path,boolean append)
public FileWriter(File path,boolean append)
回车换行--->"\r\n"
统计文件夹的字节大小
/**
* 统计文件夹的字节大小
* @param path
* @return
*/
public static long getSize(File path) {
// 获取所有的子文件\子文件夹
File[] files = path.listFiles();
// 定义一个变量,用来记录文件夹的字节大小
long len = 0;
if (files != null) {
// 循环遍历
for (File file : files) {
if (file.isFile()) {
// 如果是文件,就计算字节大小,并累加
len += file.length();
}
if (file.isDirectory()) {
// 如果是文件夹,就递归计算文件夹的字节大小,并和之前的文件夹字节大小累加
len += getSize(file);
}
}
}
// 返回文件夹的字节大小
return len;
}
删除非空文件夹
/**
* 删除非空文件夹
*
* @param f
*/
public static void delete(File f) {
// 获取所有的子文件\子文件夹
File[] arr = f.listFiles();
if (arr.length != -1) {
// 循环遍历
for (File file : arr) {
if (file.isFile()) {
// 如果是文件,就删除
file.delete();
}
if (file.isDirectory()) {
// 如果是文件夹,就递归删除
delete(file);
}
}
}
// 最后结束方法之前,删除当前文件夹
f.delete();
}