一、FIle类
1、将文件系统中的文件或文件夹封装成了File对象。提供了操作文件和文件夹的一些方法。
(1)实例化一个File对象 File file = new File(String path); 里面接收一个字符串类型的文件路径。
<1> 创建文件:file.createNewFile();
<2>创建文件夹 file.mkdir() 创建多级目录文件夹 file.mkdirs() 这个取决于最初指定的路径,如果是一个不存在的多级目录,那就可以创建多级目录。
<3>查看某一路径下所有的文件和文件夹 file.listFiles().返回一个File类型的数组,若文件夹中还有文件和文件夹,此时需要递归查看了。
public static void showFile(File dir, int level) { if (!dir.exists()) { dir.mkdir(); } //打印显示时候的缩进空格数 level++; System.out.println(getSpace(level) + dir.toString()); for (File file : dir.listFiles()) { //判断是不是文件夹,是,再次递归 if (file.isDirectory()) { showFile(file, level); } else { System.out.println(getSpace(level) + file.toString()); } } } /** * 打印缩进的空格数 * @param level * @return */ public static String getSpace(int level) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < level; i++) { sb.append(" "); } return sb.toString(); }
<4>删除文件 file.delete(),但是java中只支持删除单纯的文件或者空的文件夹,如果文件夹中还有不为空的文件夹,那么删除失败,此时需要使用递归删除,层级删除目录。
代码如下:单纯删除文件夹和文件(递归)
/** * 递归删除非空文件夹 * @param dir */ public static void deleteFile(File dir) { if (!dir.exists()) { System.out.println("路径不存在"); return; } if(dir.delete()) { System.out.println("是空文件夹,直接可以删除"); return; } //列出当前目录下所有的文件和文件夹 for (File file : dir.listFiles()) { //这种写法就是先深层到最里面一层去删除文件,然后逐层往外删除文件, //直到文件夹中所有的文件都删除后,剩下的都是空文件夹,一个一个逐层往回干掉 if(file.isDirectory()) { deleteFile(file); }else { System.out.println(file+":"+file.delete()); } //这种写法就是先尝试删除,如果不是非空文件夹就删除失败,返回false,进入if结构,再次递归 // if(!file.delete()) { // deleteFile(file); // } } System.out.println(dir+":"+dir.delete()); }
二、字节流 - 字符流
(1)字符流:Reader Writer (抽象类,必须使用子类实例化)
<1> 简单的纯文本文件的读写 使用FileReader 和 FileWriter 需要传入一个FIle对象或者传路径
- FileReader 一次读取一个字符,返回当前读取到的字符的整数表达形式,达到末尾返回-1,表示读取结束。
Reader reader = new FileReader("D:/test/abc.txt"); int len = 0; //一次读取一个字符,返回一个当前读取字符的整形数字 while((len = reader.read())!=-1) { //输出时候需要转换一个char System.out.println((char)len); }
- FileReader 也可以自定义一个数组,一次读取数组长度的数据。其实这就是自定义缓冲区,提高读取效率
Reader reader = new FileReader("D:/test/abc.txt"); int len = 0; //自定义一个1024长度的数组。长度随便定义 char[] ch = new char[1024]; //每次读取字符先存放到这个ch字符数组中,然后一次处理1024长度的数据, //最后一次可能不足数组长度,所以要使用len长度。 while ((len = reader.read(ch)) != -1) { System.out.println(new String(ch, 0, len)); }
-FilleWriter使用 跟FIleReader基本类似,只是一个写入文件的过程。
Reader reader = new FileReader("D:/test/abc.txt"); Writer writer = new FileWriter("D:/test/def.txt"); int len = 0; //自定义一个1024长度的数组。长度随便定义 char[] ch = new char[1024]; //每次读取字符先存放到这个ch字符数组中,然后一次处理1024长度的数据, //最后一次可能不足数组长度,所以要使用len长度。 while ((len = reader.read(ch)) != -1) { //直接写入字符串 // writer.write("aasdadas"); //向文件中一次写入数组长度的数据,高效. writer.write(ch, 0, len); writer.flush(); }
//关流
reader.close();
writer.close;
<2> BufferedReder :缓冲字符输入流。将读取到的字符先缓冲在缓冲区中,随后再做其他操作。
一次读取一个字符的缓冲:
BufferedReader bufr = new BufferedReader(new FileReader("D:/test/abc.txt")); int len = 0; while ((len = bufr.read()) != -1) { System.out.println((char)len); }
bufr.close();
一次读取一行的缓冲:
BufferedReader bufr = new BufferedReader(new FileReader("D:/test/abc.txt")); String line = null; //使用readLine()方法一次读取文件一行的数据,末尾返回null while ((line = bufr.readLine()) != null) { System.out.println(line); }
bufr.close();
<3>BufferedWriter:缓冲字符输出流,一般是先读取数据,将数据先缓冲到缓冲区中,然后再写入到文件中。
// 将读取到的数据写入到另一个文件中,使用两个缓冲流
BufferedReader bufr = new BufferedReader(new FileReader("D:/test/abc.txt")); BufferedWriter bufw = new BufferedWriter(new FileWriter("D:/test/def.txt")); String line = null; while ((line = bufr.readLine()) != null) { // 一次写入一行数据(到缓冲区中) bufw.write(line); // 写入一个系统换行符,因为上面读取到的是一行内容,那么写入这一行后也要进行换行 bufw.newLine(); // 刷新缓冲区,将数据写入到文件中 bufw.flush(); } bufr.close(); bufw.close();
<4> 转换流 InputStreamReader:这是字节流通往字符流的桥梁,里面接收的是一个字节流。
一般情况下用于读取控制台输入的数据写入到文件中。(因为控制台System.in是一个标准的字节输入流,但是控制台输入的是字符数据,因此转换成字符流操作更加便捷)
//没有使用缓冲,略显的粗糙,不能跳出循环 InputStreamReader insr = new InputStreamReader(System.in); FileWriter fw = new FileWriter("D:/test/def.txt"); int len = 0; //没有缓冲,一次读写一个字符 while ((len = insr.read()) != -1) { fw.write(len); fw.flush(); } insr.close(); fw.close();
<5>转化流,OutputStreamWriter :字符流通往字节流的桥梁,里面接收的是一个字节流。
一般情况下,从文本文件中读取数据,输出到控制台上。
// 缓冲流读取数据 BufferedReader bufr = new BufferedReader(new FileReader("D:/test/abc.txt")); // 接收一个标准的字节输出流 OutputStreamWriter osw = new OutputStreamWriter(System.out); String line = null; while ((line = bufr.readLine()) != null) { //这就输出到了控制台,实际跟System.out.println()效果一样 osw.write(line); osw.flush(); } bufr.close(); osw.close();
(2)字节流:InputStream OutputStream (抽象类,使用子类实例化)
<1> InputStream :字节输入流。以字节的形式读取数据,使用跟字符流差不多,可以一次读取一个字节,可以一次读取数组长度的字节(自定义缓冲)。
InputStream in = new FileInputStream(new File("D:/test/abc.txt")); int len = 0; //一次读取一个字节 while ((len = in.read()) != -1) { //文件中有中文会乱码,因为中文在utf-8编码中是两个字节,一个字节没法表示。 System.out.println((char)len); }
<2>OutputStream:字节输出流。以字节的形式将数据写入文件中。可以一次一个字节,也可以一次一个数组长度的字节(自定义缓冲)
InputStream in = new FileInputStream(new File("D:/test/abc.txt")); OutputStream out = new FileOutputStream(new File("D:/test/def.txt")); int len = 0; //自定义缓冲数组 byte[] b = new byte[1024]; //读取数组长度的字节,存放到字节数组中,满了再操作 while ((len = in.read(b)) != -1) { //将每次读取到的字节,写入到另一个文件中,中文不会乱码。 out.write(b, 0, len); } in.close(); out.close();
三、缓冲流
当需要高效读写的时候,就可以在对应使用的流(Reder Writer InputStream OutputStream)之前加上 Buffered,来定义缓冲流,读写更高效,里面需要什么new什么。
// 定义一个字符缓冲流,读取数据 BufferedReader bufr = new BufferedReader(new FileReader(new File("D:/test/abc.txt"))); // 定义一个字节缓冲流,写入数据 BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream(new File("D:/test/def.txt"))); String line = null; while ((line = bufr.readLine()) != null) { // 因为使用的是字符流读入的是一个字符, // 所以使用字节流输出时候要使用getBytes()方法,转成字节 bufos.write(line.getBytes()); // 刷新缓冲区,输出到文件中 bufos.flush(); } bufr.close(); bufos.close();
四、对象流 : 对象的序列化和反序列化
将对象的一些属性和方法序列化成流的形式,存储到文件中,当需要使用的时候,读取文件然后反序列化就可以拿到该对象
//对象的序列化与反序列化 //对象流 -输出流-序列化过程 //1.1初始化对象输出流:将当前对象中包含的一些信息保存到文档中 ObjectOutputStream objOut = new ObjectOutputStream(new FileOutputStream("D:/test/object.txt")); //2.获得一个自定义类实例 Product product = new Product(); product.setName("生活用品"); //3.序列化对象,输出 objOut.writeObject(product); //4.刷新,关流 objOut.flush(); objOut.close(); //输入流-反序列化过程 //1.2初始化一个对象输入流 ObjectInputStream objIn = new ObjectInputStream(new FileInputStream("D:/test/object.txt")); //1.3获得一个反序列化后的Object对象 Object obj = objIn.readObject(); //1.4判断反序列化后的对象是否是原来的实例 if(obj instanceof Product) { Product newProduct = (Product)obj; System.out.println(newProduct); } //1.5关流 objIn.close();
五、标准的输入输出流-System.in System.out
1.System.in 我们经常使用的读取控制台输入的数据。常用的Scanner对象就是接收一个标准的输入流。但是这并不仅仅局限于控制台,它可以实现跟其他的输入流一样的操作,读取文件中的数据同样可以完成,此时需要我们改变输入流的流向了。
2.同样Systme.out 也是常规用在输出打印在控制台中(System.out.println())。但是也可以改变它的流向,输出到文件中
代码:
public static void main(String[] args) throws IOException { // TODO 标准流练习 //用一个字节流接收 原始的System.in out 流 InputStream in = System.in; PrintStream out = System.out; InputStream inputStream = new FileInputStream("D:/test/data.txt"); OutputStream outputStream = new FileOutputStream("D:/test/SystemTest.txt", true); //设置改变标准流的输出位置,输出到文件中 System.setOut(new PrintStream(outputStream)); List<String> list = new ArrayList<>(); Scanner scanner = new Scanner(in); while (true) { String str = scanner.nextLine(); if ("over".equals(str)) { break; } list.add(str); } for (String line : list) { System.out.println(line); } // 更换输入流 输出流的流向 System.setIn(inputStream);// 指定到文件中读取 System.setOut(out);// 指定到控制台中输出 scanner = new Scanner(System.in); System.out.println(scanner.nextLine()); in.close(); out.close(); inputStream.close(); outputStream.close(); scanner.close(); }