Java 7引入了NIO.2。NIO.2是继承自NIO框架,并添加了新的功能(比如:处理软链接和硬链接的功能)。这篇帖子包含三个部分,我将使用NIO.2的一些演示样例。由此向大家演示NIO.2的基本用法。

 

下一篇地址http://blog.csdn.net/u011225629/article/details/46386599

文件拷贝

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

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

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

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()功能的影响。

接下来的内容

在第二部分,我将演示路径相关方法(比如获取路径、检索路径信息),文件或文件夹測试方法(比如測试文件或文件夹的存在性)以及面向属性的一些方法。

疯狂Java学习笔记(75)-----------NIO.2第一篇的更多相关文章

  1. 【疯狂Java学习笔记】【第一章:Java语言概述】

    [学习笔记]1.Java与C#的异同:Java与C#的相同之处有很多,它们均摒弃了C++面向对象的多继承.宏定义.全局变量.全局函数.指针等等难以使用的机制,添加进了成熟的机制,如垃圾回收.接口等等. ...

  2. 【疯狂Java学习笔记】【理解面向对象】

    [学习笔记]1.Java语言是纯粹的面向对象语言,这体现在Java完全支持面向对象的三大基本特征:封装.继承.多态.抽象也是面向对象的重要组成部分,不过它不是面向对象的特征之一,因为所有的编程语言都需 ...

  3. 疯狂Java学习笔记(84)----------大约 Java 对象序列化,你不知道 5 事

    几年前,.当一个软件团队一起用 Java 书面申请.我认识比一般程序猿多知道一点关于 Java 对象序列化的知识所带来的优点. 关于本系列 您认为自己懂 Java 编程?其实,大多数程序猿对于 Jav ...

  4. 疯狂java学习笔记之面向对象(八) - static和final

    一.static: 1.static是一个标识符: - 有static修饰的成员表明该成员是属于类的; - 没有static修饰的成员表明该成员是属于实例/对象的. 2.static修饰的成员(Fie ...

  5. 疯狂java学习笔记之面向对象(四) - this关键字

    Java中this关键字主要有以下两个方法: 1.this引用 - 可用于任何非static修饰的方法和构造器中,当this用于方法中时,它代表调用该方法的实例/对象;当this用于构造器中时,它代表 ...

  6. 疯狂java学习笔记之面向对象(一) - 定义类、方法、构造器

    Java面向对象 1.定义类 2.创建对象.调用方法 类和对象: 某一类对象的概念定义. 比如:人类 - 抽象出来的概念(不特指某个人) 对象 - 在类的概念下产生的一个实例,它就是一个对象了. ja ...

  7. 疯狂Java学习笔记(70)-----------挚爱Java

    与大家分享! 挚爱Java 10个使用Java最广泛的现实领域 写好Java代码的30条经验总结 Java字符串的substring真的会引起内存泄露么? Java内存的原型及工作原理深度剖析 Jav ...

  8. 疯狂java学习笔记之面向对象(六) - 构造器重载、方法重载和方法重写

    一.方法重载(Overload): Java允许同一个类中定义多个同名方法,只要形参不一样就可以,如果同一个类中包含了两个或两个以上方法名相同的方法,但形参列表不同,则被成为方法重载(两同一异). 同 ...

  9. 疯狂java学习笔记之面向对象(五) - 封装、继承、多态

    一.封装: 封装的概念: - 合理的隐藏:隐藏不想被外界操作的Field.方法.构造器 - 合理的暴露:一般就是希望给别人调用的方法 e.g:显示器(按键暴露出来操作,但实际的东西/细节方法被隐藏起来 ...

随机推荐

  1. 统计uv(转)

    UV是unique visitor的简写,是指通过互联网访问.浏览这个网页的自然人.在同一天内,uv只记录第一次进入网站的具有独立IP的访问者,在同一天内再次访问该网站则不计数.独立IP访问者提供了一 ...

  2. 2733: [HNOI2012]永无乡

    题解: 爬到了bzoj的数据哈哈哈哈 然后提交上去t了 自己测只有1秒多呀 不理解 然后这题目就是个线段树/平衡树合并裸题 来练一下线段树合并 据说是nlogn的 #include <bits/ ...

  3. Webservice返回json数据格式

    问题: 我将结果内容用字符串拼接成Json数据并返回的时候,会在结果前面添加xml头部,结果如下. <span ><string xmlns="http://tempuri ...

  4. zstu-4243 牛吃草

    贴一发两圆相交面积模板 #include<bits/stdc++.h> #define pi acos(-1.0) using namespace std; ; double _abs(d ...

  5. k8s 使用

    转自:https://blog.csdn.net/zyc88888/article/details/79281954

  6. Volley网络通信框架

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools=&q ...

  7. Vscode下Python的用户界面介绍

    Visual Studio Code的核心是代码编辑器.与许多其他代码编辑器一样,VS Code在左侧采用通用用户界面和浏览器布局,显示您可以访问的所有文件和文件夹,右侧显示编辑器,显示已打开文件的内 ...

  8. go语言中goroute使用:=遇到的坑

    先看下源代码,预想从1至N总取出所有能被a或b整除的正整数之和,为了利用go语言的并行优势,特使用goroute特性来实现,同时使用普通顺序计算进行效率比较分析 package chango impo ...

  9. Mac配置Eclipse CDT的Debug出现的问题(转)

      问题1:出现 Could not determine GDB version using command: gdb --version 原因: mac上没有安装gdb或者gdb位置配置有问题 解决 ...

  10. 009.Docker Compose部署及基础使用

    一 Docker Compose概述 Compose是一个用于定义和运行多容器Docker应用程序的工具.使用Compose,您可以使用YAML文件来配置应用程序的服务.然后,使用单个命令,您可以从配 ...