Java I/O流(文件操作)
Java把电脑中的文件和文件夹封装为一个File类,开发者可以使用File类对文件进行操作。 其它两个是返回字符串类型的值。 listFiles方法会对传递的目录进行遍历,获取目录的每一个文件并封装成File对象。 listFiles方法会调用参数传递的过滤器中的accept方…
Java把电脑中的文件和文件夹封装为一个File类,开发者可以使用File类对文件进行操作。

// 返回系统路径分隔符String pathSeparator = File.pathSeparator; // Win环境是 ;
// 返回系统默认名称分割符String separator = File.separator; // Win环境是 /其它两个是返回字符串类型的值。
// 可以传一个参数,传文件所在绝对路径或者相对路径。File(String pathname)// 传两个参数的话第一个参数是文件夹,第二个参数是文件名。public File(String parent, String child)File file = new File("../test.txt");// 返回文件绝对路径file.getAbsoluteFile();// 返回路径名字file.getPath();// 返回文件名或者目录名file.getName();// 返回文件的长度file.length();// 判断传的文件或目录是否存在file.exists();
// 如果路径不存在,下面两个方法都返回false// 判断传的路径是否为目录file.isDirectory();// 判断传的路径是否为文件file.isFile();// 如果传的目录不存在,创建file.mkdir();
// 创建文件或者目录可能失败,意味着可能抛出异常,所以必须要处理异常// 如果传的文件名不存在,创建file.createNewFile()// 递归的创建,如同mkdir -pfile.mkdirs()
// 如果传的路径不存在或者不是目录,会抛出空指针异常// 返回String 数组,所传路径中所有子文件或者目录file.list()// 返回一个File数组,表示该File目录中所有的文件或目录file.listFiles()public class FileFilterImpl implements FileFilter{ @Override public boolean accept(File pathname) { return false; }}- listFiles方法会对传递的目录进行遍历,获取目录的每一个文件并封装成File对象。
- listFiles方法会调用参数传递的过滤器中的accept方法。
- listFiles方法会把遍历得到的每一个File对象传递给accept方法。和Vue2里的filter(过滤器)很像。 如果accept返回true,就会把传递的File对象存入File数组。
public class test{
public static void main(String[] args) throws IOException { File file = new File("f:\\repos\\test"); getAllFile(file); }
public static void getAllFile(File dir){ File[] files = dir.listFiles(new FileFilter() { @Override public boolean accept(File pathname) { return pathname.isDirectory() || pathname.getName().toLowerCase().endsWith(".ejs"); } });
// 使用Lambda表达式优化 // File[] files = dir.listFiles(pathname->pathname.isDirectory() || pathname.getName().toLowerCase().endsWith(".ejs"));
for (File file : files) { if (file.isDirectory()){ getAllFile(file); }else { System.out.println(file); } } }}还有一个过滤器是FilenameFilter,功能差不多。不过accpet方法要传两个参数,路径和文件名,例子:
File[] files = dir.listFiles(new FileFilter() { @Override public boolean accept(File dir,String name) { return new File(dir,name).isDirectory() || name.getName().toLowerCase().endsWith(".ejs"); } });把硬盘中的数据读取到内存是输入(读取),把内存中的数据写入到硬盘中式输出(写入)。数据不同,所以流分为子节输入流和字符输入流。
输出字节流的所有类的超类——OutputStream。抽象方法:
// 关闭输出流并释放与此流有关的所有系统资源(会自动调用flush)close()// 刷新此输出流并强制写出所有缓冲的输出子节(把内容写入到文本)flush()// 将指定的子节写入此输入流wirte()将内存中的数据写入到硬盘文件——FileOutputStream。
// 传路径或者File实例// 第二个参数默认为false,每次写都会覆盖前一次内容。为true的话多次写入会追加。FileOutputStream fileOutputStream = new FileOutputStream("f:\\test.txt",true);// FileOutputStream fileOutputStream = new FileOutputStream(new File("f:\\test.txt"));
// write也可以传入的整数,Java会把转换为ASCII码fileOutputStream.wirte("hello world".getBytes());fileOutputStream.close();
// 输入换行// win: \r\n// Linux: /n// mac: /r写入数据整个流程如下: Java程序 -> JVM -> OS -> OS调用写数据的方法 -> 把数据写入到文件中。
输入字节流的所有类的超类——InputStream。抽象方法:
// 读取read()// 关闭流close将硬盘中文件的数据读取到内存中——FileInputStream。
FileInputStream fileInputStream = new FileInputStream("f:\\test.txt",true);// FileInputStream fileInputStream = new FileInputStream(new File("f:\\test.txt"));
// 读取文件中的一个子节然后返回(指针会向后移),如果读到末尾就返回-1// fileInputStream.read()// 显然不可能一直手动用read(),所以读文件通常如下:int len = 0; // 接收读取的子节while(len = fileInputStream.read() != -1){ System.out.println(len)}
// read可以传byte数组,数组长度多少就读取多少个子节。通常定义为1024(1Kb)或者它的整倍数// 返回的int是有效子节个数
// int len = fileInputStream.read(new byte[1024])
byte[] bytes = new byte[1024];int len = 0;while((len = fileInputStream.read(bytes) != -1)){ System.out.println(new String(bytes,0,len));}
fileInputStream.close()读取整个流程如下: Java程序 -> JVM -> OS -> OS调用读取数据的方法 -> 读取文件。
字节流读取中文时存在问题。因为中文编码每个字都是大于1个子节。
输入字符流的所有类的超类——Reader。抽象方法:
// 读取单个字符并返回// 传子节数组的话就是读取多个字符,将字符存入数组read()// 释放资源close()把硬盘中的数据以字符的方式读到内存中——FileReader。
FileReader fr = new FileReader("f:\\test.txt");char[] cs = new char[1024];int len = 0;while ((len = fr.read(cs)) != -1){ System.out.println(new String(cs,0,len));}输出字符流的所有类的超类——Writer。把内存中的字符数据写入到文件中——FileWriter。FileOutputStream不close数据也会到文件中。但是Writer如果不使用close或者flush方法,数据只是在缓冲区。常用方法:
// 第二个参数为true开启续写try(FileWriter fw = new FileWriter("f:\\test1.txt",true);){ char[] cs = {'d','e'};
// 可以传一个整数(ASCII码),也可以传字符数组或字符串 fw.write(97); fw.write("bc"); fw.write(cs); }Properties类实现了Map和Hashtable集合。表示持久的属性集。可以保存在流中也可以从流中加载。它时唯一和IO流相结合的集合。常用方法:
// 把集合中的临时数据持久化写入到硬盘中存储store()// 把硬盘中得到文件(键值对)读取到集合中使用load它的key和value默认都是字符串。输出:
Properties properties = new Properties(); properties.setProperty("测试", "111"); properties.setProperty("测试1", "111"); // 要用字符流,因为字节流不能输出中文 properties.store(new FileWriter("f:\\test3.txt"),"");文件:

读取:
Properties properties = new Properties();properties.load(new FileReader("f:\\test3.txt"));properties.forEach((k,v)->{ System.out.println(k + ": " + v);});对前面的基本流的增强。分为:
- 子节缓冲流
- 字符缓冲流 一次I/O从代码经过JVM到OS再到文件,步骤很多。一次操作几个子节/字符和一次操作多个子节都要经历那道流程。使用缓冲流,在创建对象时,会创建一个数组作为缓冲区。通过缓冲区读写,减少IO次数提高读写的效率。
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream("f:\\test.txt"));bufferedOutputStream.write("测试buffer".getBytes());bufferedOutputStream.close();与输出流用法差不多,使用BufferedReader。常用方法里多个readLine方法,当读取不到下一行时会返回null。
BufferedReader bufferedReader = new BufferedReader(new FileReader("f:\\test.txt"));bufferedReader.read();String line;while ((line = bufferedReader.readLine()) != null){ System.out.println(line);}给流指定编码方式。输出:
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream("f:\\test2.txt"), "utf-8");outputStreamWriter.write("测试");outputStreamWriter.close();输入:
InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream("f:\\test3.txt"), StandardCharsets.UTF_8);int len = 0;byte[] cs = null;while ((len = inputStreamReader.read()) != -1){ System.out.printf(String.valueOf((char)len));}inputStreamReader.close();要实现序列化和反序列化的类必须实现Serializabel接口。使用static修饰的属性不能被序列化,如果不想属性成静态可以使用transient。transient可以使属性不被序列化并且不加到静态区。
把对象以流的方式,写入到文件中保存,也叫对象的序列化。
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("f:\\test2.txt"));objectOutputStream.writeObject(new Test("test",11));objectOutputStream.close();把文件中保存的对象,以流的方式读取出来,就是对象的反序列化。如果序列化对象后class文件改了反序列化会失败并抛出InvalidaClassException异常。
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("f:\\person.txt"));Object o = objectInputStream.readObject();objectInputStream.close();System.out.println(o);只负责数据的输出,不负责读取。不会抛出IOException。
PrintStream printStream = new PrintStream("f:\\te.txt");printStream.write(97); // a,使用print方法可以原样输出printStream.close();
// 系统的输出位置可以用setOut更改,这个方法里要传打印流System.out.println("控制台输出");PrintStream printStream = new PrintStream("f:\\te.txt");System.setOut(printStream);System.out.println("输出到打印流的目的地");