Java NIO Path接口和Files类配合操作文件的实例
Path接口
1、Path表示的是一个目录名序列,其后还可以跟着一个文件名,路径中第一个部件是根部件时就是绝对路径,例如/或C:\,而允许访问的根部件取决于文件系统;
2、以根部件开始的路径是绝对路径,否则就是相对路径;
3、静态的Paths.get方法接受一个或多个字符串,字符串之间自动使用默认文件系统的路径分隔符连接起来(Unix是/,Windows是\),这就解决了跨平台的问题,接着解析连接起来的结果,如果不是合法路径就抛出InvalidPathException异常,否则就返回一个Path对象;
//假设是Unix的文件系统 Pathabsolute=Paths.get("/home","cat");//绝对路径 Pathrelative=Pahts.get("ixenos","config","user.properties");//相对路径
4、由String路径获取Path对象
get还可以获取一整条路径(即多个部件构成的单个字符串),例如从配置文件中读取路径:
StringbaseDir=properties.getProperty("base.dir"); //可能获得/opt/ixenos或者C:\ProgramFiles\ixenos PathbasePath=Paths.get(baseDir);
5、组合或解析路径
1)调用p.resolve(q)将按下面的规则返回一个Path:如果q是绝对路径,则返回q,否则追加路径返回p/q或者p\q
PathworkRelative=Paths.get("work"); PathworkPath=basePath.resolve(workRelative); //resolve也可以接受字符串形参 PathworkPath=basePath.resolve("work");
2)调用p.resolveSibling("q")将解析指定路径p的父路径o,并产生兄弟路径o/q
PathtempPath=workPath.resolveSibling("temp"); /* 如果workPath是/opt/ixenos/work 那么将创建/opt/ixenos/temp */
3)调用p.relativize(r)将产生一个冗余路径q,对q进行解析将产生相对路径r,最终r不包含和p的交集路径
/* pathA为/home/misty pathB为/home/ixenos/config 现已pathA对pathB进行相对化操作,将产生冗余路径 */ PathpathC=pathA.relativize(pathB);//此时pathC为../ixenos/config /* normalize方法将移除冗余部件 */ PathpathD=pathC.normalize();//pathD为/ixenos/config
4)toAbsolutePath将产生给定路径的绝对路径,从根部件开始
5)Path类还有一些有用的断开和组合路径的方法,比如getParent、getFileName、getRoot//获得根目录
6)Path有个toFile方法用来跟遗留类File类打交道,File类也有个toPath方法
Files工具类
1、读写文件
方法签名:
staticpathwrite(Pathpath,byte[]bytes,OpenOption...options)
staticpathwrite(Pathpath,Iterablelines,OpenOption...options)
这里只列举下面用到的方法,更多方法请看API文档...
其中OpenOption是个nio接口,StandardOpenOption是其枚举实现类,各枚举实例功能请查看API文档
/* Files提供的简便方法适用于处理中等长度的文本文件 如果要处理的文件长度较大,或者二进制文件,那么还是应该使用经典的IO流 */ //将文件所有内容读入byte数组中 byte[]bytes=Files.readAllBytes(path);//传入Path对象 //之后可以根据字符集构建字符串 Stringcontent=newString(bytes,charset); //也可以直接当作行序列读入 Listlines=Files.readAllLines(path,charset); //相反,也可以写一个字符串到文件中,默认是覆盖 Files.write(path,content.getBytes(charset));//传入byte[] //追加内容,根据参数决定追加等功能 Files.write(path,content.getBytes(charset),StandardOpenOption.APPEND);//传入枚举对象,打开追加开关 //将一个行String的集合List写出到文件中 Files.write(path,lines);
2、复制、剪切、删除
方法签名:
staticpathcopy(Pathsource,Pathtarget,CopyOption...options)
staticpathmove(Pathsource,Pathtarget,CopyOption...options)
staticvoiddelete(Pathpath)//如果path不存在文件将抛出异常,此时调用下面的比较好
staticbooleandeleteIfExists(Pathpath)
这里只列举下面用到的方法,更多方法请看API文档...
其中CopyOption是个nio接口,StandardCopyOption是其枚举实现类,各枚举实例功能请查看API文档
其中有个ATOMIC_MOVE可以填入用来保证原子性操作,要么移动成功完成,要么源文件保持在原位置
//复制 Files.copy(fromPath,toPath); //剪切 Files.move(fromPath,toPath); /* 以上如果toPath已存在,那么操作失败, 如果要覆盖,需传入参数REPLACE_EXISTING 还要复制文件属性,传入COPY_ATTRIBUTES */ Files.copy(fromPath,toPath,StandardCopyOption.REPLACE_EXISTING,StandardCopyOption.COPY_ATTRIBUTES);
3、创建文件和目录
//创建新目录,除了最后一个部件,其他必须是已存在的 Files.createDirectory(path); //创建路径中的中间目录,能创建不存在的中间部件 Files.createDirectories(path); /* 创建一个空文件,检查文件存在,如果已存在则抛出异常 而检查文件存在是原子性的,因此在此过程中无法执行文件创建操作 */ Files.createFile(path); //添加前/后缀创建临时文件或临时目录 PathnewPath=Files.createTempFile(dir,prefix,suffix); PathnewPath=Files.createTempDirectory(dir,prefix);
4、获取文件信息
略,具体看API文档,或者corejavapage51
5、迭代目录中的文件
旧的File类有两个方法获取目录中所有文件构成的字符串数组,String[]list()和String[]list(FileFilterfilter),但是当目录中包含大量文件时,这两方法性能会非常低。
原因分析:
1、//File类list所有文件 publicString[]list(){ SecurityManagersecurity=System.getSecurityManager();//文件系统权限获取 if(security!=null){ security.checkRead(path); } if(isInvalid()){ returnnull; } returnfs.list(this);//底层调用FileSystem的list } //FileSystem抽象类的list //File类中定义fs是由DefaultFileSystem静态生成的 privatestaticfinalFileSystemfs=DefaultFileSystem.getFileSystem(); //因此我们来看一下DefaultFileSystem类,发现是生成一个WinNtFileSystem对象 classDefaultFileSystem{ /** *ReturntheFileSystemobjectforWindowsplatform. */ publicstaticFileSystemgetFileSystem(){ returnnewWinNTFileSystem(); } } //而WinNtFileSystem类继承于FileSystem抽象类,这里我们主要观察它的list(Filefile)方法 @Override publicnativeString[]list(Filef); /*我们可以看到这是个native方法,说明list的操作是由操作系统的文件系统控制的,当目录中包含大量的文件时,这个方法的性能将会非常低。 由此为了替代,NIO的Files类设计了newDirectoryStream(Pathdir)及其重载方法,将生成Iterable对象(可用foreach迭代)*///~ 2、//回调过滤 publicString[]list(FilenameFilterfilter){//采用接口回调 Stringnames[]=list();//调用list所有 if((names==null)||(filter==null)){ returnnames; } Listv=newArrayList<>(); for(inti=0;i 这时候高科技来了——Files获得可迭代的目录流,
传入一个目录Path,遍历子孙目录返回一个目录Path的Stream,注意这里所有涉及的Path都是目录而不是文件!
因此,Files类设计了newDirectoryStream(Pathdir)及其重载方法,将生成Iterable对象(可用foreach迭代)
遍历目录得到一个可迭代的子孙文件集合
static DirectoryStream < Path > newDirectoryStream ( Path dir) Opensadirectory,returninga DirectoryStreamtoiterateoverallentriesinthedirectory. static DirectoryStream < Path > newDirectoryStream ( Path dir, DirectoryStream.Filter Path >filter)