??xml version="1.0" encoding="utf-8" standalone="yes"?>
本文中我们来讨论?span onclick="tagshow(event)" class="t_tag">NIO2中怎样创徏文g、读取文件和写文件。NIO2提供了多U创?
文g的方法,使得我们在创建文件的时候就可以指定文g的某些初始属性。例如在支持POSIX的文件系l上指定文g的所有者,讉K权限{。关于文件的属性,
L上一文?a target="_blank">Java SE 7新特性之文g操作Q?Q?- 理元数?/a>
创徏文g
可以调用createFile(FileAttribute<?>)Ҏ创徏一个空文g。该Ҏ的参数就是文件的初始属性。下面的例子是怎样
在创建文件的时候赋予该文g某些权限的属性:
;
Path newFile = ;
PosixFileAttributes attrs = Attributes.readPosixFileAttributes(sourceFile);
FileAttribute<Set<PosixFilePermission>> attr =
PosixFilePermissions.asFileAttribute(attrs.permissions());
try {
file.createFile(attr);
} catch (IOException x) {
//unable to create the file
}
;
try {
file.createFile(); //Create the empty file with default permissions, etc.
} catch (FileAlreadyExists x) {
System.err.format("file named %s already exists%n", file);
} catch (IOException x) {
//Some other sort of failure, such as permissions.
System.err.format("createFile error: %s%n", x);
}
我们可以通过newInputStreamQOpenOption...)Ҏ打开和读取文件。这个方法返回一个unbuffered输入(input
streamQ,我们可以用它来从文g中读取字节内宏V?em>
;
InputStream in = null;
try {
in = file.newInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String line = null;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException x) {
System.err.println(x);
} finally {
if (in != null) in.close();
}
使用Stream I/O来创建和写文?/font>
我们可以使用newOutputStreamҎ来创建文件、扩展文件或覆盖已有文g。这个方法ؓ了写文g而打开或创建文Ӟ该方法返回一?
unbuffered的输出流Qoutput streamQ。newOutputStreamҎ有两UŞ式:
q两UŞ式都接受一lOpenOption作ؓ参数Q第二种形式q允许指定初始的文g属性。这个方法支持的StandardOpenOption有:
如果没有指定OpenOptionQ该Ҏ的行为是Q如果文件不存在Q则创徏新文Ӟ如果文g存在Q那么截断它。也是说缺省的选择是CREATE?
TRUNCATE_EXISTING选项的组合?br />
下面的代码打开一?span onclick="tagshow(event)" class="t_tag">日志文gQ如果文件不存在Q则创徏一个新文g。如果文?
存在Q这新的内Ҏ展到文gN?em>
Path logfile = ;
//Convert the string to a byte array.
String s = ;
byte data[] = s.getBytes();
OutputStream out = null;
try {
out = new BufferedOutputStream(logfile.newOutputStream(CREATE, APPEND));
out.write(data, 0, data.length);
} catch (IOException x) {
System.err.println(x);
} finally {
if (out != null) {
out.flush();
out.close();
}
}
使用Channel I/O?span onclick="tagshow(event)" class="t_tag">d文g
Stream I/O每次d一个字W,Channel
I/O每次d一个缓冲块的数据。ByteChannel接口提供了基本的d功能。SeekableByteChannel扩展?
ByteChannelq提供了l护一个channel中的位置q改变该位置的能力。SeekableByteChannelq支持截断文件和查询文g?
的功能?br />
Ud到文件中不同的位|,从该位置开始读或写的能力我们可以随机讉K文g。有两种形式?
newByteChannelҎ可以用来L写文Ӟq两UŞ式和newOutputStreamҎ一栗?br />
q两个方法都允许指定OpenOptionQnewOutputStream所支持的选择q里也支持,而且q里q支持另外一个选项READQ因?
SeekableByteChannel既支持读也支持写?br />
如果选项是READQ那么该channel是Z读访问打开。如果选项是WRITE或APPENDQ则该channel是Z写访问打开。如果没有指
定,该channel默认是ؓ了读打开?br />
下面的代码从文g中读取内容ƈ输出到控制台上:
try {
sbc = file.newByteChannel(); //Defaults to READ
ByteBuffer buf = ByteBuffer.allocate(10);
//Read the bytes with the proper encoding for this platform.
//If you skip this step, you might see something that looks like Chinese
//characters when you expect Latin-style characters.
String encoding = System.getProperty("file.encoding");
while (sbc.read(buf) > 0) {
buf.rewind();
System.out.print(Charset.forName(encoding).decode(buf));
buf.flip();
}
} catch (IOException x) {
System.out.println("caught exception: " + x);
} finally {
if (sbc != null) sbc.close();
}
//Create the set of options for appending to the file.
Set<OpenOptions> options = new HashSet<OpenOption>();
options.add(APPEND);
options.add(CREATE);
//Create the custom permissions attribute.
Set<PosixFilePermission> perms = PosixFilePermissions.fromString("rw-r------");
FileAttribute<Set<PosixFilePermission>> attr = PosixFilePermissions.asFileAttribute(perms);
//Convert the string to a ByetBuffer.
String s = ;
byte data[] = s.getBytes();
ByteBuffer bb = ByteBuffer.wrap(data);
SeekableByteChannel sbc = null;
try {
sbc = file.newByteChannel(options, attr);
sbc.write(bb);
} catch (IOException x) {
System.out.println("exception thrown: " + x);
} finally {
if (sbc != null) sbc.close();
}
]]>
PathcL供了很多Ҏ来对文g和目录进行读、写和其他的操作。在看这些方法之前,我们先需要了解一些其他的概念Q?br />
Varargs实际上是Variable number of arguments的羃写,也就是可变数目的参数。例如在下面的方法声明中QCopyOption参数后面的省略号表明q个Ҏ接受可变个数的参数?br />
Path moveTo(Path, CopyOption...)
当一个方法可以接受可变数目的参数Ӟ你可以传入以逗号分隔的多个参敎ͼ或者传入一个数l?br />
对于上面的moveToҎQ可以这栯用:
Path orig = ;
Path new = ;
orig.moveTo(new, REPLACE_EXISTING, ATOMIC_MOVE);
Path的很多方法在文gpȝ上执行的操作都是原子操作Q例如moveToҎ。原子操作是指不会被中断或不会部分执行的操作。操作要么是完全成功Q要么是完全p|。当有多个进E操作同文gpȝ的相同的区域的时候这一点就很重要?br />
很多的文件I/OҎ支持Ҏ铄概念?br />
调用W一个方法会q回一个对象,我们可以直接调用q个对象的方法,q个Ҏ依然q回一个对象,我们又可以直接调用该对象的方法,phl下厅R例如:
String value = Charset.defaultCharset().decode(buf).toString();
UserPrincipal group = file.getFileSystem().getUserPrincipalLookupService().lookupPrincipalByName("me");
q个技术能够我们~写更加紧凑的代码,避免声明一些我们不需要的临时变量?br />
PathcdCFileRef接口。FileRef接口包含了定位文件和讉K文g的方法?br />
PathcL两个Ҏ能够接受带模式匹配的参数。下面是q种参数的规则:
星号*匚wL数目的字W(也可能是没有Q?br />
两个星号**同样是代表Q意数目的字符Q不同的是这个匹配可以穿目录边界。例?c:"a**"bar可以匚wc:"abc"barQ也可以匚wc:"am"cn"bar?br />
问号?匚w一个字W?br />
花括号{}表明子模式的集合Q例如{sun,moon,stars}可以匚w'sun','moon'?#8216;stars’Q{temp*,tmp*}可以匚w以temp或tmp开始的L字符丌Ӏ?br />
要匹?,?或其他的Ҏ字符Q可以用{义符"。例?"匚w单个?Q??匚w问号?br />
Ҏ号[]表示一l单独的字符Q当使用?的时候,也代表一个范围的字符Q例如:
[aeiou]匚wM单独的元韛_W,[0-9]匚wL数字Q[A-Z]匚wL大写字母Q[a-z,A-Z]匚wL大写或小写字母。在Ҏ号中Q星受问号和"都只是表C它们自w,不再作ؓҎW号?br />
下面是一些例子:
*.html匚w所有以.htmll尾的字W串?br />
???匚w所有长度ؓ3的字W串
*[0-9]*匚w所有包含有数字的字W串
*.{html,htm,pdf}匚w所有以.html,.html?pdfl尾的字W串
a?*.java匚w所有以a开_后面跟至一个字W,然后?javal尾的字W串?br />
{foo*,*[0-9]*}匚w以foo开头的字符串或包含有数字的字符丌Ӏ?br />
关于参数中的模式的用,请参考FileSystemcȝgetPathMatcherҎ的帮助文档?br />
如果q种模式匚w仍然不能够满需要,我们q可以用正则表辑ּ?br />
Path会指向文件或者目录,但是我们q不能确定这个文件或者目录是否存在,是否可读Q是否可写,是否可以执行。要定文g/目录是否存在以及E序是否可以讉K该文?目录Q可以用checkAccess(AccessMode...)Ҏ。可选的AccessMode有:
* READ – 查文?目录是否存在以及E序是否有权限读该文?目录
* WRITE – 查文?目录是否存在以及E序是否有权限写该文?目录
* EXECUTE – 查文?目录是否存在以及E序在该文g/目录上是否有执行权限
如果调用checkAccess的时候没有传入Q何参敎ͼ该方法只是检查文件是否存在?br />
下面的例子演CZ怎样验证文g是否存在以及E序是否有读和执行的权限?br />
import static java.nio.file.AccessMode.*;
Path file = ...;
try {
file.checkAccess(READ, EXECUTE);
} catch (IOException x) {
//Logic for error condition...
return;
}
//Logic for executable file...
需要注意的是,当checkAccess执行完之后,文g的权限可能被其他的用P例如pȝ理员)修改。这实际上是很多应用E序都有的安全性的问题。如果你感兴,可以搜烦TOCTTOU Qtime of check to time of useQ?br />
当文件系l中存在W号链接的时候,可能两个不同的\径会指向同一个文件或目录。方法isSamePath会比较两个Path来检查它们是否指向同一个文?目录?br />
Path p1 = ...;
Path p2 = ...;
try {
if (p1.isSameFile(p2)) {
//Logic when the paths locate the same file
}
} catch (IOException x) {
//Logic for error condition...
return;
}
]]>
那么执行的结果是
MethodBeforeAdvice
MethodInterceptor: before call
Really method excuting
MethodInterceptor: after call
AfterReturningAdvice
也就是说Q执行顺序是QMethodBeforeAdviceQMethodInterceptor的调用前的部分,目标ҎQMethodInterceptor的调用后的部分,AfterReturningAdvice?BR>
如果proxy的定义是
执行的结果是
MethodBeforeAdvice
MethodInterceptor: before call
Really method excuting
AfterReturningAdvice
MethodInterceptor: after call
也就是说Q执行的序是:MethodBeforeAdviceQMethodInterceptor的调用前的部分,目标ҎQAfterReturningAdviceQMethodInterceptor的调用后的部分?BR>
如果proxy的定义是
执行的结果是Q?BR>MethodInterceptor: before call
MethodBeforeAdvice
Really method excuting
AfterReturningAdvice
MethodInterceptor: after call
也就是说,执行的顺序是QMethodInterceptor的调用前的部分,MethodBeforeAdviceQ目标方法,AfterReturningAdviceQMethodInterceptor的调用后的部分?BR>以上的顺序是在springframework 1.2.5中测试的?BR>