文件命名,也可以起到文件移动的效果
以上文件系统操作,都是基于File类完成的。
文件流stream-主要原因,操作系统流
文件内容的操作核心步骤,四个
1.打开文件 fopen
2.关闭文件 fclose
3.读文件 fread
4.写文件 fwrite
JavaIO流是庞大的体系,涉及非常多的类,不同的类有不同的特性,使用方法基本类似。
字节流:InputStream,OutputStream ,后续的一些操作字节的类都是衍生自这两个类,以操作字节为单位(二进制文件)
字符流: Reader Write 操作字符为单位(文本文件)
reader.close:让一个进程打开一个文件,是要从系统中一定的资源(占据进程pcb文件描述符中的一个表项)文件描述符是顺序表(长度有限,不可扩容),如果不释放,就会出现“文件资源泄露”这是很严重的问题,一旦一直打开文件,而不去关闭不用的文件,文件描述符就会被占用满(导致服务器宕机)后续无法打开新的文件)->年终奖消失大法
我们平时可以使用try catch finally {close}但是不够优雅
最好使用try with resources
//这个就如同sychronized一样,自动给你关闭文件,但是这块写的不完全,需要写使用资源的操作 try(Reader reader=new FileReader("d:/test.txt"))
read()一次读一个字符<->char(按照Integer来表示,表示两个字符的范围,-1表示已经读取完毕eof了)
可能会有疑问——utf8格式一个字符三个字节,为什么读出字符是两个字节呢
java的char类型是用unicode编码的(一个字符,两个字节),使用完这个方法读取一个字符,java标准库内部会帮我们自动转换!unicode和utf8(一个字符)是不同的。
这个会把读到的内容,填充到参数cbuf是数组中,此处的参数,相当于一个“输出型参数”
char buf[]=new char[1024];
reader.read(buf)//这种写法java中不太常见(c++)使用偏多,通过read,就会把一个本来空的数组,填充上内容
read(char[]cbuf,int off,int len)
多个小文件,都需要读取且需要拼接到一起,就用这个方法,比如三个文件,大小都是100字节
read(cbuf,0,100) read(cbuf,100,100) read(cbuf,200,100)
我们如同下图那样,先读取txt文件,然后在去依次输出这个字符串,读到文件末尾退出
import java.io.*; public class Demo12 { public static void main(String[] args) throws IOException { try(Reader reader=new FileReader("/Users/lcl/untitled7/src/test.txt")){ while(true){ char buf[]=new char[1024]; int n=reader.read(buf); if(n==-1){ System.out.println("读到文件末尾"); break; } for(int i=0;i<n;i++){ System.out.println(buf[i]+","); } //String构造方法内部,默认是utf8(但是你可以让他变成gbk String s=new String(0,n,"gbk"); String s=new String(); System.out.println(s); } } } }
read(byte[]b)->一次读若干字节,填满数组的一部分
Scanner一视同仁,只是把当前读到的字节数据进行转换~(不关心这个数据来自于标准输入,还是来自文件或者网卡)
以前学过的Scanner只是读文本文件的,不适合读二进制文件,在标准库中,还提供了一些具体工具类,辅助更方便的读写二进制文件。
import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.Scanner; public class Demo13 { public static void main(String[] args) throws IOException { try(InputStream inputStream=new FileInputStream("/Users/lcl/untitled7/src/test.txt")){ Scanner scanner=new Scanner(inputStream); //第一段到空格之前的字符串,读取test文件读取数据 String s= scanner.next();; System.out.println(s); String s1= scanner.next();; System.out.println(s1); 第二段空格之前,相当于读取一个词 String s2= scanner.next();; System.out.println(s2); } } }
输出,使用方法和输入十分相似——
关键的操作是write,write之前要打开文件,用完需要关闭文件,输出流对象(无论字节流还是字符流)会打开文件之后,清空文件内容!正如我们之前那么写的i,变成了我喜欢你
但是我们假如想在他的后面去写,而不去自动删除,该怎么做呢,可以追加写,此时就不进行清空操作。OutputStream使用方式完全一样,只不过write方法不能支持“字符串参数”。,只能按照字节或者字节数组写入。
Scanner搭配InputStream可以简化代码效果(可以不像我们之前那么一点一点读)
PrintWriter(sout,点击里面的out,她就是这个类,使用一系列方法printf,println)搭配OutputStream
经典面试题,写个代码递归目录
深度优先-DFS(先中后序,递归)
广度优先-BFS(层序)
import java.io.File; import java.util.Scanner; public class Demo15 { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.println("请输入搜索的根目录"); File rootPath = new File(scanner.next()); System.out.println("请输入删除的关键词"); String word = scanner.next(); if (!rootPath.isDirectory()) { System.out.println("路径不合法"); return; } scanDir(rootPath, word); scanner.close(); } public static void scanDir(File currentDir, String word) { //先列出当前目录包含哪些内容 File[] files = currentDir.listFiles(); if (files == null || files.length == 0) { //空目录/非法目录 return; } for (File f : files) { System.out.println(f.getAbsolutePath()); if (f.isFile()) { //3看当前文件是普通文件,看文件名字,是否包含word,来决定是否删除 dealFile(f, word); } else { //4假如是当前文件是目录文件(文件夹)就再次递归,直到找到文件。 scanDir(f, word); } } } private static void dealFile(File f, String word) { //是根据文本的是名字删除,假如不存在就返回 if (!f.getName().contains(word)) { return; } //打印删除文件的路径 System.out.println("要删除的文件:" + f.getAbsolutePath()); f.delete(); } }
2.进行普通文件的复制,把一个文件复制成另一个文件
在这之前我们先要想一个问题,读文件一次读1024好,还是20480好?
每次read都是访问硬盘,此时把buffer(接受的数组)变大,就能降低访问硬盘次数提高效率,buffer大的前提,空间需要充足
import java.io.*; import java.util.Scanner; public class Demo16 { public static void main(String[] args) throws IOException { System.out.println("请输入复制的文件路径"); Scanner scanner = new Scanner(System.in); String src = scanner.next(); File srcFile = new File(src); if (!srcFile.isFile()) { System.out.println("源文件不存在或者不是一个文件"); return; } System.out.println("请输入复制目标文件路径"); String dest = scanner.next(); File destFile = new File(dest); //不要求目标文件本身存在,但要保证目标文件所在的目录所在。 //假设目标文件写作d:/tmp/cat2.jpg,就需保证d:tmp目录所在 if (!destFile.getParentFile().isDirectory()) { System.out.println("您的路径非法"); return; } //输入流,输出流,按照字节流方式去打开这个文件 try (InputStream inputStream = new FileInputStream(srcFile); OutputStream outputStream = new FileOutputStream(destFile)) { while(true) { byte[] buffer = new byte[1024]; int n = inputStream.read(buffer); System.out.println("n=" + n); if (n == -1) { //读完事了 System.out.println("读到eof,结束"); break; } //从0开始,写n这么长 outputStream.write(buffer, 0, n); } } } }