File类和IO流
1|0File类和IO流
1|1File类
概述
public class FileDemo { public static void main(String[] args) { //创建一个路径操作对象 路径包括父路径和子路径 File f = new File("G:\\FileTest\\java.txt"); System.out.println(f); //创建一个路径操作对象 父路径,子路径 File f1 = new File("G:\\FileTest","java.txt"); System.out.println(f1); //创建一个父路径操作对象 File f2 = new File("G:\\FileTest"); //从父路径和子路径创建的路径操作对象 File f3 = new File(f2,"java.txt"); System.out.println(f3); } }
运行结果:
//File类重写了toString() G:\FileTest\java.txt G:\FileTest\java.txt G:\FileTest\java.txt
public class FileDemo1 { public static void main(String[] args) throws IOException { /*在G:\FileTest目录下,创建一个Hello.txt文件 如果文件不存在就创建文件,返回true 如果文件存在返回false*/ File f1 = new File("G:\\FileTest\\Hello.txt"); System.out.println(f1.createNewFile()); /*在G:\FileTest目录下,创建一个Cat文件夹 如果文件不存在就创建文件,返回true 如果文件存在返回false*/ File f2 = new File("G:\\FileTest\\Cat"); System.out.println(f2.mkdir()); /*在G:\FileTest目录下,创建一个多级目录Eat\egg文件夹 如果文件不存在就创建文件,返回true 如果文件存在返回false*/ File f3 = new File("G:\\FileTest\\Eat\\egg"); System.out.println(f3.mkdirs()); } }
运行结果
true true true
注意
- 如果同一目录下存在同名的文件夹,createNewFile()创建文件时会失败;要将同名的文件夹删掉才会创建文件成功。
File类判断和获取功能
运行代码之前,先在此位置创建一个java.txt文件
public class FileDemo2 { public static void main(String[] args) { //创建File对象 File f = new File("idea_test\\java.txt"); //抽象路径名表示的File是否为目录 System.out.println("是否为目录:"+f.isDirectory()); //抽象路径名表示的File是否为文件 System.out.println("是否为文件:"+f.isFile()); //抽象路径名表示的File是否存在 System.out.println("是否存在:"+f.exists()); //返回此抽象路径名的绝对路径(字符串) System.out.println("绝对路径:"+f.getAbsolutePath()); //将此抽象路径名转化为字符串 System.out.println("抽象路径:"+f.getPath()); //返回此抽象路径名表示的文件名或者目录名 System.out.println("文件名或者目录名:"+f.getName()); System.out.println("-------FileTest目录-------------"); File f1 = new File("G:\\FileTest"); //返回此抽象路径名表示的目录中的文件名和目录的名称字符串数组 String[] list = f1.list(); //遍历字符串数组 for (String s : list) { System.out.println(s); } System.out.println("---------FileTest目录中的文件-----------"); //返回此抽象路径名表示的目录中的文件名和目录的File对象数组 File[] files = f1.listFiles(); for (File file : files) { //System.out.println(file); //如果对象是一个文件,输出文件名 if (file.isFile()){ System.out.println(file.getName()); } } } }
运行结果:
是否为目录:false 是否为文件:true 是否存在:true 绝对路径:G:\Work_Basic\JavaSE_Code\idea_test\java.txt 抽象路径:idea_test\java.txt 文件名或者目录名:java.txt -------FileTest目录------------- Cat Eat Hello.txt java.txt ---------FileTest目录中的文件----------- Hello.txt java.txt
public class FileDemo3 { public static void main(String[] args) throws IOException { //在当前模块目录下创建一个hello.txt文件 File f = new File("idea_test\\hello.txt"); //System.out.println(f.createNewFile()); //删除当前模块目录下的hello.txt文件 System.out.println(f.delete()); } }
运行结果:hello.txt文件已经删除
true
//在当前模块目录下创建一个"雀巢"文件夹 File f1 = new File("idea_test\\雀巢"); System.out.println(f1.mkdir());
//删除当前模块目录下的"雀巢"文件夹 System.out.println(f1.delete());
//在当前模块目录下创建一个"雀巢"文件夹,文件夹里有个java.txt文件 File f2 = new File("idea_test\\雀巢"); System.out.println(f2.mkdir()); File f3 = new File(f2, "java.txt"); System.out.println(f3.createNewFile());
运行结果:
true true
创建多级目录文件
- 在创建文件之前,应该先创建上一级的目录,否则会报错
//删除当前模块目录下的"雀巢"文件夹 System.out.println(f3.delete()); System.out.println(f2.delete());
运行结果:"雀巢"文件夹删掉了
true true
删除文件夹
- 如果要删除的文件夹下有文件,删除操作会不成功,返回false
- 要先删除该文件夹下的文件,之后才能删除该文件夹
1|2递归
方法中调用方法本身
思路:把一个复杂的问题,层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算。
public class Demo { public static void main(String[] args) { /*不死神兔:求第20个月兔子的对数 * 每个月兔子的对数:1,1,2,3,5,8……*/ //创建长度为20的数组 索引0-19 int[] arr = new int[20]; //第一个月:1对 arr[0] = 1; //第二个月:1对 arr[1] = 1; //从第三个月(索引2)开始:兔子的对数等于前两个月之和 for (int i = 2; i < arr.length; i++) { arr[i] = arr[i - 1] + arr[i - 2]; } //输出第20个月(索引19)兔子的对数 System.out.println(arr[19]); } }
运行结果:
6765
使用递归来解决上述问题
public class Demo { public static void main(String[] args) { /*不死神兔:求第20个月兔子的对数 * 每个月兔子的对数:1,1,2,3,5,8……*/ //第20个月,兔子的对数 System.out.println(f(20)); } /** * 递归:求第n个月兔子的对数 * * @param n 第n个月 * @return 兔子的对数 * StackOverflowError 当由于应用程序而发生堆栈溢出时引发 递归太深。递归需要停止 */ public static int f(int n) { if (n == 1 || n == 2) { return 1; } else { //从第3个月开始,每个月兔子的对数都是前两个月之和 return f(n - 1) + f(n - 2); } } }
运行结果:
6765
递归解决问题
- 递归出口:否则会出现内存溢出StackOverflowError
- 递归规则:与原问题相似的规模较小的问题
案例:递归求5的阶乘
public class Demo { public static void main(String[] args) { //调用方法,求5的阶乘 System.out.println(f(5)); } /** * 阶乘 * @param n * @return */ public static int f(int n) { if (n == 1) { return 1; } else { return n * f(n - 1); } } }
运行结果:
120
1|3IO字节流
IO流概述
- IO:输入/输出
- 流:数据传输
- IO流就是处理设备之间数据传输问题的(常见:文件复制,文件上传,文件下载)
输入:读数据;硬盘到内存条
输出:写数据;内存条到硬盘
IO流的分类
- 按照数据的流向
- 输入流:读数据
- 输出流:写数据
- 按照数据类型
- 字节流:字节输入流,字节输出流
- 字符流:字符输入流,字符输出流
使用场景
- 用记事本打开,能看懂的内容,使用字符流,否则使用字节流。
- 如果不知道该使用哪种类型的流,就使用字节流。
字节流写数据
字节流抽象基类
- public abstract class InputStream:字节输入流的所有类的超类
- public abstract class OutputStream:字节输出流的所有类的超类
- 子类名称特点:子类名称都是以父类名作为子类命的后缀
FileOutputStream:文件输入流,用于将数据写入File
- FileOutputStream(String name):将数据以指定的名称写入文件
使用字节输出流写数据的步骤
- 创建字节输出流对象
- 调用系统功能创建了文件
- 创建字节输出流
- 让字节数流对象指向文件)
- 调用字节输出流对象的写数据方法
- 释放资源:关闭此文件的输出流并释放与此流关联的任何系统资源
创建字节输出流对象的三种方式:
//创建字节输出流对象 第一种 FileOutputStream fo = new FileOutputStream("idea_test\\java.txt");
//创建字节输出流对象 第二种 File file = new File("idea_test\\java.txt"); FileOutputStream fo = new FileOutputStream(file);
//创建字节输出流对象 第三种 FileOutputStream fo = new FileOutputStream(new File("idea_test\\java.txt"));
案例:使用字节输出流写数据的步骤
public class IoDemo { public static void main(String[] args) throws IOException { /** * 创建字节输出流对象 * 1.调用系统功能创建了文件 * 2.创建了字节输出流对象 * 3.让字节输出流对象指向创建好的文件 */ FileOutputStream fo = new FileOutputStream("idea_test\\java.txt"); //void write(int b):将指定的字节写入此文件输出流 fo.write(97); //释放资源:关闭此文件的输出流并释放与此流关联的任何系统资源 fo.close(); } }
//写入abcde 第一种 fo.write(97); fo.write(98); fo.write(99); fo.write(100); fo.write(101);
//写入abcde 第二种 byte[] b = {97,98,99,100,101}; //或者,返回字符串中的字节数组 //byte[] b = "abcde".getBytes(); fo.write(b);
//写入abcde 第三种 byte[] b = {97,98,99,100,101}; //参数:字节数组 索引起始位置 索引结束位置 fo.write(b,0,b.length);
字节流写数据的两个小问题
- 字节流写数据如何实现换行?
- Windows: \r\n
- Linux: \n (win11用这个也可以)
- Mac: \r
- 字节流写数据如何实现追加写入?
- public FileOutputStream(File file, boolean append)
//追加写入 public class IoDemo { public static void main(String[] args) throws IOException { //如果第二个参数为true,将在文件末尾追加内容 //如果第二个参数不为true(不写或者false),将不是追加,而是从文件开头开始覆盖内容 FileOutputStream fo = new FileOutputStream("idea_test\\java.txt",true); //FileOutputStream fo = new FileOutputStream("idea_test\\java.txt",false); //写入十次”hello“ for (int i = 0; i < 10; i++) { // 写入字节流 // getBytes()返回字符串中的字节数组 fo.write("hello".getBytes()); fo.write("\n".getBytes()); } fo.close(); } }
字节流写数据加异常处理
public class IoDemo { public static void main(String[] args) { //初始化为null FileOutputStream fo = null; try { //可能出现异常的代码 fo = new FileOutputStream("idea_test\\java.txt"); fo.write("世界杯".getBytes()); } catch (IOException e) { //异常处理的代码 e.printStackTrace(); } finally {//被finally控制的语句,一定会执行,除非JVM退出 //null调方法会报空指针异常,所以fo不为null才能执行close()释放资源操作 if (fo != null) { try { //close()有编译时异常,用try...catch()处理一下 fo.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
字节流读数据(一次读一个字节)
FileInputStream:从文件系统中的文件获取输入字节
- FileInputStream(String name):通过打开与实际文件的连接来创建一个FileInputStream,该文件由文件系统中的路径名name命名。
使用字节输入流读数据的步骤:
- 创建字节输入流对象
- 调用字节输入流对象的读数据方法
- 释放资源
一次读取一个字节 read(),如果返回-1说明到了文件末尾
public class IoDemo { public static void main(String[] args) { //需求:把文件java.txt中的内容读取出来在控制台输出 File file = new File("idea_test\\java.txt"); //初始化fi FileInputStream fi = null; try { //创建字节输出流对象 fi = new FileInputStream(file); //调用字节输入流对象的读数据方法,一次读取一个字节 int read; while ((read = fi.read()) != -1) { //输出 System.out.print((char) read); } //释放资源 } catch (IOException e) { e.printStackTrace(); } finally { if (fi != null) { try { fi.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
再补充一个一次性读取文件全部内容的:
public class IoDemo {//throws抛出异常 public static void main(String[] args) throws IOException { //需求:把文件java.txt中的内容读取出来在控制台输出 File file = new File("idea_test\\java.txt"); //创建文件输入流对象 FileInputStream fi = new FileInputStream(file); //file.length()返回值是long,但byte只能装整形大小的空间,所以要强转 byte[] buffer = new byte[(int) file.length()]; //调用字节输入流对象的读数据方法,读取文件全部内容 fi.read(buffer); System.out.print(new String(buffer)); //释放资源 fi.close(); } }
注意:文件字节流读取文件,一次读一个字节,遇到中文会乱码;一次读取文件的所有内容,中文不会乱码。
字节流复制文本文件
思路:
- 根据数据源创建字节输入流对象
- 根据目的地创建字节输出流对象
- 读写数据,复制文本文件
- 释放资源
public class IoDemo { public static void main(String[] args) throws IOException { //需求:把文件G:\FileTest\Hello.txt中的内容复制到模块目录下的java.txt //1.根据数据源创建输入流对象 InputStream fo = new FileInputStream("G:\\FileTest\\Hello.txt"); //2.根据目的地创建输出流对象 OutputStream fi = new FileOutputStream("idea_test\\java.txt"); //一次读取一个字节,一次写入一个字节 //3.读文件 int read; while ((read = fo.read()) != -1) { //4.写入文件 fi.write(read); } //5.释放资源,先关闭输出流,在关闭输入流 fo.close(); fi.close(); } }
字节流读数据(一次读一个字节数组)
使用字节输入流读数据的步骤
- 创建字节输入流对象
- 调用字节输入流对象的读数据方法
- 释放资源
public class IoDemo1 { public static void main(String[] args) throws IOException { //创建字节输入流对象 InputStream fo = new FileInputStream("idea_test\\java.txt"); //创建一个字节数组,长度一般为1024及其整数倍 byte[] bytes = new byte[1024]; //创建字节输入流对象的读数据方法, // len 一次读取的字节数组的长度 int len; while ((len = fo.read(bytes)) != -1) { System.out.print(new String(bytes, 0, len)); } //释放资源 fo.close(); } }
注意:读含有中文的文件时,建议一次读完。
因为一个汉字占2~3个字节,如果正好读了半个汉字,那就乱码了(如图)。
后面的内容用字符流就更方便了,因为一个汉字一个字母都是一个字符。
字节流复制图片
思路
- 根据数据源创建字节输入流对象
- 根据目的地创建字节输出流对象
- 读写数据,复制图片
- 释放资源
public class IoDemo2 { public static void main(String[] args) throws IOException { //需求:把图片G:\FileTest\dog.jpg复制到模块目录下的dog.jpg //1.根据数据源创建输入流对象 InputStream fo = new FileInputStream("G:\\FileTest\\dog.jpg"); //2.根据目的地创建输出流对象 OutputStream fi = new FileOutputStream("idea_test\\dog.jpg"); //定义一个字节数组 byte[] bytes = new byte[1024]; //一次读取一个字节数组,一次写入一个字节数组 int len; //3.循环读写图片 while ((len = fo.read(bytes)) != -1) { //4.写入文件 fi.write(bytes,0,len); } //5.释放资源,先关闭输出流,在关闭输入流 fo.close(); fi.close(); } }
1|4IO字符流
字节缓冲输出流写数据
public class Demo { public static void main(String[] args) throws IOException { //字节缓冲输出流写数据 //创建字节缓冲输出流 BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("idea_test\\java.txt")); //写入数据 bos.write("hello\r\n".getBytes()); bos.write("java\r\n".getBytes()); //释放资源 bos.close(); } }
字节缓冲输入流读数据
public class Demo { public static void main(String[] args) throws IOException { //字节缓冲输入流读数据 //创建字节缓冲输入流,一次性从文件中读取8192个字节 BufferedInputStream bis = new BufferedInputStream(new FileInputStream("idea_test\\java.txt")); //一次读取的字节流数组长度 //每次读取的1024个字节,是直接从字节缓冲流那8192个字节里拿的,拿完之后字节缓冲流会再次从文件中一次性读取8192个字节 byte[] bytes = new byte[1024]; //读数据 int len; while ((len = bis.read(bytes)) != -1) { System.out.print(new String(bytes,0,len)); } //释放资源 bis.close(); } }
字节流复制视频
思路
- 根据数据源创建字节输入流对象
- 根据目的地创建字节输出流对象
- 读写数据,复制视频
- 释放资源
字节缓冲流一次读写一个字节数组
public class Demo1 { public static void main(String[] args) throws IOException { //把G:\FileTest\video.avi复制到模块目录下idea_test\video.avi BufferedInputStream bis = new BufferedInputStream(new FileInputStream("G:\\FileTest\\video.avi")); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("idea_test\\video.avi")); byte[] bytes = new byte[1024]; int len; while ((len = bis.read(bytes)) != -1) { bos.write(bytes,0,len); //System.out.println(new String(bytes,0,len)); } bos.close(); bis.close(); } }
速度:
- 基本字节流一次读写一个字节 < 基本字节流一次读写一个字节数组 < 字节缓冲流一次读写一个字节 < 字节缓冲流一次读写一个字节数组
为什么出现字符流
- 字节流操作中文不方便,所以Java提供了字符流
- 字符流 = 字节流 + 编码表
- 用字节流每次读写一个字节复制文本时,底层操作会自动进行字节拼接中文
- 汉字在存储的时候,无论选择哪种编码格式,第一个字节都是负数
案例:
public class Demo1 { public static void main(String[] args) throws IOException { String s = "abc"; byte[] bytes = s.getBytes("UTF-8"); byte[] bytes1 = s.getBytes("GBK"); //[97, 98, 99] System.out.println(Arrays.toString(bytes)); //[97, 98, 99] System.out.println(Arrays.toString(bytes1)); String s1 = "肥胖"; byte[] bytes2 = s1.getBytes("UTF-8"); byte[] bytes3 = s1.getBytes("GBK"); //[-24, -126, -91, -24, -125, -106] System.out.println(Arrays.toString(bytes2)); //[-73, -54, -59, -42] System.out.println(Arrays.toString(bytes3)); } }
编码表
- 计算机存储数据是二进制的(0和1)
- 编码和解码
- 按照规则,将字符存储到计算机中,称为编码;反之,将存储到计算机中的二进制内容按照规则解析显示出来,称为解码
- 编码和解码的规则必须一致,否则会出现乱码
- 字符编码
- 就是一套自然语言的字符与二进制数之间的对应关系。如(A,65)
字符集
- 是一个系统支持的所有字符集的集合,包括各国家文字,标点符号,图形符号,数字等
- 计算机要存储和识别各种字符集符号,就要进行字符编码,一套字符集必然至少有一套字符编码规则。常见的字符集有ASCII字符集,GBXXX字符集,Unicode字符集等
字符串中的编码解码问题
public class Demo1 { public static void main(String[] args) throws IOException { String s = "接化发"; //默认规则编码 byte[] bys = s.getBytes(); System.out.println(Arrays.toString(bys)); //指定规则编码 byte[] bys1 = s.getBytes("GBK"); System.out.println(Arrays.toString(bys1)); //默认规则解码 String s1 = new String(bys); System.out.println(s1); //指定规则解码 String s2 = new String(bys1, "GBK"); System.out.println(s2); } }
运行结果:
[-26, -114, -91, -27, -116, -106, -27, -113, -111] [-67, -45, -69, -81, -73, -94] 接化发 接化发
字符流中的编码解码问题
字符流抽象基类
- Reader:字符输入流的抽象类
- Writer:字符输出流的抽象类
InputStreamReader:是从字节流到字符流的桥梁
OutputStreamWriter:是从字符流到字节流的桥梁
public class Demo1 { public static void main(String[] args) throws IOException { //字符输出流对象 默认编码格式 //OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("idea_test\\java.txt")); //字符输出流对象 指定编码格式 OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("idea_test\\java.txt"),"UTF-8"); osw.write("蔬菜"); osw.close(); //字符输入流对象 指定编码格式 InputStreamReader isr = new InputStreamReader(new FileInputStream("idea_test\\java.txt"),"UTF-8"); //一次读取一个字符 int ch; while ((ch = isr.read()) != -1) { System.out.print((char)ch); } isr.close(); } }
flush()和close()的区别
- flush()刷新流,刷新之后还可以写数据
- close()关闭流,关闭流之前会自动执行刷新流操作,关闭之后就不能再继续写数据了
public class Demo2 { public static void main(String[] args) throws IOException { OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("idea_test\\java.txt")); osw.write(97); /** * 刷新缓冲 * 字符流写数据如果不刷新流,那么数据就在缓冲区中,没close()之前,打开文件java.txt看不到数据 * 字符流相对于字节流是有缓冲的,真正写数据是字节流 */ osw.flush(); //close():关闭流之前会自动执行刷新流操作 //flush()刷新流之后还可以继续写数据,但是close()关闭流之后就不能继续写数据了 osw.close(); } }
字符流写数据的5种方式:
public class Demo2 { public static void main(String[] args) throws IOException { OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("idea_test\\java.txt")); //1.写入一个字符:a osw.write(97); //2.写入一个字符数组:abcde char[] chs = {'a', 'b', 'c', 'd', 'e'}; osw.write(chs); //3.写入一个字符数组的一部分:abc osw.write(chs, 0, 3); //4.写入一个字符串:世界杯 String s = "世界杯"; osw.write(s); //5.写入一个字符串的一部分:界 osw.write(s,1,1); osw.flush(); osw.close(); } }
public class Demo2 { public static void main(String[] args) throws IOException { //创建字符输入流对象 InputStreamReader isr = new InputStreamReader(new FileInputStream("idea_test\\java.txt")); //1.一次读一个字符 int ch; while ((ch = isr.read()) != -1) { System.out.print((char) ch); } //2.一次读取一个字符数组 char[] chs = new char[1024]; int len; while ((len = isr.read(chs)) != -1) { System.out.print(new String(chs,0,len)); } isr.close(); } }
字符流复制Java文件
思路:
- 根据数据源创建字符输入流对象
- 根据目的地创建字符输出流对象
- 读写数据,复制文件
- 释放资源
public class Demo2 { public static void main(String[] args) throws IOException { //需求:将模块下的idea_test\java.txt,复制到idea_test\java1.txt //创建字符输入流对象 InputStreamReader isr = new InputStreamReader(new FileInputStream("idea_test\\java.txt")); //创建字符输出流对象 OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("idea_test\\java1.txt")); //读写数据,复制文件 char[] chs = new char[1024]; int len; while ((len = isr.read(chs)) != -1) { osw.write(chs,0,len); } osw.close(); isr.close(); } }
思路:
- 根据数据源创建字符输入流对象
- 根据目的地创建字符输出流对象
- 读写数据,复制文件
- 释放资源
public class Demo2 { public static void main(String[] args) throws IOException { //需求:将模块下的idea_test\java.txt,复制到idea_test\java1.txt //创建字符输入流对象 FileReader fr = new FileReader("idea_test\\java.txt"); //创建字符输出流对象 FileWriter fw = new FileWriter("idea_test\\java2.txt"); //读写数据,复制文件 char[] chs = new char[1024]; int len; while ((len = fr.read(chs)) != -1) { fw.write(chs,0,len); } fw.close(); fr.close(); } }
构造方法
- BufferedWriter(Writer out)
- BufferedReader(Reader in)
public class Demo2 { public static void main(String[] args) throws IOException { BufferedWriter bw = new BufferedWriter(new FileWriter("idea_test\\java.txt")); bw.write("hello\n"); bw.write("world\r"); bw.write("java\r\n"); bw.write(97); bw.write(98); bw.write(99); bw.close(); //缓冲流默认一次从文件里读取8192个字符 BufferedReader br = new BufferedReader(new FileReader("idea_test\\java1.txt")); //每次读取的1024个字符,是直接从缓冲流那8192个字符里拿的,拿完之后缓冲流会再次从文件中一次性读取8192个字符 char[] chs = new char[1024]; int len; while ((len = br.read(chs)) != -1){ System.out.println(new String(chs, 0, len)); } br.close(); } }
换行
- /r Mac
- /n Unix/Linux
- /r/n Windows
- 不过我在windows11上测试换行,以上三种都可以。
字符缓冲流复制Java文件
思路:
- 根据数据源创建字符缓冲输入流对象
- 根据目的地创建字符缓冲输出流对象
- 读写数据,复制文件
- 释放资源
public class Demo2 { public static void main(String[] args) throws IOException { //需求:java字符缓冲流复制文件,从idea_test\java.txt复制到idea_test\java3.txt BufferedReader br = new BufferedReader(new FileReader("idea_test\\java.txt")); BufferedWriter bw = new BufferedWriter(new FileWriter("idea_test\\java3.txt")); char[] chs = new char[1024]; int len; while ((len = br.read(chs)) != -1){ bw.write(chs,0,len); } bw.close(); br.close(); } }
newLine():就是根据系统,自动识别的换行符
readLine():一次读一行数据,如果读到了结尾则返回null;只读每行的内容,不读行尾终止符
public class Demo2 { public static void main(String[] args) throws IOException { //写数据 BufferedWriter bw = new BufferedWriter(new FileWriter("idea_test\\java.txt")); for (int i = 0; i < 10; i++) { bw.write("hello-"+i); //换行 bw.newLine(); bw.flush(); } bw.close(); //读数据 BufferedReader br = new BufferedReader(new FileReader("idea_test\\java.txt")); String s; while ((s = br.readLine()) != null){ System.out.println(s); } br.close(); } }
字符缓冲流特有功能复制Java文件
思路:
- 根据数据源创建字符缓冲输入流对象
- 根据目的地创建字符缓冲输出流对象
- 读写数据,复制文件(使用字符缓冲流特有功能)
- 释放资源
public class Demo2 { public static void main(String[] args) throws IOException { //需求:java字符缓冲流(特有功能)复制文件,从idea_test\java.txt复制到idea_test\java3.txt BufferedReader br = new BufferedReader(new FileReader("idea_test\\java.txt")); BufferedWriter bw = new BufferedWriter(new FileWriter("idea_test\\java4.txt")); char[] chs = new char[1024]; String s; while ((s = br.readLine())!=null){ //每写一行数据,换行,刷新 bw.write(s); bw.newLine(); bw.flush(); } bw.close(); br.close(); } }
字节流小结
- 字节流可以复制【任意文件】数据,有四种方式,一般采用字节缓冲流一次读写一个字节数组的方式
字符流小结
- 字符流只能复制【文本数据】,有五种方式,一般采用字符缓冲流的特有功能
1|5IO练习
1.集合到文件
public class Demo { public static void main(String[] args) throws IOException { //需求:将ArrayList集合中的字符串数据写入到文本文件。要求每一个字符串元素作为文件中的一行数据 //1.创建ArrayList集合 ArrayList<String> list = new ArrayList<>(); //2.向集合中创建字符串元素 list.add("hello"); list.add("world"); list.add("java"); list.add("世界杯"); //3.创建字符缓冲流输入对象 BufferedWriter bw = new BufferedWriter(new FileWriter("idea_test\\java.txt")); //4.遍历集合,得到每一个字符串数据 for (String s : list) { //5.调用字符缓冲流对象的方法写数据 bw.write(s); bw.newLine(); bw.flush(); } //6.释放资源 bw.close(); } }
public class Demo1 { public static void main(String[] args) throws IOException { //需求:把文本文件中的数据读取到集合中,并遍历集合。要求:文本中每一行数据是一个集合元素 //1.创建字符缓冲输入流对象 BufferedReader br = new BufferedReader(new FileReader("idea_test\\java.txt")); //2.创建ArrayList集合 ArrayList<String> list = new ArrayList<>(); //3.调用字符缓冲输入流对象的方法读数据 String s; while ((s = br.readLine()) != null) { //4.把读到的字符串数据存储到集合 list.add(s); } //5.释放资源 br.close(); //6.遍历集合 for (String s1 : list) { System.out.println(s1); } } }
运行结果:
hello world java 世界杯
3.点名器
public class Demo2 { public static void main(String[] args) throws IOException { //需求:文件中存储了班级同学的姓名,每一个姓名占一行,要求通过程序实现随机点名 //1.创建字符缓冲输入流对象 BufferedReader br = new BufferedReader(new FileReader("idea_test\\java.txt")); //2.创建ArrayList集合 ArrayList<String> list = new ArrayList<>(); //3.调用字符缓冲输入流对象的方法读数据 String line; while ((line = br.readLine()) != null) { //4.把读到的字符串数据存储到集合 list.add(line); } //5.释放资源 br.close(); //6.使用Random产生一个随机数,随机数的范围在:[0,集合长度) Random random = new Random(); int i = random.nextInt(list.size()); //7.把产生的随机数作为索引,在集合中获取值 String s = list.get(i); //8.将获取到的值输出到控制台 System.out.println(s); } }
4.集合到文件(改进版)
public class Demo1 { public static void main(String[] args) throws IOException { //需求:将ArrayList集合中的学生数据写入到文本文件。要求每一个向何生对象的数据作为文件中的一行数据 //格式:学号,姓名,年龄,居住地 //1.定义学生类 //2.创建ArrayList集合 ArrayList<Student> list = new ArrayList<>(); //3.创建学生对象 Student s1 = new Student("初二001", "小明", 15, "西安"); Student s2 = new Student("初二002", "小红", 16, "北京"); Student s3 = new Student("初二003", "小军", 17, "上海"); Student s4 = new Student("初二004", "白展堂", 14, "云南"); Student s5 = new Student("初二005", "史珍香", 13, "广州"); //4.把学生对象添加到集合中 list.add(s1); list.add(s2); list.add(s3); list.add(s4); list.add(s5); //5.创建字符缓冲输出流对象 BufferedWriter bw = new BufferedWriter(new FileWriter("idea_test\\java.txt")); //6.遍历集合,得到每一个学生对象 for (Student stu : list) { //7.把学生对象的数据拼接成指定格式的字符串 StringBuffer sb = new StringBuffer(); sb.append(stu.getId() + "," + stu.getName() + "," + stu.getAge() + "," + stu.getAddress()); //8.调用字符缓冲输出流对象的方法写数据 bw.write(sb.toString()); bw.newLine(); bw.flush(); } //9.释放资源 bw.close(); } }
5.文件到集合(改进版)
public class Demo3 { public static void main(String[] args) throws IOException { /** * 需求:把文本文件中的数据读取到集合中,并遍历集合。 * 要求:文本中每一行数据是一个学生对象的成员变量值 * 格式:学号,姓名,年龄,居住地 */ //1.定义学生类 //2.创建字符缓冲输入流对象 BufferedReader br = new BufferedReader(new FileReader("idea_test\\java.txt")); //3.创建ArrayList集合 ArrayList<Student> list = new ArrayList<>(); String line; //4.调用字符缓冲输入流对象的方法读数据 while ((line = br.readLine()) != null) { //5.把读取到的字符串用split分割,得到一个字符串数组 String[] s = line.split(","); //6.创建学生对象 Student stu = new Student(); //7.把字符串数组中的每一个元素取出来,赋值给学生对象的成员变量 stu.setId(s[0]); stu.setName(s[1]); stu.setAge(Integer.parseInt(s[2])); stu.setAddress(s[3]); //8.把学生对象添加到集合 list.add(stu); } //9.释放资源 br.close(); //10.遍历集合 for (Student s : list) { //直接输出,因为Student类中重写了toString() System.out.println(s); } } }
运行结果:
Student{id='初二001', name='小明', age=15, address='西安'} Student{id='初二002', name='小红', age=16, address='北京'} Student{id='初二003', name='小军', age=17, address='上海'} Student{id='初二004', name='白展堂', age=14, address='云南'} Student{id='初二005', name='史珍香', age=13, address='广州'}
1|6标准流和打印流
集合到文件数据排序(改进版)
定义学生类:
public class Student { private String name; private int yuwen; private int shuxue; private int yingyu; public Student() { } public Student(String name, int yuwen, int shuxue, int yingyu) { this.name = name; this.yuwen = yuwen; this.shuxue = shuxue; this.yingyu = yingyu; } //定义获取总分的方法 public int getSum() { return this.yuwen + this.shuxue + this.yingyu; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getYuwen() { return yuwen; } public void setYuwen(int yuwen) { this.yuwen = yuwen; } public int getShuxue() { return shuxue; } public void setShuxue(int shuxue) { this.shuxue = shuxue; } public int getYingyu() { return yingyu; } public void setYingyu(int yingyu) { this.yingyu = yingyu; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", yuwen=" + yuwen + ", shuxue=" + shuxue + ", yingyu=" + yingyu + '}'; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Student student = (Student) o; if (yuwen != student.yuwen) return false; if (shuxue != student.shuxue) return false; if (yingyu != student.yingyu) return false; return name != null ? name.equals(student.name) : student.name == null; } @Override public int hashCode() { int result = name != null ? name.hashCode() : 0; result = 31 * result + yuwen; result = 31 * result + shuxue; result = 31 * result + yingyu; return result; } }
测试类:
public class Demo { public static void main(String[] args) throws IOException { /** * 需求:键盘录入几个学生信息(姓名,语文成绩,数学成绩,英语成绩) * 要求:按照成绩总分由高到低写入文件(排序规则) */ Set<Student> list = new TreeSet<>(new Comparator<Student>() { //匿名内部类重写排序方法 @Override public int compare(Student o1, Student o2) { //总分从低到高 int num = o2.getSum() - o1.getSum(); //如果总分相同,按照语文成绩从高到低 int num1 = num == 0 ? o1.getYuwen() - o2.getYuwen() : num; //如果总分相同,语文成绩也相同,按照数学成绩从高到低 int num2 = num1 == 0 ? o1.getShuxue() - o2.getShuxue() : num1; //如果总分相同,语文成绩也相同,数学成绩也相同,说明英语成绩肯定相同,那就按照姓名的字母排序 int num3 = num2 == 0 ? o1.getName().compareTo(o2.getName()) : num2; return num3; } }); for (int i = 0; i < 5; i++) { Scanner sc = new Scanner(System.in); System.out.println("请输入第" + (i + 1) + "学生信息:"); System.out.println("姓名:"); String name = sc.nextLine(); System.out.println("请输入语文成绩:"); int yuwen = sc.nextInt(); System.out.println("请输入数学成绩:"); int shuxue = sc.nextInt(); System.out.println("请输入英语成绩:"); int yingyu = sc.nextInt(); Student s = new Student(name, yuwen, shuxue, yingyu); list.add(s); } BufferedWriter bw = new BufferedWriter(new FileWriter("idea_test\\java.txt")); for (Student stu : list) { StringBuilder sb = new StringBuilder(); sb.append(stu.getName() + "," + stu.getYuwen() + "," + stu.getShuxue() + "," + stu.getYingyu() + ",总分:" + stu.getSum()); bw.write(sb.toString()); bw.newLine(); bw.flush(); } bw.close(); } }
运行结果:总分从高到低排序
关羽,89,94,1,总分:184 孙权,1,99,3,总分:103 张飞,1,88,9,总分:98 caocao,1,55,9,总分:65 刘备,1,2,3,总分:6
复制单级文件夹
单级文件夹:文件夹中只有文件,没有文件夹
public class Demo2 { public static void main(String[] args) throws IOException { /** * 需求复制单级文件夹及其内容 */ //1.创建数据源目录 File file = new File("G:\\FileTest\\dog"); //2.获取创建数据源目录的名称 String name = file.getName(); //3.创建目的地File对象 File file1 = new File("idea_test", name); //4.判断目的地是否已经存在该名称的文件夹 if (!file1.exists()) { //5.在目的地创建该名称的文件夹 file1.mkdir(); } //6.获取数据源文件夹下的所有文件 File[] files = file.listFiles(); //7.遍历数组,得到每一个文件对象 for (File fi : files) { //8.获取文件名称 String fiName = fi.getName(); //9.在目的地文件夹中,创建fiName同名称的文件 File fil = new File(file1, fiName); //10.复制文件内容:将数据源文件内容复制到目的地文件中 copyFile(fi, fil); } } /** * 字节缓冲流复制文件内容 * @param f1 数据源文件 * @param f2 目的地文件 */ public static void copyFile(File f1, File f2) throws IOException { //缓冲字节输入流对象 BufferedInputStream bis = new BufferedInputStream(new FileInputStream(f1)); //缓冲字节输出流对象 BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(f2)); //读写文件 byte[] bytes = new byte[1024]; int len; while ((len = bis.read(bytes)) != -1) { bos.write(bytes,0,len); } bos.close(); bis.close(); } }
复制多级文件夹
多级文件夹:文件夹下还有文件夹
public class Demo3 { public static void main(String[] args) throws IOException { //1.创建数据源目录 File srcFile = new File("G:\\FileTest"); //2.创建目的地File对象 File destFile = new File("D:\\"); //复制文件夹,参数为数据源File对象 和 目的地File对象 copyFolder(srcFile,destFile); } /** * 复制文件夹 * @param srcFile 数据源文件夹操作对象 * @param destFile 目的地文件夹操作对象 */ private static void copyFolder(File srcFile,File destFile) throws IOException { //判断数据源是否是目录,如果是目录 if (srcFile.isDirectory()){ //获取数据源文件夹名称 String srcFileName = srcFile.getName(); //目的地文件夹名称 File destFileName = new File(destFile, srcFileName); //判断新文件夹名称在目的地是否存在 if(!destFileName.exists()){ destFileName.mkdir(); } //获取数据源文件夹下的文件 File[] files = srcFile.listFiles(); //遍历该数组,得到每一个元素对象 for (File file : files) { //file可能是文件,也可能是文件夹;所以递归调用复制文件夹方法 copyFolder(file,destFileName); } }else {//如果数据源不是目录 File newFile = new File(destFile, srcFile.getName()); copyFile(srcFile,newFile); } } /** * 复制文件内容 * @param f1 数据源文件操作对象 * @param f2 目的地文件操作对象 */ public static void copyFile(File f1, File f2) throws IOException { //缓冲字节输入流对象 BufferedInputStream bis = new BufferedInputStream(new FileInputStream(f1)); //缓冲字节输出流对象 BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(f2)); //读写文件 byte[] bytes = new byte[1024]; int len; while ((len = bis.read(bytes)) != -1) { bos.write(bytes,0,len); } bos.close(); bis.close(); } }
案例:复制文件;以下是几种处理异常的方法
/** * 复制文件内容 * * @param f1 数据源文件操作对象 * @param f2 目的地文件操作对象 */ public static void copyFile(File f1, File f2) { BufferedInputStream bis = null; BufferedOutputStream bos = null; try { //缓冲字节输入流对象 bis = new BufferedInputStream(new FileInputStream(f1)); //缓冲字节输出流对象 bos = new BufferedOutputStream(new FileOutputStream(f2)); //读写文件 byte[] bytes = new byte[1024]; int len; while ((len = bis.read(bytes)) != -1) { bos.write(bytes, 0, len); } } catch (IOException e) { e.printStackTrace(); } finally { if (bos != null) { try { bos.close(); } catch (IOException e) { e.printStackTrace(); } } if (bis != null) { try { bis.close(); } catch (IOException e) { e.printStackTrace(); } } } }
/** * 字节缓冲流复制文件内容 * @param f1 数据源文件 * @param f2 目的地文件 * JDK7之后的写法,会自动释放资源,不需要close() */ public static void copyFile1(File f1, File f2) { //注意try后面的的小括号 try(//缓冲字节输入流对象 BufferedInputStream bis = new BufferedInputStream(new FileInputStream(f1)); //缓冲字节输出流对象 BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(f2))) { //读写文件 byte[] bytes = new byte[1024]; int len; while ((len = bis.read(bytes)) != -1) { bos.write(bytes,0,len); } } catch (IOException e) { e.printStackTrace(); } }
/** * 字节缓冲流复制文件内容 * @param f1 数据源文件 * @param f2 目的地文件 */ public static void copyFile2(File f1, File f2) throws FileNotFoundException { //缓冲字节输入流对象 BufferedInputStream bis = new BufferedInputStream(new FileInputStream(f1)); //缓冲字节输出流对象 BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(f2)); try(bis;bos) { //读写文件 byte[] bytes = new byte[1024]; int len; while ((len = bis.read(bytes)) != -1) { bos.write(bytes,0,len); } } catch (IOException e) { e.printStackTrace(); } }
标准输入流
System类中有两个静态成员变量
- public static final InputStream in:“标准”输入流。此流已经 打开并准备提供输入数据。通常此流 对应于键盘输入或由 指定的其他输入源 主机环境或用户。
- public static final PrintStream out:“标准”输出流。此流已经 打开并准备接受输出数据。通常此流 对应于显示输出或其他输出目标 由主机环境或用户指定。
- 自己实现输入操作
public class Demo { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); System.out.println("请输入一个字符串:"); String line = br.readLine(); System.out.println("你输入的字符串是:" + line); System.out.println("请输入一个整数:"); System.out.println("你输入的整数是:"+Integer.parseInt(br.readLine())); } }
运行:
请输入一个字符串: hello 你输入的字符串是:hello 请输入一个整数: 123 你输入的整数是:123
- Java提供的输入类Scanner
//自己实现输入操作太麻烦,所以Java提供了一个类 Scanner sc = new Scanner(System.in);
标准输出流
public class Demo1 { public static void main(String[] args) { PrintStream out = System.out; out.print("hello"); out.println("world"); out.println(100); /** * System.out的本质是一个字节输出流 * print()必须有参数 * println()可以没有参数 * PrintStream类有的方法,System.out都可以调用 */ System.out.println(); System.out.print("世界杯"); System.out.println(123); } }
运行:
helloworld 100 世界杯123
字节打印流
打印流分类:
- 字节打印流:PrintStream
- 字符打印流:PrintWriter
打印流的特点:
- 只负责输出数据,不负责读取数据
- 有自己的特有方法
字节打印流
- PrintStream(String fileName):使用指定的文件名创建新的打印流
- 使用继承父类的方法写数据,查看的时候会转码;使用自己的特有方法写数据,查看的数据原样输出
public class Demo { public static void main(String[] args) throws FileNotFoundException { //创建字节打印流对象 PrintStream ps = new PrintStream("idea_test\\java1.txt"); //写数据 // 1.字节输出流写数据 //使用继承父类的方法写数据,查看的时候会转码 ps.write(97); ps.write(98); ps.println(); // 2.字节打印流特有方法写数据 //使用自己的特有方法写数据,查看的数据原样输出 ps.println(97); ps.print(98); ps.close(); } }
public class Demo1 { public static void main(String[] args) throws IOException { //创建字符打印流对象 PrintWriter pw = new PrintWriter("idea_test\\java2.txt"); pw.write("世界杯"); pw.write("\r\n"); pw.flush(); pw.write("足球"); pw.write("\r\n"); pw.flush(); pw.println("hello"); pw.flush(); pw.println("world"); pw.flush(); pw.close(); //PrintWriter(Writer out,boolean outFlush) //创建一个新的PrintWriter,true自动刷新flush PrintWriter pw1 = new PrintWriter(new FileWriter("idea_test\\java3.txt"), true); pw1.println("麻辣"); pw1.println("米线"); pw1.close(); } }
复制Java文件(打印流改进版)
思路
- 根据数据源创建字符输入流对象
- 根据目的地创建字符输出流对象
- 读写数据,复制文件
- 释放资源
public class Demo2 { public static void main(String[] args) throws IOException { /*需求:把idea_test\java.txt复制到idea_test\java4.txt*/ BufferedReader br = new BufferedReader(new FileReader("idea_test\\java.txt")); PrintWriter pw = new PrintWriter(new FileWriter("idea_test\\java4.txt"), true); //读写数据 String line; while((line = br.readLine())!=null){ pw.println(line); } pw.close(); br.close(); } }
1|7对象序列化流
对象序列化流
对象序列化流
- 就是将对象保存到磁盘中,或者在网络中传输对象
- 这种机制就是使用一个字节序列表示一个对象,该字节序列包含:对象的类型,对象的数据和对象中存储的属性等
- 字节序列写到文件之后,相当于文件中持久保存了一个对象的信息
- 反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化
对象序列化流:ObjectOutputStream
对象反序列化流:ObjectInputStream
public class Demo { public static void main(String[] args) throws IOException { /*需求:将学生对象序列化到文件idea_test\hello.txt*/ //创建对象序列化流操作对象 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("idea_test\\hello.txt")); //创建学生对象;Student类实现了Serializable接口 Student s = new Student("马超", 30); //序列化对象 oos.writeObject(s); //释放资源 oos.close(); } }
public class Demo1 { public static void main(String[] args) throws IOException, ClassNotFoundException { /*需求:将文件idea_test\hello.txt中的学生对象反序列化*/ //创建对象反序列化流操作对象 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("idea_test\\hello.txt")); //反序列化对象 Object o = ois.readObject(); //强转对象类型 System.out.println((Student)o); //释放资源 ois.close(); } }
运行结果:
//Student类中重写了toString() Student{name='马超', age=30}
1|8Properties类
Properties概述
- 是一个Map体系的集合类
- Properties可以保存到流中或从流中加载
- Properties不能有泛型;默认是<Object,Object>类型
Properties作为Map集合
public class PropertiesDemo { public static void main(String[] args) { //创建集合对象 Properties p = new Properties(); //添加元素 p.put("高一1班", "张铁牛"); p.put("高一2班", "马牛旦"); p.put("高一3班", "李桂皮"); //遍历 for (Object key : p.keySet()) { Object value = p.get(key); System.out.println(key + "," + value); } } }
运行结果:
高一3班,李桂皮 高一2班,马牛旦 高一1班,张铁牛
public class PropertiesDemo { public static void main(String[] args) { //创建集合对象 Properties p = new Properties(); System.out.println("Properties集合:" + p); //添加元素 p.setProperty("高一1班", "张铁牛"); p.setProperty("高一2班", "马牛旦"); p.setProperty("高一3班", "李桂皮"); //返回键的合集 Set<String> keys = p.stringPropertyNames(); //遍历 for (String key : keys) { //根据键获取值 String value = p.getProperty(key); System.out.println(key + "," + value); } } }
运行结果:
Properties集合:{} 高一3班,李桂皮 高一2班,马牛旦 高一1班,张铁牛
public class PropertiesDemo1 { public static void main(String[] args) throws IOException { //把集合中的数据保存到文件 myStore(); //把文件中的数据加载到集合 myLoad(); } /** * 把文件中的数据加载到集合 */ private static void myLoad() throws IOException { //创建集合对象 Properties p = new Properties(); //创建字符输入流对象 FileReader fr = new FileReader("idea_test\\fw.txt"); //读取元素到集合 p.load(fr); fr.close(); //输出集合 System.out.println(p); } /** * 把集合中的数据保存到文件 */ private static void myStore() throws IOException { //创建集合对象 Properties p = new Properties(); //添加元素 p.setProperty("高一1班", "张铁牛"); p.setProperty("高一2班", "马牛旦"); p.setProperty("高一3班", "李桂皮"); //创建字符输出流对象 FileWriter fw = new FileWriter("idea_test\\fw.txt"); //将元素写入Properties p.store(fw,null); fw.close(); } }
{高一3班=李桂皮, 高一2班=马牛旦, 高一1班=张铁牛}
__EOF__

本文链接:https://www.cnblogs.com/chawaner/p/16943303.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix