JavaNIO学习一

摘要:
使用标准参数OpenOption。在NIO。2、create、read和write都支持可选的OpenOption参数,用于设置如何打开和读取文件。事实上,OpenOption是java中的一个接口。尼奥。文件包。它有两个实现:LinkOption(还记得著名的NOFOLLOW_LINKS枚举常量吗?请尝试{Files\createFile;}捕获{System.err.println;}也可以在创建文件时设置属性。以下代码演示了如何在POSIX文件系统上创建文件并设置访问权限:Java代码Pathnewfile=FileSystems。getDefault()。获取路径;设置perms=PosixFilePermissions。fromString;FileAttribute<Set<PosixFilePermission>>attr=PosixFilePermissions。asFileAttribute;尝试{Files.createFile;}捕获{System.err.println;}正如您稍后将看到的,这不是创建文件的唯一方法。

文章来源:http://cucaracha.iteye.com/blog/2041847

对文件来说,可能最常用的操作就是创建、读取和写出。NIO.2 提供了丰富的方法来完成这些任务。本文从简单的小文件操作开始,最后以缓冲和非缓冲流的操作结束。 

流分为输入流和输出流(可以输出到任何地方,比如硬盘或内存)。流支持不同类型的数据,比如字符串、字节、原始数据类型、本地化字符、对象等。使用非缓冲流,读和写的操作直接依赖底层文件系统,使用缓冲流,数据从内存的缓冲区读取,只有缓冲区空了之后才会调用本地方法进行读取。同样,缓冲输出流也是先将数据写出缓冲区,当缓冲区满了之后才会使用本地方法写出。如果没有等到缓冲区满就需要写出数据,那么可以使用 flush 方法。 

使用标准参数 OpenOption 

在 NIO.2 中,创建、读取和写出都支持一个可选的 OpenOption 参数,使用它来设置怎样打开和读取文件。实际上,OpenOption 是 java.nio.file 包中的一个接口,它有两个实现:LinkOption (还记得著名的 NOFOLLOW_LINKS 枚举常量吗?)和 StandardOpenOption 类。StandardOpenOption 提供了以下的枚举常量: 

  •     READ - 打开文件进行读取访问
  •     WRITE - 打开文件进行写出访问
  •     CREATE - 如果文件不存在则创建新文件
  •     CREATE_NEW - 创建新文件,如果文件已存在,则抛出异常
  •     APPPEND - 在文件末尾添加数据(与 WRITE 和 CREATE 结合使用)
  •     DELETE_ON_CLOSE - 当流关闭的时候删除文件(用于删除临时文件)
  •     TRUNCATE_EXISTING - 将文件截断为 0 个字节(与 WRITE 结合使用)
  •     SPARSE - 新创建的文件是 Sparse 文件
  •     SYNC - 保持文件内容和元数据同步
  •     DSYNC - 保持文件内容异步



在本文中,将会演示一些上面的枚举常量的用法。 

创建新文件 

可以使用 Files.createFile() 方法来创建新文件,这个方法接受一个 Path 类型的参数,并且接受一个可选的 FileAttribute<?> 参数用于在创建文件的时候设置文件属性。调用后返回新创建的文件。下面的代码段将演示在  C: afaelnadal ournaments2010 目录(此目录必须存在)下创建 SonyEricssonOpen.txt 文件(文件必须不存在,如果已经存在,则会抛出 FileAlreadyExistsException 异常),并使用默认属性。 

Java代码  收藏代码
  1. Path newfile = FileSystems.getDefault().   
  2.                            getPath("C:/rafaelnadal/tournaments/2010/SonyEricssonOpen.txt");   
  3. …   
  4. try {   
  5.     Files.createFile(newfile);   
  6. catch (IOException e) {   
  7.     System.err.println(e);   
  8. }  



也可以在创建文件的时候设置属性,下面的代码演示了如何在  POSIX 文件系统上创建文件,并设置访问权限: 

Java代码  收藏代码
  1. Path newfile = FileSystems.getDefault().   
  2.                getPath("/home/rafaelnadal/tournaments/2010/SonyEricssonOpen.txt");   
  3.   
  4. Set<PosixFilePermission> perms = PosixFilePermissions.fromString("rw-------");   
  5. FileAttribute<Set<PosixFilePermission>> attr = PosixFilePermissions.asFileAttribute(perms);   
  6. try {   
  7.     Files.createFile(newfile, attr);   
  8. catch (IOException e) {   
  9.     System.err.println(e);   
  10. }  



随后你将会看到,这并不是创建文件的唯一方式。 

写出小文件 

NIO.2 提供了优雅的方式来写出小的二进制或文本文件。使用 Files.write() 方法写出文件,这个方法会打开文件用于写出(如果文件不存在会先创建文件)或者将常规文件截取为 0 字节后写出。当所有字节和行写完后,这个方法会关闭文件(即使出现 I/O 错误或异常也会关闭)。简单说来,这个方法相当于使用了  CREATE、TRUNCATE_EXISTING、和 WRITE 的 OpenOption 参数。 

调用 write() 写出字节 

可以使用 Files.write() 来写出字节,这个方法接受一个 Path 类型的参数,一个用于写出的字节数组,和一个可选的文件打开参数(OpenOption)。这个方法会返回写出文件的 Path 对象。 

下面的代码段将演示如何写出字节数组,并且使用了默认的打开参数。(文件名为 ball.png,将会被写出到 C: afaelnadalphotos 目录): 

Java代码  收藏代码
  1. Path ball_path = Paths.get("C:/rafaelnadal/photos", "ball.png");   
  2. …   
  3. byte[] ball_bytes = new byte[]{              
  4. (byte)0x89,(byte)0x50,(byte)0x4e,(byte)0x47,(byte)0x0d,(byte)0x0a,(byte)0x1a,(byte)0x0a,   
  5. (byte)0x00,(byte)0x00,(byte)0x00,(byte)0x0d,(byte)0x49,(byte)0x48,(byte)0x44,(byte)0x52,   
  6. (byte)0x00,(byte)0x00,(byte)0x00,(byte)0x10,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x10,   
  7. (byte)0x08,(byte)0x02,(byte)0x00,               
  8. …   
  9. (byte)0x49,(byte)0x45,(byte)0x4e,(byte)0x44,(byte)0xae,(byte)0x42,(byte)0x60,(byte)0x82    
  10. };   
  11.   
  12. try {   
  13.     Files.write(ball_path, ball_bytes);   
  14. catch (IOException e) {   
  15.     System.err.println(e);   
  16. }  



现在,你检查目录,就可以看到创建的 ball.png 文件。 

如果你想使用字节的方式来写出字符串(String),那么先要将字符串转换为字节数组,下面的代码将在  C: afaelnadalwiki 目录下写出 wiki.txt 文件: 

Java代码  收藏代码
  1. Path rf_wiki_path = Paths.get("C:/rafaelnadal/wiki", "wiki.txt");   
  2. …   
  3. String rf_wiki = "Rafael "Rafa" Nadal Parera (born 3 June 1986) is a Spanish professional   
  4. tennis " + "player and a former World No. 1. As of 29 August 2011 (2011 -08-29)[update], he is   
  5. ranked No. " + "by the Association of Tennis Professionals (ATP). He is widely regarded as   
  6. one of the greatest players " + "of all time; his success on clay has earned him the nickname   
  7. "The King of Clay", and has prompted " + "many experts to regard him as the greatest clay   
  8. court player of all time. Some of his best wins are:";   
  9.   
  10. try {   
  11.     byte[] rf_wiki_byte = rf_wiki.getBytes("UTF-8");   
  12.     Files.write(rf_wiki_path, rf_wiki_byte);   
  13. catch (IOException e) {   
  14.     System.err.println(e);   
  15. }  



调用 write() 按行写出 

可以使用 Files.write() 方法按行写出文件,方法会在每行的结尾根据系统添加一个行结束符(line.separator 系统属性)。这个方法接受一个 Path 类型的参数,一个可迭代的字符序列集合,一个用于编码的参数和一个可选的文件打开参数。这个方法会返回写出的文件 Path 对象。 

下面的代码将演示如何按行写出文件(实际上,会在上节创建的 wiki.txt 文件后面添加内容)。 

Java代码  收藏代码
  1. Path rf_wiki_path = Paths.get("C:/rafaelnadal/wiki", "wiki.txt");  
  2. …  
  3. Charset charset = Charset.forName("UTF-8");  
  4. ArrayList<String> lines = new ArrayList<>();  
  5. lines.add(" ");  
  6. lines.add("Rome Masters - 5 titles in 6 years");  
  7. lines.add("Monte Carlo Masters - 7 consecutive titles (2005-2011)");  
  8. lines.add("Australian Open - Winner 2009");  
  9. lines.add("Roland Garros - Winner 2005-2008, 2010, 2011");  
  10. lines.add("Wimbledon - Winner 2008, 2010");  
  11. lines.add("US Open - Winner 2010");  
  12.   
  13. try {  
  14. Files.write(rf_wiki_path, lines, charset, StandardOpenOption.APPEND);  
  15. catch (IOException e) {  
  16. System.err.println(e);  
  17. }  



读取小文件 

NIO.2 提供了快速读取小文件的方法。使用  Files.readAllBytes() 和Files.readAllLines() 方法读取文件。这个方法在读取完成后会自动关闭流(即使出现 I/O 异常或错误也会关闭)。 

调用 readAllBytes() 方法读取数据 

Files.readAllBytes() 方法将整个文件读入字节数组中。下面的代码将演示读取前面创建的  ball.png 文件(文件必须存在)到字节数组: 

Java代码  收藏代码
  1. Path ball_path = Paths.get("C:/rafaelnadal/photos", "ball.png");   
  2. …   
  3. try {   
  4.     byte[] ballArray = Files.readAllBytes(ball_path);               
  5. catch (IOException e) {   
  6.     System.out.println(e);   
  7. }  



如果你想验证返回的字节是否正确,你可以将返回的字节写出到相同目录的 bytes_to_ball.png 文件中: 

Java代码  收藏代码
  1. …   
  2. Files.write(ball_path.resolveSibling("bytes_to_ball.png"), ballArray);   
  3. …  



或者可以通过下面的 ImageIO 方式写出 PNG 图片文件: 

Java代码  收藏代码
  1. BufferedImage bufferedImage = ImageIO.read(new ByteArrayInputStream(ballArray));   
  2. ImageIO.write(bufferedImage, "png", (ball_path.resolveSibling("bytes_to_ball.png")).toFile());  



readAllBytes() 方法也可以用于读取文本文件,这时,读取的字节需要转换成字符串,看看下面的例子(你可以使用任何其它编码): 

Java代码  收藏代码
  1. …   
  2. try {   
  3.     byte[] wikiArray = Files.readAllBytes(wiki_path);   
  4.     String wikiString = new String(wikiArray, "ISO-8859-1");   
  5.     System.out.println(wikiString);   
  6. catch (IOException e) {   
  7.     System.out.println(e);   
  8. }  



注意:如果文件太大(超过 2GB),那么字节数组的长度将会超出上限,会抛出 OutOfMemory 异常。这依赖于 JVM 的 Xmx 参数:在 32 位 JVM 上,不能超过 2GB(通常使用默认,不超过 256 MB)。在 64 位 JVM 上,可以大一些——十几 GB。 

调用 readAllLines() 方法读取文件 

使用 readAllLines() 方法会按行返回 String 类型的 List,方便进行循环取值(传递给这个方法的 Path 对象用于指定被读取文件,CharSet 用于设置解码的编码格式): 

Java代码  收藏代码
  1. Path wiki_path = Paths.get("C:/rafaelnadal/wiki", "wiki.txt");   
  2. …   
  3. Charset charset = Charset.forName("ISO-8859-1");   
  4. try {   
  5.     List<String> lines = Files.readAllLines(wiki_path, charset);   
  6.     for (String line : lines) {   
  7.          System.out.println(line);   
  8.     }   
  9. catch (IOException e) {   
  10.     System.out.println(e);   
  11. }  



按照官方文档,这个方法会识别以下的行结束符: 

  •     u000Au000D - 换行回车
  •     u000A - 换行
  •     u000D - 回车



使用缓冲流 

对于大多数操作系统来说,进行读写操作都是比较消耗资源的操作。NIO.2 提供了两个方法来进行缓冲区读写:Files.newBufferedReader() 和 Files.newBufferedWriter(),这两个方法都接受 Path 类型的对象,并返回老的 JDK 1.1 中的 BufferedReader 或 BufferedWriter 对象。 

使用 newBufferedWriter() 方法 

newBufferedWriter() 参数为一个 Path 类型的对象,一个 Charset 对象用于编码,一个可选的文件打开方式选项,返回一个新的 BufferedWriter 对象。这个方法将打开文件用于写出(如果文件不存在将会创建文件)或者将已存在的文件截取为 0 字节。简短说来,这个方法默认情况下相当于使用了 CREATE、TRUNCATE_EXISTING、和 WRITE 的 OpenOption 属性。 

下面的代码将在前面创建的 wiki.txt 文件后面添加内容: 

Java代码  收藏代码
  1. Path wiki_path = Paths.get("C:/rafaelnadal/wiki", "wiki.txt");   
  2. …   
  3. Charset charset = Charset.forName("UTF-8");   
  4. String text = " Vamos Rafa!";   
  5. try (BufferedWriter writer = Files.newBufferedWriter(wiki_path, charset,    
  6.                                                                  StandardOpenOption.APPEND)) {   
  7.      writer.write(text);   
  8. catch (IOException e) {   
  9.      System.err.println(e);   
  10. }  



使用 newBufferedReader() 方法 

newBufferedReader() 方法可用于通过缓冲区读取文件。它的参数为一个 Path 类型的对象,一个 Charset 用于解码。它将返回一个 BufferedReader 类型的对象。 

下面的代码将演示使用 UTF-8 的方式读取 wiki.txt: 

Java代码  收藏代码
  1. Path wiki_path = Paths.get("C:/rafaelnadal/wiki", "wiki.txt");   
  2. …   
  3. Charset charset = Charset.forName("UTF-8");   
  4. try (BufferedReader reader = Files.newBufferedReader(wiki_path, charset)) {   
  5.      String line = null;   
  6.      while ((line = reader.readLine()) != null) {   
  7.              System.out.println(line);   
  8.      }   
  9. catch (IOException e) {   
  10.      System.err.println(e);   
  11. }  



如果按照前文的例子一步步运行下来,那么运行结果将会是: 

Java代码  收藏代码
  1. Rafael "Rafa" Nadal Parera (born 3 June 1986) is a Spanish professional tennis player and a   
  2. former World No. 1. As of 29 August 2011 (2011 -08-29)[update], he is ranked No. 2 by the   
  3. Association of Tennis Professionals (ATP). He is widely regarded as one of the greatest   
  4. players of all time; his success on clay has earned him the nickname "The King of Clay", and   
  5. has prompted many experts to regard him as the greatest clay court player of all time. Some   
  6. of his best wins are:   
  7. Rome Masters - 5 titles in 6 years   
  8. Monte Carlo Masters - 7 consecutive titles (2005-2011)   
  9. Australian Open - Winner 2009   
  10. Roland Garros - Winnner 2005-2008, 2010, 2011   
  11. Wimbledon - Winner 2008, 2010   
  12. US Open - Winner 2010   
  13. Vamos Rafa!  



使用非缓冲流 

NIO.2 提供了使用非缓冲流的方法,可以用于直接读取或通过 java.io 的 API 封装成缓冲流使用。使用非缓冲流的方法是  Files.newInputStream() 和 Files.newOutputStream()。 

使用 newOutputStream() 方法 

newOutputStream() 参数为一个 Path 对象和一个可选的用于配置文件打开方式的 OpenOption 配置选项。它返回一个新的线程安全的非缓冲输出流 OutputStream。这个方法将打开文件用于写出(如果文件不存在将会创建文件)或者将已存在的文件截取为 0 字节。简短说来,这个方法默认情况下相当于使用了 CREATE、TRUNCATE_EXISTING、和 WRITE 的 OpenOption 属性。 

下面的代码将会写出 "Racquet: Babolat AeroPro Drive GT" 文本内容到文件 C: afaelnadalequipment acquet.txt,因为没有指定 OpenOption,所以文件不存的话会自动创建: 

Java代码  收藏代码
  1. Path rn_racquet = Paths.get("C:/rafaelnadal/equipment", "racquet.txt");   
  2. String racquet = "Racquet: Babolat AeroPro Drive GT";   
  3.    
  4. byte data[] = racquet.getBytes();   
  5. try (OutputStream outputStream = Files.newOutputStream(rn_racquet)) {   
  6.      outputStream.write(data);   
  7. catch (IOException e) {   
  8.      System.err.println(e);   
  9. }  



另外,如果你决定要使用缓冲流来取代非缓冲流,可以使用 java.io API 提供的方法。看看下面的代码,将会在 racquet.txt 文件(文件必须存在)后面添加“String: Babolat RPM Blast 16” 文本。 

Java代码  收藏代码
  1. Path rn_racquet = Paths.get("C:/rafaelnadal/equipment", "racquet.txt");   
  2. String string = " String: Babolat RPM Blast 16";      
  3.    
  4. try (OutputStream outputStream = Files.newOutputStream(rn_racquet, StandardOpenOption.APPEND);   
  5.      BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream))) {   
  6.       writer.write(string);   
  7. catch (IOException e) {   
  8.      System.err.println(e);   
  9. }  



使用  newInputStream() 方法 

newInputStream() 的参数为一个 Path 对象和一个可选的用于配置文件打开方式的 OpenOption 配置选项。它返回一个新的线程安全的 InputStream 对象。默认情况下,这个方法是用的是 OpenOption.READ 选项。 

下面的代码将读取 racquet.txt 文件(文件必须存在)的内容: 

Java代码  收藏代码
  1. Path rn_racquet = Paths.get("C:/rafaelnadal/equipment", "racquet.txt");   
  2. …   
  3. int n;        
  4. try (InputStream in = Files.newInputStream(rn_racquet)) {   
  5.      while ((n = in.read()) != -1) {   
  6.        System.out.print((char)n);                   
  7.     }   
  8. catch (IOException e) {   
  9.     System.err.println(e);   
  10. }  



你也可以使用 InputStream 的 read() 方法将数据读取到用于缓冲的字节数组中。你可以将上面的代码改写为(记住,你的处理对象依然是非缓冲输入流): 

Java代码  收藏代码
  1. Path rn_racquet = Paths.get("C:/rafaelnadal/equipment", "racquet.txt");   
  2. …   
  3. int n;        
  4. byte[] in_buffer = new byte[1024];   
  5. try (InputStream in = Files.newInputStream(rn_racquet)) {   
  6.      while ((n = in.read(in_buffer)) != -1) {   
  7.             System.out.println(new String(in_buffer));   
  8.      }   
  9. catch (IOException e) {   
  10.      System.err.println(e);   
  11. }  


注:调用 read(in_buffer) 方法和调用 read(in_buffer,0,in_buffer.length) 方法是同样的效果。 

你也可以通过 java.io API 将非缓冲输入流转换为缓冲输入流,下面的代码和上面的代码运行结果相同,但是更有效率: 

Java代码  收藏代码
  1. Path rn_racquet = Paths.get("C:/rafaelnadal/equipment", "racquet.txt");   
  2. …   
  3. try (InputStream in = Files.newInputStream(rn_racquet);   
  4.      BufferedReader reader = new BufferedReader(new InputStreamReader(in))) {   
  5.      String line = null;   
  6.      while ((line = reader.readLine()) != null) {   
  7.              System.out.println(line);   
  8.      }   
  9. catch (IOException e) {   
  10.      System.err.println(e);   
  11. }  



上面三段代码输出的结果都是相同的: 

Java代码  收藏代码
    1. Racquet: Babolat AeroPro Drive GT   
    2. String: Babolat RPM Blast 16  

免责声明:文章转载自《JavaNIO学习一》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇02 超级表、表格快速求和方法Linux ${} 变量内容的提取和替换功能等下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

3--Java NIO基础1

一、NIO概述 1. BIO带来的挑战 BIO即堵塞式I/O,数据在写入或读取时都有可能堵塞,一旦有堵塞,线程将失去CPU的使用权,性能较差。 2. NIO工作机制 Java NIO由Channel、Buffer、Selector三个核心组成,NIO框架类结构图如下: 其中,Buffer主要负责存取数据,Channel用于数据传输,获取数据,然后流入Bu...

Neety的基础使用及说明

BIO(缺乏弹性伸缩能力,并发量小,容易出现内存溢出,出现宕机每一个客户端对应一个线程 伪异步IO:创建线程池,由线程池里边的线程负责连接处理,M个个请求进来时,会在线程池创建N个线程。容易出现线程池阻塞。由一个线程池来处理客户端的请求。 NIO:异步非阻塞,服务器实现模式为一个请求一个线程,客户端发送的连接请求都会注册到多路复用器上,多路...

详解tomcat的连接数与线程池

前言 在使用tomcat时,经常会遇到连接数、线程数之类的配置问题,要真正理解这些概念,必须先了解Tomcat的连接器(Connector)。 在前面的文章详解Tomcat配置文件server.xml中写到过:Connector的主要功能,是接收连接请求,创建Request和Response对象用于和请求端交换数据;然后分配线程让Engine(也就是Ser...

客户端(springmvc)调用netty构建的nio服务端,获得响应后返回页面(同步响应)

后面考虑通过netty做一个真正意义的简约版RPC框架,今天先尝试通过正常调用逻辑调用netty构建的nio服务端并同步获得返回信息。为后面做铺垫 服务端实现 我们先完成服务端的逻辑,逻辑很简单,把客户端请求的内容加上服务器时间戳一并返回 public void run() throws InterruptedException { Ev...

Tomcat性能调优方案

web应用的并发提升,除了负载均衡。在小企业中也可以通过一些软件的上的设置来进行一些优化。下面是一些在服务器上修改tomcat参数的优化方法,非常简单实用!(这些方法通过网络整理的) 1,让Tomcat6 中支持Java语言的特性 NIO( New I/O) 引用 使用NIO在服务器端会有更好的性能,加强服务器端对并发处理的性能。 请注意:很抱歉,在to...

Netty Nio启动全流程

Netty Nio启动全流程 1. 各组件之间的关系 说明:EventLoopGroup类似线程池,EventLoop为单线程,每个EventLoop关联一个Nio Selector,用于注册Channel,形成一个EventLoop被多个channel公用。在EventLoop会执行通道Io选择操作,以及非Io任务。在Channel初始化后会创建pipe...