您的位置:首页 > 编程语言 > Java开发

《Java编程思想》学习笔记14——I/O高级

2016-01-04 09:56 211 查看
1.内存映射文件:

内存映射文件允许把比内存大的文件读入内存中创建和修改,使用内存映射文件,可以像使用内存中数组一样在内存中访问整个文件,例子如下:

[java] view
plaincopy

import java.nio.*;

import java.nio.channels.*;

import java.io.*;

pulbic class MemoryMappedFile{

//十六进制,128MB大小

static int length = 0x8FFFFFF;

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’);

}

System.out.println(“Finished writing”);

for(int I = length/2; i < length/2 + 6; i++){

System.out.println((char)out.get(i));

}

}

}

MappedByteBuffer是直接字节缓冲区,其内容是文件的内存映射区域,映射的字节缓冲区和它所表示的文件映射关系在该缓冲区本身成为垃圾回收之前一直保持有效。

FileChannel的MappedByteBuffermap(FileChannel.MapMode mode, long position, long size) thorws IOException方法可以将此通道的文件区域直接映射到内存中。

可以通过以下三种模式将文件区域映射到内存中:

(1).只读:视图修改得到的缓冲区将导致抛出ReadOnlyBufferException。

(2).读/写:对得到的缓冲区的更改将最终传播到文件,该更改对映射到同一文件的其他程序不一定是可见的。

(3).专用:对的到的缓冲区更改将不会被传播到文件,并且该更改对映射到同一文件的其他程序也是不可见的,相反,会创建缓冲区已修改部分的专用副本。

创建映射时指定文件区域映射的起始位置和大小,因此,只有指定的部分才会被影响到内存的字节缓冲区中,而不再指定范围内的文件区域不会被映射到内存中,因此,对于大型文件来说,可以大大提高程序性能。

注意:映射关系一经创建,就不再依赖于创建它时所用的文件通道,特别是关闭该通道对映射关系的有效性没有任何影响。另外,从性能观点来讲,通常相对较大的文件映射到内存中才是值得的。

2.文件锁定:

在同一个JVM中,共享资源的文件可以通过线程同步来确保访问的安全性,但是在不同的JVM或者Java线程和操作系统本地线程共同竞争一个共享的文件资源时,就必须通过对文件的锁定机制来确保,例子如下:

[java] view
plaincopy

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”);

}

foc.close();

}

}

输出结果:

Locked File

Released Lock

文件通道的tryLock()方法试图获取对此通道的文件给定区域的锁定,是个非阻塞方法,无论是否已成功获得请求区域的锁定,调用总是立即返回。如果由于另一个程序保持这一个重叠锁而无法锁定,则此方法返回null.

文件锁定方法:

(1).FileLock tryLock():

试图获取对此通道文件的独占锁定。

(2).FileLock tryLock(long position, long size, Boolean shared):

视图获取对此通道文件给定区域的锁定。

(3).FileLock lock():

获取此通道的文件的独占锁定。

(4).FileLock lock(long position, long size, Boolean shared):

获取此通道的文件的给定区域锁定。

文件锁定方法是共享锁还是排斥锁取决于底层操作系统,可以使用FileLock.isShared()方法判断使用的是何种类型的文件锁。

3.压缩/解压缩:

Java I/O类库中提供了一些关于压缩和加压的类,由于压缩和解压缩算法是针对字节数据进行操作的,因此javaI/O中关于压缩和加压素的类是继承自InputStream和OutputStream字节流体系。

Java压缩和解压的相关类在java.util.zip包下,具体的类如下:

(1).CheckedInputStream:

需要维护所读取数据校验和的输入流,校验和可用于验证输入数据的完整性。

(2).CheckedOutputStream:

需要维护所写入数据校验和的输出流。

(3).Deflater:

使用流行的”ZLIB”压缩程序库为通用压缩提供支持。

(4).Inflater:

使用流行的”ZLIB”压缩程序库为通用解压缩提供支持。

(5).DeflaterInputStream:

为压缩“deflate“格式压缩数据实现输入流过滤器。

(6).DeflaterOutputStream:

为压缩 “deflate“格式压缩数据实现输出流过滤器,它还用作其他类型的压缩过滤器(如GZIPOutputStream)的基础。

(7).InflaterInputStream:

为解压缩”deflate”压缩格式的数据实现输入流过滤器,它还用作其他解压缩过滤器(如GZIPInputStream)的基础。

(8).InfaterOutputStream:

为解压缩“deflate”压缩格式存储数据实现输出流过滤器。

(9).ZipOutputStream:

为以”zip”文件格式写入文件实现输出流过滤器,包括对已压缩和未压缩条目的支持。

(10).ZipInputStream:

为读取以”zip”文件格式的文件实现输入流过滤器,包括对已压缩和未压缩条目的支持。

(11).GZIPOutputStram:

为使用“GZIP“文件格式写入压缩数据实现输出流过滤器。

(12).GZIPInputStram:

为读取“GZIP“文件格式的压缩数据实现输入流过滤器。

Java I/O压缩和解压缩操作小例子如下:

[java] view
plaincopy

import java.util.zip.*;

import java.io.*;

public class GZIPCompress{

public static void main(String[] args)throws IOException{

BufferedReader in = new BufferedReader(new FileReader(“test.dat”));

BufferedOutputStream out = new BufferedOutputStream(new GZIPOutputStream(

new FileOutputStream(“test.gz”)));

int c;

//写GZIP格式压缩文件

while((c = in.read()) != -1){

out.write(c);

}

in.close();

out.close();

BufferedReader in2 = new BufferedReader(new InputStreamReader(

new GZIPInputStream(new FileInputStream(“test.gz”))));

String s;

//读取GZIP格式压缩文件

while((s = in2.readLine()) != null){

System.out.println(s);

}

in2.close();

}

}

使用java中压缩相关类时,只需对输入流使用GZIPInputStream或ZipInputStream包装,对输出流使用GZIPOutputStream或ZipOutputStream包装即可,其他的操作和普通的java I.O操作相同。

4.使用zip多文件压缩:

zip格式的压缩文件是最常用的压缩方式,使用zip多文件压缩时,可以将多个文件压缩在一个压缩包中,同时还可以从一个包含多个文件的压缩包中读取所有的压缩文件。使用zip进行多文件压缩时,一般要使用CheckSum类计算校验和,校验和的计算有两种算法:

(1).Adler32:速度比较快。

(2).CRC32:速度比较慢,但是更精确。

使用zip多文件压缩的例子如下:

[java] view
plaincopy

import java.util.zip.*;

import java.io.*;

import java.util.*;

public class ZipCompress{

public static void main(String[] args)throws Exception{

FileOutputStream f = new FileOutputStream(“test.zip”);

//使用Adler32算法为文件输入流产生输出校验和文件

CheckedOutputStream csum = new CheckedOutputStream(f, new Adler32());

ZipOutputStream zos = new ZipOutputStream(csum);

BufferedOutputStream out = new BufferedOutputStream(zos);

//设置zip文件注释

zos.setComment(“A test of java zipping”);

//向zip压缩文件写入多个文件

for(String arg : args){

System.out.println(“Writing file:” + arg);

BufferedReader in = new BufferedReader(new FileReader(arg));

//写入一个zip文件条目,并将流定位到条目数据的开始处

zos.putNextEntry(new ZipEntry(arg));

int c;

//写入zip文件内容

while((c = in.read()) != -1){

out.write(c);

}

in.close();

out.flush();

}

out.close();

//文件关闭后获取校验和

System.out.println(“Checksum:” + csum.getChecksum().getValue());

FileInputStream fi = new FileInputStream(“test.zip”);

//使用Adler32算法为输入文件流产生输入校验和文件流

CheckedInputStream csumi = new CheckedInputStream(fi, new Adler32());

ZipInputStream in2 = new ZipInputStream(csumi);

BufferedInputStream bis = new BufferedInputStream(in2);

ZipEntry ze;

//读取zip文件条目

While((ze = in2.getNextEntry()) != null){

System.out.println(“Reading file:” + ze);

int x;

//读取zip文件条目内容

while((x = bis.read()) != -1){

System.out.println(x);

}

}

if(args.length == 1){

System.out.println(“Checksum:” + csumi.getChecksum().getValue());

}

bis.close();

//另一种读取zip文件的方法

ZipFile zf = new ZipFile(“test.zip”);

//获取zip文件的条目

Enumeration e = zf.entries();

while(e.hasMoreElements()){

ZipEntry ze2 = (ZipEntry)e.nextElement();

System.out.println(“Reading File:” + ze2);

}

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: