文件内容相关的操作
文件内容相关的操作,就是对文件内容进行读写操!
我们也是通过java中的API进行学习!
我们java提供了两种对文件操作读取的方案!
字符流: 以字符为单位进行读取!
文件流: 以字节为单位进行读取!
这里的字节流和字符流就对应了我们的二进制文件和字符文件的读取
什么是流呢?
就好比水流,我们将文件的读取抽象成了水流!
输入流: 就好比你在喝水,文件读取的过程!
输出流:就好比你在输出知识,文件删除的过程!
我们通过这个表格就可以对字符流和字节流的读取进行区分!
我们会详细学习这些读取类!
字节流
字节流:就是以字节为单位,一次读写一个或多个字节!
读操作
如果我们要对一个文件进行读操作,都要进行那些步骤呢?
打开文件
进行读操作
关闭文件
我们通过下面案例对字节流读取进行学习!
//字节流读操作! import java.io.*; public class File2 { public static void main(String[] args) throws IOException { //输入操作,也就是读文件(学习读书过程就是输入) File file = new File("./hello.txt"); //输入流,打开文件! InputStream inputStream = new FileInputStream(file); byte[] result = new byte[1024]; //byte数组用来存放读取结果 while (true){ int len = inputStream.read(result);//保存了有效字节数! if(len==-1){//读取完成! break; } for (int i = 0; i System.out.print((char)result[i]); } } //关闭文件! inputStream.close(); } }
读取结果:
FileInputStream用于读取诸如图像数据的原始字节流!
构造方法:
我们这里的字节流读操作,用到了read方法!
下面3个read方法都是对输入流进行读操作!
int read() 从该输入流读取一个字节的数据。
无参方法read(),默认读取一个字节,返回值是一个整型int!
为啥不是返回一个byte型呢?
我们知道byte范围是-128~127
而我们规定当返回值为-1就表示读取到文件末尾!
如果这样就冲突了!
所以这里的返回值是int 一个字节的范围是 0~255
int read(byte[] b)
从该输入流读取最多 b.length个字节的数据为字节数组。
我们通过byte数组,去接收读取的结果!
而这里的返回值是读取到的有效字节个数!
返回-1就是读取结束!
int read(byte[] b, int off, int len)
从该输入流读取最多 len`字节的数据为字节数组。
和上面的读取操作类似!
这里的b字节数组存放读取内容时,是从off数组下标开始,一次最多可以读取len长度的字节!
而返回值是读取到有效字节数!
输出流写操作
写文件也是类似的步骤!
打开文件
进行写操作
关闭文件
我们先看一个案例:
//字节流写操作 public static void main(String[] args) throws IOException { //输出操作,也就是写文件(学习做题,写博客过程就是输出) File file = new File("./4_22.txt"); //打开文件! OutputStream outputStream = new FileOutputStream(file); //我们将string字符串写入 file文件! String string = "hello world!"; //我们要通过字节方式进行写操作! outputStream.write(string.getBytes()); System.out.println("写入成功!"); //关闭流文件! outputStream.close(); }
FileOutputStream用于写入诸如图像数据的原始字节流。 对于写入字符流,请考虑使用FileWriter 。
我们输出流写操作,主要通过write 方法进行!
void write(byte[] b)
将 b.length个字节从指定的字节数组写入此文件输出流。
void write(byte[] b, int off, int len)
将 len字节从位于偏移量 off的指定字节数组写入此文件输出流。
void write(int b)
将指定的字节写入此文件输出流。
这里的write和read类似!
这里是将b数组里的内容写到file文件!
注意:
这里每次打开文件进行写操作,都会将文件内容置空,再进行写操作!如果并不存在此文件,就会创建改文件!
如果我们要从文件末尾开始写操作呢?
//追加写入操作! public static void main(String[] args) throws IOException { //输出操作,也就是写文件(学习做题,写博客过程就是输出) File file = new File("./4_22.txt"); //打开文件! //true可追加!默认不可追加! OutputStream outputStream = new FileOutputStream(file,true); //我们将string字符串写入 file文件! String string = "hello world!"; //我们要通过字节方式进行写操作! outputStream.write(string.getBytes()); System.out.println("追加写入成功!"); //关闭流文件! outputStream.close(); }
我们需要在创建输出流对象时通过构造方法传参设置是否可追加!
字符流
字符流:就是以字符为单位,一次读取一个或多个字符!
字符流读操作:
//字符流读操作! import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.Reader; public class File3 { public static void main(String[] args){ Reader reader = null; try { //打开文件! reader = new FileReader("./hello.txt"); while (true){ //一次读取一个字符! int x = reader.read(); if(x==-1){//读取结束! break; } //输出该字符! System.out.print((char)x); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } //关闭文件! try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } }
我们可以看到上面的代码比较繁琐,因为要处理好多异常,还有关闭文件操作!
我们可以简化一下代码,将文件流在try语句块创建,语句块结束就会自动关闭资源!
//优化后的代码! public static void main(String[] args){ ///try() 中语句块结束自动关闭资源! try (Reader reader = new FileReader("./hello.txt")){ //打开文件! while (true){ //一次读取一个字符! int x = reader.read(); if(x==-1){//读取结束! break; } //输出该字符! System.out.print((char)x); } } catch (IOException e) { e.printStackTrace(); } }
注意:
只要实现了Closeable这个接口的类都可以进行这样的操作!
而我们的文件操作流对象实现了这个接口!
字符流的读取和字节流的读取大同小异!
int read()
读一个字符
int read(char[] cbuf)
将字符读入数组。
abstract int read(char[] cbuf, int off, int len)
将字符读入数组的一部分。
int read(CharBuffer target)
尝试将字符读入指定的字符缓冲区。
字符流写操作:
//字符流写操作! public static void main(String[] args) { //打开文件! try(Writer writer = new FileWriter("./4_22.txt",true)){ String string = "加油!"; writer.write(string); System.out.println("追加写入成功!"); } catch (IOException e) { e.printStackTrace(); } }
常用方法:
Writer append(char c)
将指定的字符附加到此作者。
Writer append(CharSequence csq)
将指定的字符序列附加到此作者。
Writer append(CharSequence csq, int start, int end)
将指定字符序列的子序列附加到此作者。
abstract void close()
关闭流,先刷新。
abstract void flush()
刷新流。
void write(char[] cbuf)
写入一个字符数组。
abstract void write(char[] cbuf, int off, int len)
写入字符数组的一部分。
void write(int c)
写一个字符
void write(String str)
写一个字符串
void write(String str, int off, int len)
写一个字符串的一部分。
上述方法就可以对字符流进行写操作了!
文件操作案例
我们通过下面3个案例进一步巩固学习!
问题一:
扫描指定目录,并找到名称中包含指定字符的所有普通文件(不包含目录),并且后续询问用户是否要删除该文件
//实例一 import java.io.File; import java.io.IOException; import java.util.Scanner; public class File4 { public static void main(String[] args) throws IOException { // 扫描指定目录,并找到名称中包含指定字符的所有普通文件(不包含目录), // 并且后续询问用户是否要删除该文件 Scanner scanner = new Scanner(System.in); //获取要扫描的目录文件! System.out.print("目录文件->"); String dirctoryString = scanner.next(); File dirctoryFile = new File(dirctoryString); //获取要删除的文件 System.out.printf("要删除的文件->"); String fileString = scanner.next(); //扫描文件! scanFile(dirctoryFile,fileString); } private static void scanFile(File dirctoryFile,String fileString) throws IOException { //将该目录下的文件列出! File[] files = dirctoryFile.listFiles(); for (File file:files) { System.out.println(file.getCanonicalFile()); if(file.isDirectory()){ //目录文件继续遍历! scanFile(file,fileString); }else { //文件判断是否要删除! if(file.getName().contains(fileString)){ //进行删除! file.delete(); } } } } }
我们可以找到test文件,然后进行了删除操作!
问题二:
进行普通文件的复制
//实例二: import java.io.*; import java.util.Scanner; public class File5 { public static void main(String[] args) throws IOException { //进行文件复制操作! Scanner scanner = new Scanner(System.in); //获取要复制的源文件! System.out.print("源文件->"); String srcString = scanner.next(); File srcFile = new File(srcString); //获取源文件目录: String parentString = srcFile.getParent(); System.out.println("目录文件:"+parentString); //目录文件 File parentFile = new File(parentString); //获取目标文件 System.out.printf("目标文件->"); String desString = scanner.next(); File desFile = new File(desString); //扫描文件! scanner(parentFile,srcFile,desFile); } private static void scanner(File parentFile,File srcFile, File desFile) { File[] files = parentFile.listFiles(); for (File file:files) { System.out.println(file.getName()); if(file.isDirectory()) {//目录文件继续遍历 scanner(file, srcFile,desFile); } if(file.getName().equals(desFile.getName())){ //找到了目标文件! //进行复制操作! copyfile(srcFile,desFile); return; } } } private static void copyfile(File srcFile, File desFile) { try(Reader reader = new FileReader(srcFile)){//读src文件! //存放读取结果 char[] chars = new char[1024]; while (true){ int len = reader.read(chars); if(len==-1){//读取结束! break; } //写入到目标文件! try(Writer writer = new FileWriter(desFile,true)){ String string = new String(chars,0,len); System.out.println("复制内容:"+string); writer.write(string); } System.out.println("复制成功!"); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
源文件:
目标文件:
注意这里的目标文件要写绝对或相对路径!
问题三:
扫描指定目录,并找到名称或者内容中包含指定字符的所有普通文件(不包含目录)
注意 :我们现在的方案性能较差,所以尽量不要在太复杂的目录下或者大文件下实验!
//实例三 import java.io.*; import java.util.Scanner; public class File6 { public static void main(String[] args) throws IOException { // 扫描指定目录,并找到名称中包含指定字符或者内容的所有普通文件(不包含目录), Scanner scanner = new Scanner(System.in); //获取要扫描的目录文件! System.out.print("目录文件->"); String dirctoryString = scanner.next(); File dirctoryFile = new File(dirctoryString); //获取要删除的关键字 System.out.printf("要删除的关键字->"); String fileString = scanner.next(); //扫描文件! scanFile(dirctoryFile,fileString); } private static void scanFile(File dirctoryFile,String fileString) throws IOException { //将该目录下的文件列出! File[] files = dirctoryFile.listFiles(); for (File file:files) { System.out.println(file.getCanonicalFile()); if(file.isDirectory()){ //目录文件继续遍历! scanFile(file,fileString); }else { //文件判断是否要删除! if(file.getName().contains(fileString)){ //文件名称有该关键字进行删除! file.delete(); System.out.println(file.getName()+" 删除成功!"); }else { //查看文件内容是否含该关键字! if(isdelete(file,fileString)){ file.delete(); System.out.println(file.getName()+" 删除成功!"); } } } } } private static boolean isdelete(File file, String fileString) { try(Reader reader = new FileReader(file)){ char[] chars = new char[1024]; while (true){ int len = reader.read(chars); if(len==-1){ break; } String str = new String(chars,0,len); System.out.println(file.getName()+" 内容:"+str); if (str.contains(fileString)) { //如果内容中包含了该关键字! return true; } } }catch (IOException e) { e.printStackTrace(); } return false; } }