NIO2.0之copy、delete和move
转自:http://www.importnew.com/15884.html
Java 7引入了NIO.2,NIO.2是继承自NIO框架,并增加了新的功能(例如:处理软链接和硬链接的功能)。这篇帖子包括三个部分,我将使用NIO.2的一些示例,由此向大家演示NIO.2的基本使用方法。
文件拷贝
Q:怎样拷贝一个文件?
A:你可以使用java.nio.file.Files类的public static Path copy(Path source, Path target, CopyOption… options)方法来实现这个功能,该方法可以实现从源文件到目标文件的拷贝。
默认情况下,如果目标文件已经存在或者是一个符号链接,拷贝就会失败。但是,如果源文件和目标文件是同一个文件,这个拷贝的动作就不会执行。
此外还有一些注意的事项:
- 文件的属性的拷贝不是必须的。
- 如果支持符号链接,当源文件是一个符号链接时,拷贝的是最终目标文件的链接。
- 当源文件是一个目录,copy()方法将目标位置生成一个空目录(目录中的元素不会拷贝)。
每个java.nio.file.CopyOption类型的参数传递到copy()方法的可变参数列表后将改变该方法的行为。该参数是一个java.nio.file.StandardCopyOption类型或java.nio.file.LinkOption枚举常量:
- COPY_ATTRIBUTES:尝试将文件的属性拷贝到目标文件。这些属性依赖于平台和文件系统,因此是不确定的。但是,至少来说,如果源文件和目标文件的存储都支持最后修改时间属性的话,该属性是会拷贝到目标文件的。不过,需要注意的时,拷贝文件的时间戳的精度可能会有所丢失。
- NOFOLLOW_LINKS:不一样的符号链接.如果该文件是一个符号链接,拷贝的是符号链接自身而不是其引用的目标文件。它的特殊实现在于是否拷贝文件的属性到新的链接上,换句话说,当拷贝一个符号链接的时候,COPY_ATTRIBUTES可能被忽略。
- REPLACE_EXISTING:当目标文件已经存在时,目标文件将被替换,除非目标文件是一个非空的目录。当目标文件是一个符号链接并且已经存在的话,仅仅符号链接自身被替换而不改变符号链接所引用的文件。
copy() 方法不支持StandardCopyOption的ATOMIC_MOVE选项,在文件拷贝中该选项是一个无意义的。我将在之后关于文件移动的讨论中介绍ATOMIC_MOVE选项。
非原子性拷贝:
拷贝文件是一个非原子性操作。如果抛出java.io.IOException异常,意味着目标文件可能没有拷贝完成或者文件的属性没有从源文件拷贝过来。如果指定为REPLACE_EXISTING模式并且目标文件已经存在,则目标文件已经被替换了。此外,对文件系统已有文件的存在的检查和新文件的创建的检查可能也不是原子的。
除了java.lang.SecurityException,copy()还会抛出以下某一种异常:
- java.nio.file.DirectoryNotEmptyException: REPLACE_EXISTING模式下,因目标文件是一个非空的目录文件而不能被替换。
- java.nio.file.FileAlreadyExistsException:目标文件已经存在,但没有指定REPLACE_EXISTING参数而不能被替换。
- IOException: I/O异常
- java.lang.UnsupportedOperationException: 传入的可变参数CopyOptions是不被支持的。
可选的特定异常:
DirectoryNotEmptyException和FileAlreadyExistsException是可选的异常,它们之所以是可选的是因为这些异常的抛出需要底层操作系统能识别,如果不能识别的话,就抛出IOException来替换。
我已经创建了一个小的应用程序来展示copy()方法的最基本方法。列表1展示了该应用程序的源代码:
列表1:Copy.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
import java.io.IOException; import java.nio.file.DirectoryNotEmptyException; import java.nio.file.Files; import java.nio.file.FileAlreadyExistsException; import java.nio.file.Path; import java.nio.file.Paths; public class Copy { public static void main(String[] args) { if (args.length != 2 ) { System.err.println( "usage: java Copy source target" ); return ; } Path source = Paths.get(args[ 0 ]); Path target = Paths.get(args[ 1 ]); try { Files.copy(source, target); } catch (FileAlreadyExistsException faee) { System.err.printf( "%s: file already exists%n" , target); } catch (DirectoryNotEmptyException dnee) { System.err.printf( "%s: not empty%n" , target); } catch (IOException ioe) { System.err.printf( "I/O error: %s%n" , ioe.getMessage()); } } } |
列表1的main()方法首先验证命令行确认有两个参数,代表源文件和目标文件,如果没有,则输出相关信息,并结束该程序。
接下来,java.nio.file.Paths类的静态方法Path get(URI uri)方法被调用两次,根据文件名从文件系统获取源文件和目标文件的java.nio.file.Path的实例对象。
Path对象现在被传到了copy()方法。如果方法执行成功了,将不会输出任何信息,否则,将输出适当的错误信息。
编译列表1中的代码(javac Copy.java)然后运行该程序。例如,执行java Copy Copy.java Copy.bak.你可以尝试拷贝一个非空目录到另一个目录.将出现什么现象?
作为练习,可以修改Copy.java增加命令行参数使得该程序能识别CopyOptions,然后传入对应的枚举常量到copy()方法,再观察这些参数对copy()功能的影响。
向后兼容
为了兼容过去的基于流的I/O框架,Files类提供以下两种copy()方法的变种:
public static long copy(InputStream in, Path target, CopyOption… options)
public static long copy(Path source, OutputStream out)
在此系列的后面,我将演示扩展列表1中的copy方法,使得此方法能够拷贝一个目录及子目录到另外一个目录中。
删除文件和目录
Q: 怎样删除一个文件或目录?
A:你可以使用Files类的public static void delete(Path path)方法来删除一个文件或目录,该方法根据文件或目录的路径来删除:
- 如果该路径引用的文件是一个被使用的打开的文件,某些操作系统将会阻止该文件被删除。
- 如果该路径引用的是一个目录,该目录必须是空的(除非是特殊操作系统的特殊的文件)。
- 如果该路径引用的是一个符号链接,该方法只删除符号链接,而不删除符号链接指向的文件。
非原子性删除
该方法的实现是可能需要检查该物理文件是否是在当前目录下。由于这个原因,delete()方法对部分操作系统来说可能不是原子的。为了可移植性和安全性考虑,你不应该认为delete()方法的实现是原子的。
delete()遇到I/O异常时抛出IOException,如果要删除的文件不存在,将抛出java.nio.file.NoSuchFileException,如果目录不为空,则会抛出DirectoryNotEmptyException。
可选的特定异常:
NoSuchFileException是一个可选的特定的异常。
我创建了一个小的应用程序,用于演示怎样使用delete()方式。列表2中列出了该应用程序的源代码。
列表2: Delete.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
import java.io.IOException; import java.nio.file.DirectoryNotEmptyException; import java.nio.file.Files; import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.nio.file.Paths; public class Delete { public static void main(String[] args) { if (args.length != 1 ) { System.err.println( "usage: java Delete file-or-directory" ); return ; } Path path = Paths.get(args[ 0 ]); try { Files.delete(path); } catch (NoSuchFileException nsfe) { System.err.printf( "%s: no such file or directory%n" , path); } catch (DirectoryNotEmptyException dnee) { System.err.printf( "%s: not empty%n" , path); } catch (IOException ioe) { System.err.printf( "I/O error: %s%n" , ioe.getMessage()); } } } |
列表2的main()方法首先验证命令行参数,确保有且仅有一个参数被传入,该参数是一个文件或者目录的路径。如果没有,将会输出有用的信息并结束该程序。
接下来,调用Paths类的get()方法获取Path对象,该对象代表着文件系统中的文件或目录。
Path对象现在被传入到delete()方法中。如果该方法执行成功,将不会输出任何信息。但是,如果失败,则会输出适当的错误信息。
编译列表2(javac Delete.java)中的代码并运行该应用程序。试着删一个可读写的文件,一个只读文件,一个非空目录和一个符号链接,然后观察删除的结果。
deleteIfExists方法:
Files类声明一个静态方法boolean deleteIfExists(Path path)作为delete()的变种。这两个方法唯一的区别是deleteIfExists只删除存在的文件,因此,deleteIfExists方法永远不会抛出NoSuchFileException异常。
移动文件:
Q: 怎样移动一个文件?
A:你可以使用Files类的public static Path move(Path source, Path target, CopyOption… options)方法来移动文件,该方法的作用就是从源文件移动到目标文件。
默认情况下,该方法尝试移动源文件到目标文件,当目标文件已经存在的时候会发生异常,除非目标文件是源文件自身,这种情况下,该方法不会起作用。
每个CopyOption类型的参数传递到move()方法的可变参数列表后将改变该方法的行为。该参数是一个java.nio.file.StandardCopyOption类型枚举常量:
- ATOMIC_MOVE: move方法表现为原子的文件系统操作,其他的参数都会被忽略。当目标文件已经存在的时候,特定的实现表现为该存在的文件是否能够被替换,否则将会抛出IO异常。如果该move方法不能实现原子的文件系统操作,将会抛出java.nio.file.AtomicMoveNotSupportedException异常。
- REPLACE_EXISTING:当目标文件已经存在的时候,目标文件将会被替换,除非目标文件是一个非空的目录。当目标文件已经存在并且是一个符号链接,只替换该符号链接自身,而不替换符号链接所指向的文件。
除了AtomicMoveNotSupportedException之外,move方法抛出的异常与copy方法一致。
我创建了一个小的应用程序用于演示move方法最基本的使用。列表3列出了该应用程序的源代码,该方法与列表1的代码基本一致。
列表3:Move.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
import java.io.IOException; import java.nio.file.DirectoryNotEmptyException; import java.nio.file.Files; import java.nio.file.FileAlreadyExistsException; import java.nio.file.Path; import java.nio.file.Paths; public class Move { public static void main(String[] args) { if (args.length != 2 ) { System.err.println( "usage: java Move source target" ); return ; } Path source = Paths.get(args[ 0 ]); Path target = Paths.get(args[ 1 ]); try { Files.move(source, target); } catch (FileAlreadyExistsException faee) { System.err.printf( "%s: file already exists%n" , target); } catch (DirectoryNotEmptyException dnee) { System.err.printf( "%s: not empty%n" , target); } catch (IOException ioe) { System.err.printf( "I/O error: %s%n" , ioe.getMessage()); } } } |
编译列表3并运行该应用程序。例如,假设有一个名为report.txt的文件,执行java Move report.txt report bak。当你移动文件到另一个已经存在的文件的时候将会发生什么?
作为练习,可以修改Move.java增加命令行参数使得该程序能识别CopyOptions,然后传入对应的枚举常量到move()方法,然后观察这些参数对move()功能的影响。
接下来的内容
在第二部分,我将演示路径相关方法(例如获取路径、检索路径信息),文件或目录测试方法(例如测试文件或目录的存在性)以及面向属性的一些方法。
原文链接: JavaWorld 翻译: ImportNew.com- paddx
译文链接: http://www.importnew.com/15884.html
[ 转载请保留原文出处、译者和译文链接。]
NIO2.0之copy、delete和move的更多相关文章
- Java IO------------------BIO(同步阻塞)、NIO1.0(多路复用)、NIO2.0(AIO,非阻塞)
1. BIO JDK5之前, JDK的IO模式只有BIO(同步阻塞)问题: 因为阻塞的存在, 需对每个请求开启一个线程. 过多的线程切换影响操作系统性能解决: 使用线程池, 处理不过来的放入队列, 再 ...
- go内建方法 append copy delete
package mainimport "fmt"func main() { testAppend() testCopy() testDelete()}func testAppend ...
- Effective C++ 第0章 copy constructor和copy assignment operator
拷贝构造函数(copy constructor)被用来以一个对象来初始化同类型的另一个对象,拷贝赋值运算符(copy assignment operator)被用来将一个对象中的值拷贝到同类型的另一个 ...
- C# - 常见问题整理
关于循环和try{}..catch{}的嵌套使用 foreach(var item in items) { try { try{ } catch(Exception ex) { throw; // 将 ...
- pascal中的xor,shr,shl,Int(),ArcTan(),copy,delete,pos和leftstr,RightStr等详解
数学函数:Inc(i)使I:=I+1;Inc(I,b)使I:=I+b;Abs(x)求x的绝对值例:abs(-3)=3Chr(x)求编号x对应的字符. 例:Chr(65)=’A’chr(97)=’a’c ...
- [Bash] Move and Copy Files and Folders with Bash
In this lesson we’ll learn how to move and rename files (mv) and copy (cp) them. Move index.html to ...
- koa-router 源码由浅入深的分析(7.4.0版本的)
首先简单的介绍下什么koa-router,为什么要使用它,可以简单看下上一篇文章. 了解koa-router 首先我们来看下koa-router的源码的基本结构如下,它是由两部分组成的: ------ ...
- ajax请求基于restFul的WebApi(post、get、delete、put)
近日逛招聘软件,看到部分企业都要求会编写.请求restFul的webapi.正巧这段时间较为清闲,于是乎打开vs准备开撸. 1.何为restFul? restFul是符合rest架构风格的网络API接 ...
- C#中缓存的使用 ajax请求基于restFul的WebApi(post、get、delete、put) 让 .NET 更方便的导入导出 Excel .net core api +swagger(一个简单的入门demo 使用codefirst+mysql) C# 位运算详解 c# 交错数组 c# 数组协变 C# 添加Excel表单控件(Form Controls) C#串口通信程序
C#中缓存的使用 缓存的概念及优缺点在这里就不多做介绍,主要介绍一下使用的方法. 1.在ASP.NET中页面缓存的使用方法简单,只需要在aspx页的顶部加上一句声明即可: <%@ Outp ...
随机推荐
- HDU 6228 tree 简单思维树dp
一.前言 前两天沈阳重现,经过队友提点,得到3题的成绩,但是看到这题下意识觉得题目错了,最后发现实际上是题目读错了....GG 感觉自己前所未有的愚蠢了....不过题目读对了也是一道思维题,但是很好理 ...
- 03018_监听器Listener
1.什么是监听器? (1)监听器就是监听某个对象的状态变化的组件: (2)监听器的相关概念 ①事件源:被监听的对象------三个域对象:request.session.ServletContext ...
- 输出1到最大的N位数 【微软面试100题 第六十五题】
题目要求: 输入数字n,按顺序输出从1到最大的n位10进制数. 例如,输入3,则输出1.2.3....999(最大的3位数). 参考资料:剑指offer第12题. 题目分析: 如果我们在数字前面补0的 ...
- 编程高手解读什么是NodeJs?
首先在搞清楚什么NodeJs之前,我们先来聊聊JavaScript,只要做过开发的人都应该知道JavaScript是目前最为流行的前端(客户端)脚 本语言,JavaScript在Web项目中的使用率可 ...
- gcc学习记录2——多输入文件
首先有两个.c文件:circle.c和circulararea.c. 分别对两个源文件生成目标文件,circle.o和circulararea.o. gcc -c circle.c circularr ...
- redis 集群分配哈希曹
重新分配哈希曹: ip:port 为当前redis集群任意节点ip和port redis-cli --cluster reshard ip:port 操作如图: 分配哈希槽有两种方式: 1.在其他节点 ...
- java如何建项目
java常开发的项目有哪几种? 这几种项目都是怎么建的?
- Linux性能分析调优工具介绍
1.常用性能分析工具 1)CPU性能分析工具 vmstat ps sar time strace pstree top 2)Memory性能分析工具 vmstat strace top ipcs ip ...
- iOS-绘制图层-CALayer的属性
一.position和anchorPoint 1.简单介绍 CALayer有2个非常重要的属性:position和anchorPoint @property CGPoint position; 用来设 ...
- include和require的区别误区
面试时总会被问到include和require的区别,回答的时候一般也是有以下几种区别: 1.include引入文件的时候,如果碰到错误,会给出警告,并继续运行下边的代码. require引入文件的时 ...