JavaIO流中的拷贝

  JavaIO流中对数据的操作尤为重要,掌握了基本的拷贝操作,才能将各种数据源的操作联系起来。

  先来看看对文件夹的拷贝吧:

 1 /**
 2  * 利用递归实现文件夹的拷贝操作
 3  * 分析:判断
 4  *     是文件:调用拷贝文件的方法fileCopy(...)
 5  *     是文件夹:创建文件夹,并使用递归实现子文件夹/子文件的判断及操作
 6  * @param src:要拷贝的文件夹源头
 7  * @param dest:要拷贝到的文件夹源头
 8  */
 9 public static void dirCopy(File src,File dest) {
10     if(src.isFile()) { //是文件
11         fileCopy(src, dest);
12     }else { //是文件夹
13         dest.mkdirs();
14         for(File subSrc:src.listFiles()) { //遍历子文件夹/子文件
15             dirCopy(subSrc, new File(dest,subSrc.getName()));
16         }
17     }
18 }

  对文件的拷贝,我们可以这样写:

 1 /**
 2  * 实现文件的拷贝
 3  *     输入流读取的同时输出流进行写出
 4  * @param src:要拷贝的文件源头
 5  * @param dest:要拷贝到的文件源头
 6  */
 7 public static void fileCopy(File src,File dest) {
 8     //1.创建源
 9     //2.选择流
10     InputStream is = null;
11     OutputStream os = null;
12     try {
13         is = new FileInputStream(src);
14         os = new FileOutputStream(dest);
15         //3.操作:分段读取并写出
16         int len; //接收长度
17         byte[] flush = new byte[1024]; //缓冲容器,一次读写1k
18         while((len=is.read(flush))!=-1) {
19             os.write(flush, 0, len);
20         }
21         os.flush(); //写完手动刷新,避免数据在缓冲容器中(当然当流关闭时会自动刷新)
22     }catch(FileNotFoundException e) {
23         e.printStackTrace();
24     }catch(IOException e) {
25         e.printStackTrace();
26     }finally {
27         //4.关闭流,分别关闭,先打开的后关闭
28         try {
29             if(os!=null) {    //判断是否为空,避免空指针异常
30                 os.close();
31             }
32         }catch(IOException e) {
33             e.printStackTrace();
34         }
35         try {
36             if(is!=null) { //判断是否为空,避免空指针异常
37                 is.close();
38             }
39         }catch(IOException e) {
40             e.printStackTrace();
41         }
42     }
43 }

  以上代码只能实现对文件的拷贝操作,当然适合于拷贝任何格式的数据文件,包括视频、音频、图片等等。但是如果我想将一张图片拷贝到字节数组中呢(这里的字节数组相当于内存),也就是说从文件到字节数组,或着是从字节数组到文件。那么以上代码就具有局限性了,也不易于扩展,来看以下代码:

 1 /**
 2  * 对接流
 3  * @param is:输入流
 4  * @param os:输出流
 5  */
 6 public static void copy(InputStream is,OutputStream os) {
 7     //1.创建源
 8     //2.选择流
 9     try {
10         //3.操作
11         byte[] flush = new byte[1024]; //缓冲容器
12         int len; //接收长度
13         while((len=is.read(flush))!=-1) {
14             os.write(flush, 0, len);
15         }
16         os.flush();
17     }catch(FileNotFoundException e) {
18         e.printStackTrace();
19     }catch(IOException e) {
20         e.printStackTrace();
21     }finally {
22         try {
23             if(os!=null) {
24                 os.close();
25             }
26         }catch(IOException e) {
27             e.printStackTrace();
28         }
29         try {
30             if(is!=null) {
31                 is.close();
32             }
33         }catch(IOException e) {
34             e.printStackTrace();
35         }
36     }
37 }

  嗯,这样就可以实现以上要求了,但是我们发现:关闭资源的操作一直在,而且都一样,我们可以封装一下,这样在finally中就可以直接调用了。

 1 /**
 2  * 关闭的方法
 3  * @param is:输入流
 4  * @param os:输出流
 5  */
 6 public static void close(InputStream is,OutputStream os) {
 7     try {
 8         if(os!=null) {
 9             os.close();
10         }
11     }catch(IOException e) {
12         e.printStackTrace();
13     }
14     try {
15         if(is!=null) {
16             is.close();
17         }
18     }catch(IOException e) {
19         e.printStackTrace();
20     }
21 }

  好了,看看封装的代码,幸亏只有两个流,要是流很多咋办,形参太多,但是我们发现输入流InputStream和输出流OutputStream都实现了同一个接口:Closeable。嗯,这样,我们可以试试JDK1.5的新特性:可变参数。

 1 /**
 2  * 封装的关闭方法
 3  * @param ios:要关闭的流
 4  */
 5 public static void close(Closeable... ios) {
 6     for(Closeable io:ios) {
 7         try {
 8             if(io!=null) {
 9                 io.close();
10             }
11         }catch(IOException e) {
12             e.printStackTrace();
13         }
14     }
15 }

  现在看似完美了,但我还不太满意,有时候,我觉得手动关闭资源太麻烦了。别急,来看看JDK1.7的新特性:try...with...resources(自动关闭资源)。

 1 /**
 2  * JDK1.7之后的新特性 try...with...resources:自动关闭资源
 3  * 文件的拷贝
 4  * @param srcPath:要拷贝的源头
 5  * @param destPath:要拷贝到的目的地
 6  */
 7 public static void copy1(String srcPath,String destPath) {
 8     //1.创建源
 9     File src = new File(srcPath);
10     File dest = new File(destPath);
11     //2.选择流
12     try(InputStream is = new FileInputStream(src);
13         OutputStream os = new FileOutputStream(dest)) {
14         //3.操作
15         byte[] flush = new byte[1024]; //缓冲容器
16         int len; //接收长度
17         while((len=is.read(flush))!=-1) {
18             os.write(flush, 0, len);
19         }
20         os.flush();
21     }catch(FileNotFoundException e) {
22         e.printStackTrace();
23     }catch(IOException e) {
24         e.printStackTrace();
25     }
26 }

  大家发现:try里面写的好繁琐,别急,看看JDK1.9的改进版(不过要求你所要关闭的资源是final或等效于final的变量)。

 1 /**
 2  * JDK1.9之后对 try...with...resources的改进
 3  * 对接流
 4  * @param is:输入流
 5  * @param os:输出流
 6  */
 7 public static void copy2(InputStream is,OutputStream os) {
 8     //1.创建源
 9     //2.选择流
10     try(is;os) {
11         //3.操作
12         byte[] flush = new byte[1024]; //缓冲容器
13         int len; //接收长度
14         while((len=is.read(flush))!=-1) {
15             os.write(flush, 0, len);
16         }
17         os.flush();
18     }catch(FileNotFoundException e) {
19         e.printStackTrace();
20     }catch(IOException e) {
21         e.printStackTrace();
22     }
23 }

  哈哈,看上去是不是简洁很多。对的,随着JDK的新版本发布,越来越多的新技术,也使得代码看起来越简洁,不过对我们的要求也只会越来越高。前段时间JDK12已经出来了,还没用,不过我相信肯定会有好多的新特性,期待,也看好Java,加油。

posted @ 2019-03-25 22:24  吴永吉  阅读(2752)  评论(0编辑  收藏  举报