JAVA基础--IO输入输出(File使用)17
一、 File中的方法
1. 列举方法
1 /* 2 * 获取指定目录以及子目录下的所有文件和文件夹 3 */ 4 public class ListFilesDemo { 5 public static void main(String[] args) { 6 7 File dir = new File("d:/test"); 8 getFiles(dir); 9 } 10 //获取指定目录下的文件或文件夹 11 public static void getFiles(File dir) { 12 13 //判断dir所表示的文件或文件夹是否存在 14 if( !dir.exists() ){ 15 throw new RuntimeException("传递的文件或文件夹不存在"); 16 } 17 //判断dir是否是目录 18 if( !dir.isDirectory() ){ 19 throw new RuntimeException("传递的文件对象表示的不是一个有效的目录"); 20 } 21 22 //获取指定目录 下的文件和文件夹 23 File[] files = dir.listFiles(); 24 //判断当前指定的目录Java是否有权限访问,如果没有权限会得到null 25 if( files != null ){ 26 //遍历文件数组 27 for( File file : files ){ 28 //取出数组中的某个File对象 29 if( file.isDirectory() ){ 30 //判断 成立说明当前数组中保存的某个文件对象一定是目录(文件夹) 31 getFiles(file); 32 }else{ 33 //判断不成立,说明当前从数组中取出的文件对象一定是文件 34 System.out.println("正在删除的文件是:"+file.getName()+",删除的结果是:"+file.delete()); 35 } 36 //程序如果执行到这里,说明一定将某个目录中的文件删除完成,紧接着删除这个目录 37 System.out.println("被删除的文件夹是:"+file.getName()+",删除的结果是:"+file.delete()); 38 } 39 } 40 } 41 }
2. 递归技术
上述的遍历多级目录,使用到的方法在调用自己。这个技术被称为方法的递归调用。
递归:方法调用方法。
直接递归:方法在自己的方法体中又调用自己。
间接递归:A方法调用B方法,B方法调用C ...... 最后一个方法调用A方法。
1 /* 2 * 需求:计算1~5的和值,禁止使用循环。 3 */ 4 public class DiGui { 5 public static void main(String[] args) { 6 int num = 5; 7 int sum = getSum( num ); 8 System.out.println(sum); 9 } 10 11 public static int getSum(int num) { 12 13 if( num > 1 ){ 14 return num + getSum( num -1 ); 15 } 16 return 1; 17 } 18 }
递归程序注意的细节:
1、递归调用一定要在程序添加判断,保证递归可以停止。否则就是无限递归调用。会导致栈内存溢出。
2、如果递归调用有判断,但是判断的语句还没有结束就可能导致栈溢出。因此递归的次数一定不要太多。
3. 文件队列
1 /* 2 * 使用文件队列获取指定目录以及子目录下的文件和文件夹 3 */ 4 public class ListFilesDemo2 { 5 public static void main(String[] args) { 6 File dir = new File("d:/test"); 7 getFiles(dir); 8 } 9 //获取指定目录以及子目录下的文件和文件夹 10 public static void getFiles(File dir) { 11 //定义集合容器 12 LinkedList<File> list = new LinkedList<File>(); 13 //将传递进来的文件夹先保存到集合容器中 14 list.addLast(dir); 15 //遍历集合容器 16 while( list.size() > 0 ){ 17 //只要循环成立,说明集合容器中就会有文件夹存在 18 File file = list.removeFirst(); 19 //获取从容器中取出的这个文件夹下的所有文件和文件夹 20 File[] files = file.listFiles(); 21 //判断当前的目录Java是否有权限.判断files是否为null 22 if( files != null ){ 23 for( File f : files ){ 24 //遍历当前从容器中取出的这个文件夹下的每个文件或文件夹对象 25 if( f.isDirectory() ){ 26 //判断成立,说明当前得到的子文件对象一定是文件夹,添加到集合中 27 list.addLast(f); 28 }else{ 29 ///当前的f一定是文件 30 System.out.println(f); 31 } 32 } 33 } 34 } 35 } 36 }
二、 文件过滤器
1. 文件过滤器介绍
我们在使用list或者listFiles方法列出某个目录下的文件或者文件夹的时候,是将所有的全部列出,有时我们并不需要某个目录下的所有文件或文件夹,而是希望列出符合条件的文件或文件夹。
可以在使用list或listFiles方法时,给方法传递一个符合用户需求的过滤对象,这个对象可以帮助list和listFiles方法在列出目录下文件或文件夹的时候,根据传递的过滤对象将符合条件的文件和文件夹列出,不符合的就会被过滤掉。
在Java中提供了2个负责过滤的过滤器:
FilenameFilter:文件名过滤器:是通过文件或文件夹的名称过滤
FileFilter:文件过滤器:通过文件或文件夹对象过滤器
2. FilenameFilter接口
1 /* 2 * 自己定义文件名过滤器 3 */ 4 public class MyFilenameFilter implements FilenameFilter{ 5 //定义成员变量,记录传递的过滤的名称 6 private String suffix; 7 //定义构造方法,让使用者在创建过滤器对象的时候指定需要过滤的条件 8 public MyFilenameFilter(String suffix){ 9 this.suffix = suffix; 10 } 11 /* 12 * 解释FilenameFilter中的accept方法上的两个参数 13 * File dir : 是当前需要列举的那个目录 14 * String name:是当前指定的目录下的文件或文件夹的名称 15 */ 16 public boolean accept(File dir, String name) { 17 //System.out.println(dir + "....." + name); 18 return name.endsWith(this.suffix); 19 } 20 21 } 22 23 /* 24 * 演示FilenameFilter过滤器的使用 25 */ 26 public class FilenameFilterDemo { 27 public static void main(String[] args) { 28 29 //创建文件对象 30 File dir = new File("d:/test/day07_code"); 31 /* 32 * 当我们在程序中使用list方法的时候,list方法会先列出当前目录下的所有文件和文件夹 33 * 然后将这些文件和文件夹传递给指定的过滤器对象, 34 * 如果过滤器中的accept方法返回的true,就认为当前这个文件或文件夹是需要保留的 35 * 如果过滤器中的accept方法返回的false,就认为当前这个文件或文件夹是不需要的 36 */ 37 String[] list = dir.list(new MyFilenameFilter(".java")); 38 39 //遍历 40 for (String s : list) { 41 System.out.println(s); 42 } 43 } 44 }
3. FileFilter接口
1 /* 2 * 自定义FileFilter过滤器对象 3 */ 4 public class MyFileFilter implements FileFilter{ 5 private String suffix; 6 public MyFileFilter(String suffix){ 7 this.suffix = suffix; 8 } 9 /* 10 * 解释FileFilter中的accept方法上接收的参数 11 * File pathname : 表示的当前目录下的那个文件或文件夹对象 12 */ 13 public boolean accept(File pathname) { 14 //System.out.println(pathname.isDirectory() +".."+pathname.getName()+"..."+pathname.isFile()); 15 //需要将扩展名为 .mp3的文件保留下来 16 return pathname.isFile() && pathname.getName().endsWith(this.suffix); 17 } 18 19 } 20 21 /* 22 * 演示FileFilter的使用 23 */ 24 public class FileFilterDemo { 25 public static void main(String[] args) { 26 27 //创建File对象 28 File dir = new File("d:/test"); 29 30 /* 31 * 获取指定目录下的文件或文件夹 32 * 33 * 当我们调用File类中的listFiles方法,并传递以了一个FileFilter过滤器对象 34 * listFiles方法也是先将指定目录下的所有文件和文件夹获取到, 35 * 然后将这些文件或文件夹对象逐一传递给FileFilter中的accept方法。 36 * 37 */ 38 File[] files = dir.listFiles(new MyFileFilter(".java")); 39 40 for ( File file : files){ 41 System.out.println(file); 42 } 43 } 44 }
4. 过滤器练习
需求:获取指定目录以及子目录下的文件(扩展名为.java).
1 /* 2 * 需求:获取指定目录以及子目录下的文件(扩展名为.java) 3 * 4 */ 5 public class FilterTest { 6 public static void main(String[] args) { 7 8 File dir = new File("d:/test"); 9 getFiles(dir); 10 } 11 12 public static void getFiles(File dir) { 13 14 //列出指定目录下的文件和文件夹 15 File[] files = dir.listFiles( new FileFilter(){ 16 17 /* 18 * 书写过滤的条件: 19 * 如果是只过滤当前的目录,那么在书写过滤器条件的时候, 20 * 只需要判断是否是文件和文件的扩展名。 21 * 22 * 如果需要多级目录文件获取,这时在书写过滤器的时候, 23 * 判断的条件中需要保留文件夹,和文件(扩展名必须是符合条件) 24 */ 25 public boolean accept(File pathname) { 26 return (pathname.isDirectory()) || 27 (pathname.isFile() && pathname.getName().endsWith(".txt")); 28 } 29 30 } ); 31 //判断 32 if( files != null ){ 33 //遍历 34 for (File file : files) { 35 if( file.isDirectory() ){ 36 getFiles(file); 37 }else{ 38 System.out.println(file); 39 } 40 } 41 } 42 } 43 }
三、 IO流技术
1. 流的分类
File类:它主要是操作文件和文件夹,并不能读写文件中的数据。
我们如果需要操作保存在文件中的数据,这时只能使用Java中提供的IO流对象。
IO:Input Output。
IO流:它是使用Java中提供的众多的对象,和文件中的数据进行交互。
IO流如果按照操作数据的方向:
输入流:Input,读取数据。
输出流:Output,写出数据。
IO流如果按照操作的数据类型:
字节流:它全部是以字节形式操作(读写)的数据
字符流:全部是以字符的形式操作(读写)数据
上课以数据类型分类:现讲字节流,再讲字符流。
字节流和字符流它们对文件中的数据操作规律是一致的。主要会一种,其他的都可以照着模版代码进行抄写。
2. 字节流介绍
任何数据在电子设备中存储的方式都是二进制形式(字节)。我们就可以直接以字节方式读取文件中的数据,或者以字节的方式给文件中写数据。
字节流:
字节输入流:它是负责以字节的方式从文件中读取数据。在程序中我们会获取到读取的字节数据。
字节输出流:它是负责以字节的方式将程序(内存)中的数据写到文件中。
3. 字节输出流
OutputStream:它是所有字节输出流的超类(基类、根类)。它中肯定定义了应该如何将字节写到底层文件中的最基本(共性)的方法。
使用Java程序操作Java以外的其他数据(数据库,硬盘,网络,其他语言开发的程序),首先需要让我们的Java程序和其他的资源平台获取连接(关联),在这个连接中进行数据的交互。交互结束之后一定要记住将彼此之间的连接断开。因此我们使用Java中的IO流技术操作其他设备上的数据,这时操作完一定要记得调用close方法。
write(byte[] b) 将指定的字节数组中的全部数据写到底层指定的设备中。
write(byte[] b , int off , int len) 将指定的字节数组中的数据从off位置开始,共计写出len个。
write(int b) 将int类型数据中的最低位一个字节写出。
4. 文件字节输出流
FileOutputStream:它是专门负责将字节数据写到文件中。
1 /* 2 * 演示字节输出流 3 * 使用输出流,往出写数据的时候,如果指定的文件不存在, 4 * 这时输出流会自动的在指定的目录下创建这个文件,并将数据写到文件中。 5 * 6 * 使用输出流的时候,文件不存在会创建,如果文件存在,会覆盖。原来文件中的数据全部丢失。 7 */ 8 public class FileOutputStreamDemo { 9 public static void main(String[] args)throws IOException { 10 method3(); 11 } 12 // write(byte b) 13 public static void method3() throws IOException { 14 //创建负责写字节数据的流对象 15 FileOutputStream fos = new FileOutputStream("d:/aa.txt"); 16 /* 17 * OutputSteam它写出的是字节数据,字节数据的范围是-128到127之间。 18 * 其中提供的write(int b) 它本质只能写一个字节,但是接收的int类型的数据 19 * int类型的数据在内存中共计占用4个字节,write方法它其实只能将4个字节中 20 * 最低一位上的那个字节数据写到文件中。 21 * 22 * 97 : 0000 0000 0000 0000 0000 0000 0110 0001 23 * 353:0000 0000 0000 0000 0000 0001 0110 0001 24 * 25 */ 26 fos.write(97); 27 fos.write(353); 28 29 fos.close(); 30 } 31 //write(byte[] b , int off , int len) 32 public static void method2() throws IOException { 33 34 //创建负责写字节数据的流对象 35 FileOutputStream fos = new FileOutputStream("d:/aa.txt"); 36 37 //创建字节数组 38 byte[] b = {65,66,67,68,69}; 39 //调用写的方法写数据 40 fos.write(b , 1 , 2); 41 42 //关闭流对象 43 fos.close(); 44 45 } 46 //演示 write(byte[] b); 47 public static void method() throws IOException { 48 49 //创建负责写字节数据的流对象 50 FileOutputStream fos = new FileOutputStream("d:/aa.txt"); 51 52 //创建字节数组 53 byte[] b = {65,66,67,68,69}; 54 //调用写的方法写数据 55 fos.write(b); 56 57 //关闭流对象 58 fos.close(); 59 } 60 }
5. 追加数据和换行
1 /* 2 * 文件写字符串数据,并换行 3 */ 4 public static void method5() throws IOException { 5 6 FileOutputStream fos = new FileOutputStream("d:/aa.txt",true); 7 8 //获取操作系统支持的换行符 9 String line_separator = System.getProperty("line.separator");// \r\n 10 String s = "Java基础正在学习IO技术"+line_separator; 11 12 fos.write(s.getBytes()); 13 14 fos.close(); 15 } 16 /* 17 * 在文件的末尾追加数据 18 * FileOutputStream(String name, boolean append) 19 * 如果创建FileOutputStream的时候,在构造方法中指定的boolean值为true 20 * 这时需要关联的文件如果不存在,它会创建, 21 * 如果已经存在,并且其中有数据,会在原来文件的末尾继续追加数据 22 */ 23 public static void method4() throws IOException { 24 25 FileOutputStream fos = new FileOutputStream("d:/aa.txt",true); 26 27 fos.write(101); 28 fos.write(102); 29 fos.write(103); 30 fos.write(104); 31 32 //关流 33 fos.close(); 34 }
6. 输出流练习
1 /* 2 * 需求:将指定目录和子目录下的指定扩展名(.java)的文件所在路径写到一个文件中,形成一个文件清单。 3 * 分析: 4 * 获取符合条件的文件,然后将其路径得到。再使用输出流写到文件中即可 5 */ 6 public class FileOutputStreamTest { 7 public static void main(String[] args) throws IOException { 8 9 File dir = new File("d:/test"); 10 FileOutputStream fos = new FileOutputStream("d:/文件清单.txt"); 11 getListFile(dir,fos); 12 fos.close(); 13 } 14 //获取指定目录下的文件清单 15 public static void getListFile(File dir ,FileOutputStream fos) throws IOException { 16 17 File[] files = dir.listFiles( new FileFilter(){ 18 public boolean accept(File pathname) { 19 return (pathname.isDirectory()) || 20 (pathname.isFile() && pathname.getName().endsWith(".avi")); 21 } 22 } ); 23 //判断 24 if( files != null ){ 25 for (File file : files) { 26 if( file.isDirectory() ){ 27 getListFile(file,fos); 28 }else{ 29 //一定是文件 30 System.out.println(file); 31 String path = file.getAbsolutePath() + System.getProperty("line.separator"); 32 fos.write(path.getBytes()); 33 } 34 } 35 } 36 } 37 }
7. 字节输入流
InputStream:它是字节输入流的超类(基类、根类),它中定义的是字节输入流如何读取字节数据的方法。
所有输入流:它们都有read方法,负责从底层读取数据的。如果读取到文件末尾统一返回的都是-1。
int read() 这个方法调用一次,就会从底层文件中获取一个字节数据,并返回这个字节数据。
int read(byte[] b) 调用一次,会从底层文件中读取若干个字节数据,并将这些字节数据存储在byte数组中,每次都是从数组的零位置开始往后存储。返回的int值表示的是给byte数组中真正存储的字节个数。
int read(byte[]b , int off , int len) 调用一次,从底层读取若干字节数据,将数据存储在b数组中,但是是从off位置开始存储,共计只能存储len个。返回的int值表示是的是给数组中存储的字节个数。
8. 文件字节输入流
FileInputStream:它是专门负责从文件中读取字节数据。
1 /* 2 * 演示字节输入流 3 */ 4 public class FileInputStreamDemo { 5 6 public static void main(String[] args) throws IOException { 7 method3(); 8 } 9 //一次读取多个字节数据 10 public static void method3() throws IOException { 11 //创建输入流对象和需要被读取的文件进行关联 12 FileInputStream fis = new FileInputStream("d:/aa.txt"); 13 /* 14 * 定义数组充当临时的容器,存储每次从文件中读取到的若干个字节数据。 15 * 一般定义的数组如果是存储读取到的数据,这个数组一般会是1024的整数倍 16 */ 17 byte[] buf = new byte[1024]; 18 //定义变量,记录每次给数组中存储的字节个数 19 int len = 0; 20 //使用循环读取数据 21 while( ( len = fis.read( buf ) ) != -1 ){ 22 /* 23 for( int i = 0 ; i < len ; i++ ){ 24 System.out.print(buf[i]+" "); 25 } 26 */ 27 System.out.println(new String( buf , 0 , len )); 28 } 29 30 //关流 31 fis.close(); 32 } 33 //使用循环读取文件中的数据 ,一次读取一个 34 public static void method2() throws IOException { 35 36 //创建输入流对象和需要被读取的文件进行关联 37 FileInputStream fis = new FileInputStream("d:/aa.txt"); 38 //定义变量记录每次读取到的字节数据 39 int ch = 0; 40 //使用while循环读取数据 41 while( ( ch = fis.read( ) ) != -1 ){ 42 System.out.println(ch); 43 } 44 //关流 45 fis.close(); 46 } 47 //演示 read() 48 public static void method() throws IOException { 49 50 //创建输入流对象和需要被读取的文件进行关联 51 FileInputStream fis = new FileInputStream("d:/aa.txt"); 52 53 //读取字节数据 54 System.out.println(fis.read()); 55 System.out.println(fis.read()); 56 System.out.println(fis.read()); 57 System.out.println(fis.read()); 58 59 //关流 60 fis.close(); 61 } 62 }
9. 复制文件练习
1 /* 2 * 需求:复制指定的文件到指定的目录下 3 * 4 */ 5 public class CopyFileTests { 6 public static void main(String[] args) throws IOException{ 7 copyFile2(); 8 } 9 //使用数组复制 10 public static void copyFile2() throws IOException{ 11 12 //定义输入流读取文件 13 FileInputStream fis = new FileInputStream("d:/1.avi"); 14 //定义输出流写文件 15 FileOutputStream fos = new FileOutputStream("c:/1.avi"); 16 17 //在开始复制文件之前获取系统的时间 18 long start = System.currentTimeMillis(); 19 20 //保存每次读取的字节个数 21 int len = 0; 22 /* 23 * 定义字节数组保存数据 24 * 8二进制 = 1字节 25 * 8bit = 1Byte 26 * 1024B = 1KB 27 * 1024KB = 1MB 28 * 1024MB = 1GB 29 * 1024GB = 1TB 30 * 1024TB = 1PB 31 */ 32 byte[] buf = new byte[8192]; 33 //使用循环读取数据 34 while( ( len = fis.read( buf ) ) != -1 ){ 35 //使用输出流写到文件中 36 fos.write( buf, 0 , len ); 37 } 38 39 //循环结束,数据已经复制完成 40 long end = System.currentTimeMillis(); 41 System.out.println("复制文件所用时间:"+(end - start)); 42 43 //关流 44 fis.close(); 45 fos.close(); 46 } 47 //演示 一次读取一个字节的方式复制 48 public static void copyFile() throws IOException{ 49 50 //定义输入流读取文件 51 FileInputStream fis = new FileInputStream("d:/1.mp3"); 52 //定义输出流写文件 53 FileOutputStream fos = new FileOutputStream("c:/1.mp3"); 54 55 //在开始复制文件之前获取系统的时间 56 long start = System.currentTimeMillis(); 57 58 //保存每次读取的字节数据 59 int ch = 0; 60 //使用循环读取数据 61 while( ( ch = fis.read() ) != -1 ){ 62 //使用输出流写到文件中 63 fos.write(ch); 64 } 65 66 //循环结束,数据已经复制完成 67 long end = System.currentTimeMillis(); 68 System.out.println("复制文件所用时间:"+(end - start)); 69 70 //关流 71 fis.close(); 72 fos.close(); 73 } 74 }