在前面五名已经学习了四篇关于NIO系列的文章:
核心概念及基本读写 、缓冲区内部实现机制 、连网和异步IO 、缓冲区更多特性及分散/聚集IO ,
这里我们继续探讨和学习有关文件锁定和字符集相关的内容。
9. 文件锁定
1) 概述:
文件锁定初看起来可能让人迷惑。它似乎指的是防止程序或者用户访问特定文件。事实上,文件锁就像常规的Java对象锁,它们是“劝告式”的(advisory)锁。它们不阻止任何形式的数据访问,相反,它们通过锁的共享和获取赖允许系统的不同部分相互协调。
您可以锁定整个文件或者文件的一部分。如果您获取一个排它锁,那么其他人就不能获得同一个文件或者文件的一部分上的锁。如果您获得一个共享锁,那么其他人可以获得同一个文件或者文件一部分上的共享锁,但是不能获得排它锁。文件锁定并不总是出于保护数据的目的。例如,您可能临时锁定一个文件以保证特定 的写操作成为原子的,而不会有其他程序的干扰。
大多数操作系统提供了文件系统锁,但是它们并不都是采用同样的方式。有些实现提供了共享锁,而另一些仅提供了排它锁。事实上,有些实现使得文件的锁 定部分不可访问,尽管大多数实现不是这样的。
在这里,我们将学习如何在 NIO 中执行简单的文件锁过程,还将探讨一些保证被锁定的文件尽可能可移植的方法。
2) 锁定文件:
要获取文件的一部分上的锁,您要调用一个打开的FileChannel上的lock()方法。注意,如果要获取一个排它锁,您必须以写方式打开文件。
RandomAccessFile raf = new RandomAccessFile( "usefilelocks.txt", "rw" );
FileChannel fc = raf.getChannel();
FileLock lock = fc.lock( start, end, false );
在拥有锁之后,您可以执行需要的任何敏感操作,然后再释放锁:
lock.release();
在释放锁后,尝试获得锁的其他任何程序都有机会获得它。
本附件的例子程序UseFileLocks.java必须与它自己并行运行。这个程序获取一个文件上的锁,持有三秒钟,然后释放它。如果同时运行这个程序的多个实例,您会看到每个实例依次获得锁。
3) 文件锁定和可移植性:
文件锁定可能是一个复杂的操作,特别是考虑到 不同的操作系统是以不同的方式实现锁这一事实。下面的指导原则将帮助您尽可能保持代码的可移植性:
i 只使用排它锁。
ii将所有的锁视为劝告式的(advisory)。
10. 字符集
1) 概述:
根据Sun的文档,一个Charset是“十六位Unicode字符序列与字节序列之间的一个命名的映射”。实际上,一个Charset允许您以尽可能最具可移植性的方式读写字符序列。
Java语言被定义为基于Unicode。然而在实际上,许多人编写代码时都假设一个字符在磁盘上或者在网络流中用一个字节表示。这种假设在许多情况下成立,但是并不是在所有情况下都成立,而且随着计算机变得对Unicode越来越友好,这个假设就日益变得不能成立了。
在这里,我们将看一下如何使用Charsets以适合现代文本格式的方式处理文本数据。这里将使用的示例程序相当简单,不过,它触及了使用Charset的所有关键方面:为给定的字符编码创建Charset,以及使用该Charset解码和编码文本数据。
2) 编码/解码:
要读和写文本,我们要分别使用CharsetDecoder和CharsetEncoder。将它们称为“编码器”和“解码器” 是有道理的。一个字符不再表示一个特定的位模式,而是表示字符系统中的一个实体。因此,由某个实际的位模式表示的字符必须以某种特定的编码来表示。
CharsetDecoder用于将逐位表示的一串字符转换为具体的char值。同样,一个CharsetEncoder用于将字符转换回位。
3) 处理文本的正确方式:
现在我们将分析这个例子程序UseCharsets.java。这个程序非常简单:它从一个文件中读取一些文本,并将该文本写入另一个文件。但是它把该数据当作文本数据,并使用CharBuffer来将该数句读入一个CharsetDecoder中。同样,它使用CharsetEncoder来写回该数据。
我们将假设字符以ISO-8859-1(Latin1)字符集(这是ASCII的标准扩展)的形式储存在磁盘上。尽管我们必须为使用Unicode做好准备,但是也必须认识到不同的文件是以不同的格式储存的,而ASCII无疑是非常普遍的一种格式。事实上,每种Java实现都要求对以下字符编码提供完全的支持:
US-ASCII
ISO-8859-1
UTF-8
UTF-16BE
UTF-16LE
UTF-16
4) 示例程序:
在打开相应的文件、将输入数据读入名为inputData的ByteBuffer之后,我们的程序必须创建ISO-8859-1字符集的一个实例:
Charset latin1 = Charset.forName( "ISO-8859-1" );
然后,创建一个解码器(用于读取)和一个编码器 (用于写入):
CharsetDecoder decoder = latin1.newDecoder();
CharsetEncoder encoder = latin1.newEncoder();
为了将字节数据解码为一组字符,我们把ByteBuffer传递给CharsetDecoder, 结果得到一个CharBuffer:
CharBuffer cb = decoder.decode( inputData );
如果想要处理字符,我们可以在程序的此处进行。但是我们只想无改变地将它写回,所以没有什么要做的。
要写回数据,我们必须使用CharsetEncoder将它转换回字节:
ByteBuffer outputData = encoder.encode( cb );
在转换完成之后,我们就可以将数据写到文件中了。
11. 结束语和参考资料
正如您所看到的,NIO库有大量的特性。在一些新特性(例如文件锁定和字符集)提供新功能的同时,许多特性在优化方面也非常优秀。
在基础层次上,通道和缓冲区可以做的事情几乎都可以用原来的面向流的类来完成。但是通道和缓冲区允许以快得多的方式完成这些相同的旧操作,事实上接近系统所允许的最大速度。
不过NIO最强大的长度之一在于,它提供了一种在Java语言中执行进行输入/输出的新的(也是迫切需要的)结构化方式。随诸如缓冲区、通道和异步I/O这些概念性(且可实现的)实体而来的,是我们重新思考Java程序中的I/O过程的机会。这样,NIO甚至为我们最熟悉的I/O过程也带来了新的活力,同时赋予我们通过和以前不同并且更好的方式执行它们的机会。
本系列教程的整理参考了IBM developerworks 中国社区关于NIO的一些学习资料。
分享到:
相关推荐
### NIO学习与总结 #### 一、NIO概述与核心概念 **NIO(New IO)**,即新输入/输出...此外,NIO还提供了一系列高级特性,如文件锁定、字符集转换、分散/聚集IO等,使得开发者能够更加灵活地处理各种复杂的I/O问题。
#### 文件锁定和字符集 为了确保文件的安全访问,NIO提供了文件锁定机制,允许应用程序在文件上设置锁,防止其他进程同时访问同一部分文件。此外,NIO还支持对字符集的转换,使得在处理不同编码格式的文本数据时...
Java NIO提供了FileChannel,支持文件的读写、映射和文件锁定等操作。例如,可以使用transferTo()和transferFrom()方法在两个通道之间高效地传输数据。 6. **内存映射文件(Memory-Mapped File)**: 这是一种...
5. **字符集转换**:NIO的Charset类支持各种字符编码的转换,解决了跨平台的字符编码问题。 6. **管道(Pipes)**:在NIO中,Pipe提供了一种单向的数据传输通道,用于在两个线程之间传递数据。 7. **多路复用...
Java NIO 还提供了一组工具来处理字符集的编码和解码,包括: - **`Charset`**:定义了字符集编码和解码的类。 - **`CharsetEncoder`** 和 **`CharsetDecoder`**:在字节和 Unicode 字符之间进行转换。 #### 实现...
书中的内容涵盖了NIO的新特性,基础和高级I/O概念,二进制I/O和新的缓冲区类,内存映射文件和文件锁定,字符I/O:包括编码、解码和转换字符数据,正则表达式以及新的`java.util.regex`包,以及使用`java.nio`进行多...
- **文件锁和内存映射**:支持文件锁定和内存映射技术,增强数据安全性并提高性能。 - **多路复用的非阻塞IO**:允许单个线程管理多个并发连接,大幅提升了网络IO的可扩展性。 #### 二、Buffer & Channel(缓冲区与...
5. **字符集(Charsets)**:NIO扩展了字符集的支持,提供了更多的编码和解码选项,使得跨平台的文本处理更为方便。 6. **scatter/gather I/O**:scatter/gather I/O允许数据从多个缓冲区读取或写入一个通道,或者...
8. **字符集转换(Charset)**:NIO提供了更完善的字符集支持,可以方便地进行不同字符编码的转换。 9. **异步I/O(Asynchronous File I/O)**:Java 7引入了异步文件I/O,允许在后台线程中执行I/O操作,而不阻塞...
深入了解 Java NIO 的高级特性,如直接缓冲区、异步 I/O 和文件锁定等。这些特性能够帮助开发者构建更加高效和健壮的应用程序。 ##### 4. 实际项目应用 最后,在实际项目中应用所学的 NIO 技术。可以通过重构现有...
5. **字符集转换**:NIO中的Charset类处理字符编码和解码,使得在不同字符集之间进行转换变得更加简单。 6. **管道(Pipes)**:管道用于两个线程之间的单向通信。一个线程写入数据到管道,另一个线程可以从管道中...
- NIO中的Charset类和CharsetDecoder/CharsetEncoder用于处理字符编码和解码,支持多种字符集,如UTF-8、GBK等。 6. **管道(Pipes)** - 管道是两个线程之间的单向数据连接。一个线程写入的数据可以被另一个线程...
7. **字符集转换**:NIO中的Charset类和CharsetDecoder/CharsetEncoder提供了字符编码和解码的功能,支持各种字符集,使得跨平台的文本处理变得更加方便。 8. **Scattering and Gathering(分散与聚集)**:NIO支持...
在处理文本数据时,NIO还提供了一系列字符集编码和解码的方法,如Charset、CharsetDecoder和CharsetEncoder等,帮助开发者轻松应对不同语言环境下的文本处理需求,实现应用程序的国际化。 九、总结与资源推荐 总之...
10. **文件锁定**:在多线程环境中,可能需要对文件进行锁定以防止并发访问导致的数据不一致。Java的`FileLock`接口可以实现文件锁。 11. **临时文件**:`java.io.TempFile`类可以帮助创建临时文件,它们在程序结束...