//声明:部分内容引自《Java编程思想(第四版)》机械工业出版社
【进程控制】
– 你经常会需要在 Java 内部执行其他操作系统的程序,并且要控制这些程序的输入和输出。Java 类库提供了执行这些操作的类。
【新 I/O】
– 转换数据。缓冲器容纳的是普通的字节,为了把它们转换成字符,我们要么在输入它们的时候对其进行编码,要么在将其从缓冲器输出时对它们进行解码。可以使用 java.nio.charset.Charset 类实现这些功能,该类提供了把数据编码成多种不同类型的字符集的工具。
例:
package io;//: io/AvailableCharSets.java
// Displays Charsets and aliases
import java.nio.charset.*;
import java.util.*;
import static net.mindview.util.Print.*;
public class AvailableCharSets {
public static void main(String[] args) {
SortedMap<String,Charset> charSets =
Charset.availableCharsets();
Iterator<String> it = charSets.keySet().iterator();
while(it.hasNext()) {
String csName = it.next();
printnb(csName);
Iterator aliases =
charSets.get(csName).aliases().iterator();
if(aliases.hasNext())
printnb(": ");
while(aliases.hasNext()) {
printnb(aliases.next());
if(aliases.hasNext())
printnb(", ");
}
print();
}
}
} /* Output:
Big5: csBig5
Big5-HKSCS: big5-hkscs, big5hk, big5-hkscs:unicode3.0, big5hkscs, Big5_HKSCS
EUC-JP: eucjis, x-eucjp, csEUCPkdFmtjapanese, eucjp, Extended_UNIX_Code_Packed_Format_for_Japanese, x-euc-jp, euc_jp
EUC-KR: ksc5601, 5601, ksc5601_1987, ksc_5601, ksc5601-1987, euc_kr, ks_c_5601-1987, euckr, csEUCKR
GB18030: gb18030-2000
GB2312: gb2312-1980, gb2312, EUC_CN, gb2312-80, euc-cn, euccn, x-EUC-CN
GBK: windows-936, CP936
...
*///:~
– 获取基本类型。
– 视图缓冲器。
– 字节存放次序。ByteBuffer 是以高位优先的形式存储数据的,并且数据在网上传送时也常常使用高位优先的形式。
例:(怎样通过字节存放模式设置来改变字符中的字节次序)
package io;//: io/Endians.java
// Endian differences and data storage.
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;
import static net.mindview.util.Print.print;
/**
* Created by JT on 2016/7/27.
*/
public class Endians {
public static void main(String[] args) {
ByteBuffer bb = ByteBuffer.wrap(new byte[12]);
bb.asCharBuffer().put("abcdef");
print(Arrays.toString(bb.array()));
bb.rewind();
bb.order(ByteOrder.BIG_ENDIAN);
bb.asCharBuffer().put("abcdef");
print(Arrays.toString(bb.array()));
bb.rewind();
bb.order(ByteOrder.LITTLE_ENDIAN);
bb.asCharBuffer().put("abcdef");
print(Arrays.toString(bb.array()));
}
}
ByteBuffer 有足够的空间,以存储作为外部缓冲器的 charArray 中的所有字节,因此可以调用 array() 方法显示视图底层的字节。array() 方法是“可选的”并且我们只能对由数组支持的缓冲器调用此方法,否则,将会抛出 UnsupportedOperationException。
通过调用 CharBuffer 视图可以将 charArray 插入到 ByteBuffer 中。在底层的字节被显示时,我们会发现默认次序和随后的高位优先次序相同,然而低位优先次序则与之相反,后者交换了这些字节次序。
– 用缓冲期操纵数据。
例如:如果想把一个字节数组写到文件中去,那么就应该使用 ByteBuffe.wrap() 方法把字节数组包装起来,然后用 getChannel() 方法在 FileOutputStream 上打开一个通道,接着将来自于 ByteBuffer 的数据写到 FileChannel 中。
注意,ByteBuffer 是将数据移进移出通道的唯一方式,并且我们只能创建一个独立的基本类型缓冲器,或者使用“as”方法从 ByteBuffer 中获得。也就是说,我们不能把基本类型的缓冲器转换成 ByteBuffer。然而,由于我们可以经由视图缓冲器将基本类型数据移进移出 ByteBuffer,所以这也就不是什么真正的限制了。
– 缓冲器的细节。
Buffer 由数据和可以高效地访问以及操纵这些数据的四个索引组成,这四个索引是:mark(标记),position(位置),limit(界限),capacity(容量)。在缓冲器中插入和提取数据的方法会更新这些索引,用于反应所发生的变化。
例(用到交换相邻字符的算法,以对 CharBuffer 中的字符进行编码和译码):
package io;//: io/UsingBuffers.java
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import static net.mindview.util.Print.print;
/**
* Created by JT on 2016/7/27.
*/
public class UsingBuffers {
private static void symmetricScramble(CharBuffer buffer) {
while (buffer.hasRemaining()) {
buffer.mark();
char c1 = buffer.get();
char c2 = buffer.get();
buffer.reset();
buffer.put(c2).put(c1);
}
}
public static void main(String[] args) {
char[] data = "UsingBuffers".toCharArray();
ByteBuffer bb = ByteBuffer.allocate(data.length * 2);
CharBuffer cb = bb.asCharBuffer();
cb.put(data);
print(cb.rewind());
symmetricScramble(cb);
print(cb.rewind());
symmetricScramble(cb);
print(cb.rewind());
}
}
– 内存映射文件。
内存映射文件允许我们创建和修改那些因为太大而不能放入内存的文件。有了内存映射文件,我们就可以假定整个文件都放在内存中,而且可以完全把它当作非常大的数组来访问。这种方法极大地简化了用于修改文件的代码。
package io;//: LargeMapFiles.java
// Creating a very large file using mapping.
// {RunByHand}
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import static net.mindview.util.Print.print;
import static net.mindview.util.Print.printnb;
/**
* Created by JT on 2016/7/27.
*/
public class LargeMappedFiles {
static int length = 0x8FFFFF; // 128MB
public static void main(String[] args) throws Exception {
MappedByteBuffer out = new RandomAccessFile("test.dat", "rw").getChannel().map(FileChannel.MapMode.READ_WRITE, 0, length);
for (int i = 0; i < length; i++)
out.put((byte)'x');
print("Finished writing");
for (int i = length/2; i < length/2 + 6; i++)
printnb((char)out.get(i));
}
}
为了既能写又能读,我们先由 RandomAccessFile 开始,获得该文件上的通道,然后调用 map() 产生 MappedByteBuffer,这是一种特殊类型的直接缓冲器。注意我们必须指定映射文件的初始位置和映射区域的长度,这意味着我们可以映射某个大文件的较小的部分。
“映射文件访问”可以更加显著地加快速度。
– 文件加锁。允许我们同步访问某个作为共享资源的文件。文件锁对其他的操作系统进程是可见的,因为 Java 的文件加锁直接映射到了本地操作系统的加锁工具。
例:
package io;//: io/FileLocking.java
import java.nio.channels.*;
import java.util.concurrent.*;
import java.io.*;
public class FileLocking {
public static void main(String[] args) throws Exception {
FileOutputStream fos= new FileOutputStream("file.txt");
FileLock fl = fos.getChannel().tryLock();
if(fl != null) {
System.out.println("Locked File");
TimeUnit.MILLISECONDS.sleep(100);
fl.release();
System.out.println("Released Lock");
}
fos.close();
}
} /* Output:
Locked File
Released Lock
*///:~
tryLock() 是非阻塞式的,它设法获取锁,但是如果不能获得,它将直接从方法调用返回。lock() 则是阻塞式的,它要阻塞进程直至锁可以获得,或调用 lock() 的线程中断,或调用 lock() 的通道关闭。使用 FileLock.release() 可以释放锁。
– 对映射文件的部分加锁。
【压缩】
– 用 GZIP 进行简单压缩。适合对单个数据流,而不是一系列互异数据进行压缩。
– 用 Zip 进行多文件保存。这个类库使用的是标准 Zip 格式,所以能与当前那些可通过因特网下载的压缩工具很好地协作。
– Java 档案文件。Zip 格式也被应用于 JAR(Java ARchive,Java 档案文件)文件格式中。这种文件格式就像 Zip 一样,可以将一组文件压缩到单个压缩文件中。
一个 JAR 文件由一组压缩文件构成,同时还有一张描述了所有这些文件的“文件清单”(可自行创建文件清单,也可以由 jar 程序自动生成)。
【对象序列化】
– Java 的对象序列化将那些实现了 Serializable 接口的对象转换成一个字节序列,并能够在以后将这个字节序列完全恢复为原来的对象。这一过程甚至可以通过网络进行,这意味着序列化机制能自动弥补不同操作系统之间的差异。
【XML】
– 对象序列化的限制:只有 Java 程序才可使用。解决方案:将数据转换成 XML 格式,可被各种平台和语言使用。
【Preferences】
– Preferences API 用于存储和读取用户的偏好以及程序配置项的设置。
– Preferences 是一个键-值集合(类似映射),存储在一个节点层次结构中。通常创建以你的类名命名的单一节点,然后将信息存储于其中。
【注意】
– ‘0’和‘O(大写o)’;
– ‘1’和‘l(小写 L)’;