目录
文件过滤器
概念:将不要文件过滤掉,剩下我们需要
类型:
1. FilenameFilter:文件过滤器 如果需要使用多次可以创建一个类去实现FilenameFilter接口
File[] files = file.listFiles(new FilenameFilter() { // 带有文件过滤器 @Override public boolean accept(File dir, String name) { return new File(dir, name).isFile(); // 用这个方法需要新建对象 } });
2. FileFilter:文件过滤器 如果需要使用多次可以创建一个类去实现FileFilter接口
File[] files = file.listFiles(new FileFilter() { // file.list不适用 @Override public boolean accept(File pathname) { return pathname.isFile() && pathname.getName().endsWith(".txt"); } });
复制文件
File file = new File("e:/pp"); // 只需要ppt文件 File[] files = file.listFiles(new FileFilter() { @Override public boolean accept(File pathname) { return pathname.isFile() && pathname.getName().endsWith(".ppt"); } }); // 遍历创建文件 for (File f : files) { File ff = new File("e:/aa", f.getName()); // 创建文件 // 放入磁盘中 ff.createNewFile(); }
方法的递归调用
概念:简单理解就是方法的一种特殊调用,自己方法调用自己
递归:
第一个动作是:递(调自己),一直递会造成栈溢出
第二个动作是:归(不再调用自己,递的终点,然后再逐层返回结果)
缺点:递归的性能很差,一般不用递归
优点:解决无限级问题
// 设计一个方法来计算1-n的和 public static int getSum(int n) { int sum = 0; for (int i = 1; i <= n; i++) { sum += i; } if(n == 1) { // 当n==1的时候,停止调用自己,开始返回值,依次输出之前暂停的方法 return 1; // 归, 没有这个会栈溢出 } // getSum(n - 1) 每次执行都会调用这个方法,在栈中第一次执行的会在最下面,然后调用方法的时候,就会暂时停在那里,等有了出口的时候,就会再依次从栈的顶端返回来输出。 return n + getSum(n - 1); // 调用的方法是自己,这就是递归调用 }
// 递归应用的案例
// 删除 e:/pp文件夹
public static void remove(File file) {
// 获取file对象(文件夹)里面所有File对象
File[] files = file.listFiles();
for (File f : files) {
// f如果是文件夹
if(f.isDirectory())
// 递归调用
remove(f);
// 删除
f.delete();
}
// 删除最外的文件夹0
file.delete();
}
public static void main(String[] args) {
remove(new File("e:/pp"));
}
IO流
流:具有流动性,操作数据
I : InputStream:输入流,读取文件内容
-
怎么读取文件的?
1)、使用输入流和文件建立连接
2)、将文件里面的内容加载到流里面
3)、从流对象中取出内容 读文件数据的流动方向:从硬盘到内存
O : OutputStream:输出流,向文件写入内容
-
怎样向文件写入内容?
1)、使用输出流和文件建立连接
2)、将内容写入输出流对象里面
3)、将流里面内容写到文件里面 写文件数据的流动方向:从内存到硬盘
IO:输入输出流,对文件进行读写操作的
IO的分类:
按操作单位来分:
字节流:按照字节为单位来操作文件,一次读一个字节或者写一个字节
字符流:按照字符为单位来操作文件,一次读一个字符或者写一个字符
注意:一个中文占2个或3个字节,字节流读取中文不友好,字节流一般不用来操作文本文件
一个中文,字母,数字都是一个字符,字符流读取中文没有问题,字符流一般用来读取文本文件
按数据流动的方向来分:
输入流:用来读文件 输出流:用来向文件写入的
字节流(重点)
InputStream:字节输入流的父类
子类FileInputStream:文件字节输入流(读取的数据源是一个文件)
构造方法:
1)、FileInputStream(String name)
2)、FileInputStream(File file)
FileInputStream fis = new FileInputStream(new File("e:/1.txt")); // 字节输入流和文件的连接 方法1. read() // 从流里面取出一个字节 read():读一个字节 int data = fis.read();// 从流里面读一个字节 System.out.println(data); // 返回-1说明文件已经读完了 // 循环读取 int data; while((data = fis.read()) != -1) { // read():一次读一个字节性能比较低 System.out.print((char)data); } 方法2.read(byte[] b):连接一次可以读多个字节,将数据读到一个字节数组中,返回的数读到字节个数 性能远远高于read(); // 创建文件字节输入流 FileInputStream fis = new FileInputStream("e:/1.txt"); // 创建一个字节数组 byte[] bytes = new byte[3]; int count; // 存储读取的字节个数 while((count = fis.read(bytes)) != -1) { // 放到一个string对象里 String s = new String(bytes,0,count); System.out.print(s); } // count:表示读取的字节个数,从流里面读取的数据,放到bytes数组里面 // int count = fis.read(bytes); // 连接一次文件读取三个字节 // System.out.println(Arrays.toString(bytes)); // System.out.println("第一次读取的字节数:" + count); 打印3 返回字节个数为-1,表示文件读完了 /* * 字节流读中文 */ FileInputStream fis = new FileInputStream("e:/1.txt"); byte[] bytes = new byte[3]; // 一个汉字占三个字节,必须要写3,否则会把汉字给拆开 int count; // 存储读取的字节个数 while((count = fis.read(bytes)) != -1) { // 放到一个string对象里 String s = new String(bytes,0,count); System.out.println(s); } OutputStream:所有字节输出流的父类
子类FileOutputStream:文件字节输出流,向文件写入内容,字节流是自动刷新
构造方法:
1)、FileOutputStream(String name):覆盖流 创建文件输出流以指定的名称写入文件
// 创建FileOutputStream(文件字节输出流) FileOutputStream fos = new FileOutputStream("e:/2.txt");// 写入的文件不存在,会自动创建2)、FileOutputStream(String name, boolean append): 追加流
3)、FileOutputStream(File file):创建文件输出流以写入由指定的 File对象表示的文件。
4)、FileOutputStream(File file, boolean append):创建文件输出流以写入由指定的
File
对象表示的文件。// 方法1:write(int b):一次写入一个字节 FileOutputStream fos = new FileOutputStream("e:/2.txt"); // 覆盖流会覆盖 fos.write(66); // 将A写入到fos流里面 fos.write(66); // 将A写入到fos流里面 fos.flush(); // 刷新流,将流里面的数据写入文件里面 // 方法2:write(byte[] b):写入多个字节 String str = "范德萨范德萨发生的范德萨发生发生的发的所发生的"; fos.write(str.getBytes()); // str.getBytes():将字符串转换字节数组 // 方法3:write(byte[] b, int off, int len):将数组中指定数据写入 fos.write("abcdefghijk".getBytes(),2,5); // getBytes 将结果存储到一个新的 byte 数组中 /** * 文件字节输出流的案例 */ public class IODemoOut2 { public static void main(String[] args)throws IOException { // 产生10个100以内不重复的数字,将这数字写入一个文件中 HashSet<Integer> hs = new HashSet<>(); while(hs.size() < 10) { hs.add((int)(Math.random() * 100 + 1)); } // 创建文件字节输出流 FileOutputStream fos = new FileOutputStream("e:/number.txt"); // 遍历集合 Iterator<Integer> it = hs.iterator(); while (it.hasNext()) { Integer next = it.next(); fos.write(String.valueOf(next + " ").getBytes()); } } } /** * 讲解关闭流 * 流对象用完要关闭 * 注意关闭流的顺序:先用的后关 */ public class CloseDemo { public static void main(String[] args) { FileInputStream fis = null; FileOutputStream fos = null; try { fis = new FileInputStream("e:/1.txt"); int data = fis.read(); fos = new FileOutputStream("e:/3.txt"); fos.write(data); // 关闭流:close(); // fis.close(); // 代码有可能执行不到 } catch (FileNotFoundException e) { throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } finally { // 释放锁,关闭流 if(fos != null) { try { fos.close(); } catch (IOException e) { throw new RuntimeException(e); }finally { // 注意这里的嵌套 if(fis != null) { try { fis.close(); } catch (IOException e) { throw new RuntimeException(e); } } } } } } } /** * 自动关流 * 注意:要关闭的流必须支持自动关流 * * 自动关流的语法 * try(创建流的代码) { * 流要执行代码 * } */ public class CloseDemo2 { public static void main(String[] args) { try( FileInputStream fis = new FileInputStream("e:/1.txt"); FileOutputStream fos = new FileOutputStream("e:/3.txt"); ) { fis.read(); fos.write("abc".getBytes()); } catch (FileNotFoundException e) { throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } } } /** * 复制图片案例 * 输入输出流都要用 */ public class CopyImage { public static void copy(String src,String dest) { try { // 创建文件字节输入流 FileInputStream fis = new FileInputStream(src); byte[] bytes = new byte[1024]; int count; // 保存读取字节个数 // 创建文件字节输出流 FileOutputStream fos = new FileOutputStream(dest); while ((count = fis.read(bytes)) != -1) { // 将数据写入fos流 fos.write(bytes,0,count); } } catch (FileNotFoundException e) { throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } } public static void main(String[] args) { copy("e:/2.webp","e:/3.webp"); } } // 模仿写过滤器 public class FileDemo { public static void main(String[] args) { File file = new File("F:\\1117JAVA全栈班\\2023-12-26-Java加强-IO流-文件读写\\video"); File[] fileList = getFileList(file, new FileFilter() { @Override public boolean accept(File f) { return f.getName().endsWith(".mp4"); } }); for (File f : fileList) { System.out.println(f); } } //条件过滤, 条件是调用的时候传进来的 public static File[] getFileList(File file, FileFilter fileFilter){ File[] files = file.listFiles(); ArrayList<File> list = new ArrayList<>(); for (File f : files) { if (fileFilter.accept(f)) { list.add(f); } } //转为File数组 return list.toArray(new File[0]); } }
字符流
概念:以字符为单位来操作文件的流
1.Reader:所有输入字符流的父类,输入字符流
FiLeReader:文件字符输入流,用来按字符为单位读取文件
2.Writer:所有输出字符流的父类,输出字符流
FileWriter:文件字符输出流,不会自动刷新
// 创建FileReader对象:文件字符输入流 // 读取文件 // 0.一个一个读 int data = fr.read();// 一次读取一个字符,返回的是字符ASCII码 返回-1表示文件读完了 // 1.循环读 // 返回-1表示文件读完了 int data; while((data = fr.read()) != -1) { System.out.print((char)data); } // 2.一次读3个字符 char[] chars = new char[3]; int count; // 读取字符个数 while((count = fr.read(chars)) != -1) { // 创建字符创 String s = new String(chars, 0, count); System.out.print(s); } // 3.截取一部分读 while ((count = fr.read(chars,1,2)) != -1) { String s = new String(chars, 1, count); System.out.println(s); }
/** * 字符输入流的案例 */ public class IODemo2 { public static void main(String[] args) throws IOException { try( // 创建文件字符输入流 FileReader fr = new FileReader("C:\\Users\\ITsource\\Desktop\\新建文本文档.txt"); ) { char[] chars = new char[1024]; int count; while ((count = fr.read(chars)) != -1) { String s = new String(chars, 0, count); System.out.println(s); } } } } /** * 字符输出流的案例 * FileWriter:文件字符输出流,不会自动刷新 * flush:刷新 * */ public class IODemo3 { public static void main(String[] args) throws IOException { // 创建文件字符输出流对象 FileWriter fw = new FileWriter("e:/4.txt");// 覆盖流 // fw.write(34567); // 向流写入 // fw.write(23456); // fw.write(65222); // fw.write(21345); // fw.flush(); // 刷新流 // fw.write("dsgfdsfgd无关风月325432sds".toCharArray(),2,4); fw.write("我题序等你回~",2,5); fw.flush(); // 刷新流 } }
转换流
将字节流转换字符流的一种流
InputStreamReader: 字节输入转换流,将输入字节流转换为输入字符流
构造方法:
InputStreamReader(InputStream in): 将传入的字节流转换字符流
InputStreamReader(InputStream in,String charsetName): 设置字符流的编码集
OutputStreamWriter:字节输出转换流,将输出字节流转换为输入字符流
构造方法:
OutputStreamWriter(OutputStream out): 创建一个使用默认字符编码的OutputStreamWriter。
OutputStreamWriter(OutputStream out, String charsetName): 创建一个使用命名字符集的OutputStreamWriter。
注意:转换流只能操作字节流,不能直接操作文件
FileInputStream fis = new FileInputStream("1.txt"); // 创建文件字节输入流 // 1.将字节流转换字符流 InputStreamReader isr = new InputStreamReader(fis); InputStreamReader isr = new InputStreamReader(fis); int data; while((data = isr.read()) != -1) { System.out.print((char)data); } //2.将字节流转换字符流,并且设置字符流的编码集是gbk new InputStreamReader(fis,"gbk");
缓冲流
概念:自带缓冲区的流,默认的缓冲区是8K,操作文件就可以减少连接次数,从而提高的性能
作用:
字节流和字符流操作的流程
1)、和文件产生连接
2)、开始操作 操作一次就要连接一次(连接的次数多操作性能就比较低) 为提高操作性能,用数组,减少连接次数
缓冲字节流
缓冲字节输入流: BufferedIntputStream 操作的对象是输入字节流
缓冲字节输出流: BufferedoutputStream
缓冲字符流
缓冲字符输入流: BufferedReader(Reader in) :创建使用默认大小的输入缓冲区的缓冲字符输入流。
方法:readLine() 读行
缓冲字符输出流: BufferedWriter(Writer out) :创建使用默认大小的输出缓冲区的缓冲字符输出流。
方法: newLine() 换行
BufferedReader br = new BufferedReader(new FileReader("e:/1.txt")); // 创建缓冲字符输入流 BufferedWriter bw = new BufferedWriter(new FileWriter("e:/333.txt")); // 创建缓冲字符输出流 char[] chars = new char[1024]; // 一次读1kb的数据 int count; while ((count = br.read(chars)) != -1) { String s = new String(chars, 0,count); System.out.print(s); // readLine() 读行 输入流的方法 // newLine(); 换行 输出流的方法 String s = ""; // 需要用String来接收,读的整行 while ((s = br.readLine()) != null) { // readLine()返回null说明文件读完了 System.out.println(s); bw.write(s); bw.newLine(); // 换行 bw.flush(); // 刷新流 }
IO流小节:( Java要掌握的流(16个))
文件专属:
字节输入输出流 :自动刷新
Inputscream
FileInputStream(掌握)
Outputscream
FileOutputStream(掌握)
字符输入输出流: 需要手动刷新
Reader
FileReader
Writer
FileWriter
转换流:(将字节流转换成字符流)
InputStreamReader
OutputStreamWriter
缓冲流:
BufferedReader
BufferedWriter
BufferedInputStream
BufferedOutputStream
Lambda表达式
作用:简化使用匿名内部类创建函数式接口对象的代码
注意: 函数式接口只有一个抽象方法的时候可以使用
语法:()-> { }
从抽象方法的()开始简化,到这个方法的方法体,其他都不要了 ()和方法体之间需要->连接
// 正常使用匿名内部类 IDemo iDemo = new IDemo() { @Override public int getSum(int n) { return 10 + n; } }; // 使用lambda表达式 IDemo iDemo2 = (int n) ->{ // (int n):就是重写getSum()方法,方法体就是->后面 return 10 + n; }; // 创建IDemo2函数式接口的对象 IDemo2 d2 = (int a,int b) -> {return a > b ? a : b;}; // 创建IDemo3的函数式接口的对象 IDemo3 d3 = () -> { System.out.println("hello"); }; // 遍历集合 List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6); // list.forEach((Integer pp)->{ System.out.println(pp); }); /* * 简化lambda表达式 * 方法名已经简化了,可以省略参数的数据类型 * 如果参数的个数只有一个,可以省略() * ->后面的称为lambda体,如果lambda体只有一句语句,{}可以省略,如果{}里面有return,在省略{}时候一起省略 */ IDemo id = a -> 10 + a; IDemo2 id2 = (a,b) -> a > b ? a : b;