`
airu
  • 浏览: 267516 次
  • 性别: Icon_minigender_1
  • 来自: 云南
社区版块
存档分类
最新评论

学习JavaNIO-文件内存映射

 
阅读更多
...文件映射有个需要注意的问题,就是你无法确保他被释放了。
也就是只有映射的内存被回收,文件才会被释放。否则其他进程访问就是被锁状态。
所以这个对于一个进程一个文件。如果多个进程访问一个文件,还是不是很适合。

最近看了文件内存映射。在NIO中,使用起来很方便。
文件通过内存映射以后,访问速度自然是提高了。
当然也有很多问题,现在我们来看看NIO中的内存映射文件。

public abstract class FileChannel extends 
AbstractChannel implements ByteChannel, GatheringByteChannel, ScatteringByteChannel {
 // This is a partial API listing
public abstract MappedByteBuffer map (MapMode mode, long position,long size) 
public static class MapMode { 
	public static final MapMode READ_ONLY 
	public static final MapMode READ_WRITE 
	public static final MapMode PRIVATE 
	} 
}


内存映射文件,是通过一个FileChannel来完成的,返回的MappedByteBuffer,也是一种ByteBuffer。这里有三种映射模式。主要针对这三种映射模式的差异说说。

根据map函数,我们得知,我们可以映射部分文件,也可以全部映射。
如果请求的大小,size超出文件,那么文件会相应的增长以对应映射。如果是Integer.MAX_VALUE,那么文件就会达到2.1GB
当然,如果你请求的只是一个只读文件,而你的size超出文件大小,那么就会抛出IOException。
对于 MapMode的前两种,READ_ONLY和READ_WRITE来说,都很好理解。要注意的而是,如果在一个只读文件上使用READ_WRITE,是要抛出NonWritableChannelException异常的。
MapMode.PRIVATE模式很有意思,称为“写时拷贝”(copy-on-write)的映射。这是操作系统中常用的技术。比如创建一个子进程时,子进程共享父进程的地址空间,当子进程修改空间的时候,才会拷贝要修改的部分。对于PRIVATE模式来说,只有使用put函数的时候,才会去拷贝。可能拷贝某一页或者几页。假设此时有其他的映射,是看不到本次put后的改变的。也就是说,私有的。

注意,没有unmap函数,也就是说,一旦map成功,那么即使FileChannel被关闭,映射依然存在,只有映射对应的MappedByteBuffer内存被回收,映射才算取消。

MappedByteBuffer直接反应磁盘文件,如果磁盘文件结构或大小改变,那么可能就无法访问文件。
MappedByteBuffer 直接内存访问,并不占用虚拟机内存。
MappedByteBuffer 也是ByteBuffer,所以可以用于SocketChannel之类的通道读写。
对于MappedByteBuffer还有几个函数可以介绍下。
public abstract class MappedByteBuffer extends ByteBuffer { 
// This is a partial API listing 
public final MappedByteBuffer load( ) 
public final boolean isLoaded( ) 
public final MappedByteBuffer force( ) 
}

load函数用于从磁盘文件加载到内存。这个操作将会引起大量系统调用。慎用。一旦加载完成,再次访问文件,就和访问内存一样快。但是,这些都起决于操作系统底层调用。

isLoaded函数是用来判断文件是否完全加载到内存。

force则是强制同步内存文件到磁盘。也就是把MappedByteBuffer中的更改应用到磁盘中。这里包括了文件的元数据(最近一次访问,作者,创建时间等)。当然,如果是READ_ONLY或者PRIVATE模式,则不起作用。

下面这个例子,使用内存映射文件,生成一个HTTP应答格式的文件。我们来看看这个例子:
package shaoxin.nio;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URLConnection;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;

/***
 * Dummy HTTP server using MappedByteBuffer.
 * Given a filename on the command line, pretend to be 
 * a web server and generate an HTTP response containing
 * the file content preceded by appropriate headers The
 * data is send with a gathering write.
 * 
 * @author Ron Hitchens (ron@ronsoft.com)
 *
 */
public class MappedHttp {
	private static final String OUTPUT_FILE="MappedHttp.out";
	private static final String LINE_SEP = "\r\n";
	private static final String SERVER_ID = "Server: Ronsoft Dummy Server";
	private static final String HTTP_HDR = 
		"HTTP/1.0 200 OK" + LINE_SEP + SERVER_ID + LINE_SEP;
	private static final String HTTP_404_HDR = 
		"HTTP/1.0 404 Not Found" + LINE_SEP + SERVER_ID + LINE_SEP;
	private static final String MSG_404 = "Cound not open file: ";
	public static void main(String[] args) throws Exception{
		if(args.length < 1){
			System.err.println("Usage:filename");
			return;
		}
		
		String file = args[0];
		ByteBuffer header = ByteBuffer.wrap(bytes(HTTP_HDR));
		ByteBuffer dynhdrs = ByteBuffer.allocate(128);
		ByteBuffer[] gather = {header,dynhdrs,null};
		String contentType = "unknown/unknown";
		long contentLength = -1;
		try{
			FileInputStream fis = new FileInputStream(file);
			FileChannel fc = fis.getChannel();
			MappedByteBuffer filedata = 
				fc.map(MapMode.READ_ONLY, 0, fc.size());
			gather[2] = filedata;
			contentLength = fc.size();
			contentType = URLConnection.guessContentTypeFromName(file);
		}catch(IOException e){
			//file could not be opend; report problem
			ByteBuffer buf = ByteBuffer.allocate(128);
			String msg = MSG_404 + LINE_SEP;
			buf.put(bytes(msg));
			buf.flip();
			//Use the HTTP error response
			gather[0] = ByteBuffer.wrap(bytes(HTTP_404_HDR));
			gather[2] = buf;
			contentLength = msg.length();
			contentType = "text/plain";
		}
		
		StringBuffer sb = new StringBuffer();
		sb.append("Content-Length: " + contentLength);
		sb.append(LINE_SEP);
		sb.append("Content-Type: ").append(contentType);
		sb.append(LINE_SEP).append(LINE_SEP);
		dynhdrs.put(bytes(sb.toString()));
		dynhdrs.flip();
		
		FileOutputStream fos = new FileOutputStream(OUTPUT_FILE);
		FileChannel out = fos.getChannel();
		// All the buffers have been prepared , write them out
		while(out.write(gather) > 0){
			//Empty body; loop until all buffers are empty			
		}
		out.close();
		System.out.println("output written to "+ OUTPUT_FILE);
	}
	
	//Convert a String to its constituent bytes
	//from the ASCII character set
	private static byte[] bytes(String string)throws Exception {
		return (string.getBytes("US-ASCII"));
	}
}



这里结合使用了scatter/gather技术。
0
0
分享到:
评论

相关推荐

    Java NIO 应用使用内存映射文件实现进程间通信

    Java NIO 应用 -- 使用内存映射文件实现进程间通信

    java nio中文版

    java NIO是 java New IO 的简称,在 jdk1.4 里提供的新 api 。...– 支持锁和内存映射文件的文件访问接口。 – 提供多路 (non-bloking) 非阻塞式的高伸缩性网络 I/O 。 本文档将围绕这几个特性进行学习和介绍。

    nio.rar_FastCopyFile.java_NIO_UseFloatBuffer.java_java nio_文件锁

    Java NIO 源码适合初学者,里面包括通道和Buffer的基本适用,以及文件锁,和内存文件映射等等

    文件快速加密

    但是,Java实现采用了多线程、NIO以及内存文件映射,其速度要远远超过Python版实现。 实测结果:加密大小为1G的文件,Java版耗时为3秒左右,而Python版则需要8分钟左右,而且还可能会出现内存溢出错误。 Java版本:...

    尚硅谷Java视频_NIO 视频教程

    尚硅谷_NIO_通道的数据传输与内存映射文件 ·06. 尚硅谷_NIO_分散读取与聚集写入 ·07. 尚硅谷_NIO_字符集 Charset ·08. 尚硅谷_NIO_阻塞与非阻塞 ·09. 尚硅谷_NIO_阻塞式 ·10. 尚硅谷_NIO_非阻塞式 ·11. ...

    Java性能优化之使用NIO提升性能(Buffer和Channel)

    在软件系统中,由于IO的速度要比内存慢,因此,I/O读写在很多场合都会成为系统的瓶颈。提升I/O速度,对提升系统整体性能有着很大的好处。...支持锁和内存映射文件的文件访问接口;提供了基于Selector的异步网

    Java NIO与IO的差别和比较

    当中还提供了一个特殊类用于内存映射文件的I/O操作。  2. Charset:它提供Unicode字符串影射到字节序列以及逆影射的操作。  3. Channels:包括socket,file和pipe三种管道,它实际上是双向交流的通道。  

    nio:Clojure对java.nio的支持

    还定义了函数mmap来对文件进行内存映射。 此外,还有三个函数buffer-seq,buffer-nth和buffer-to-array,旨在使将java.nio类集成到Clojure中更加容易。 希望通过将它们的功能滚动到clojure.core中,它们将变得过时...

    mmfinvoker:简单的进程间 java 请求-响应库

    mmfinvoker 这是一个简单的 java 库,它使用 nio.MappedByteBuffer 在内存映射文件上实现请求/响应功能。

    JAVA上百实例源码以及开源项目

     Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、输出错误信息等Java编程小技巧。 Java数组倒置...

    JAVA上百实例源码以及开源项目源代码

     Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、输出错误信息等Java编程小技巧。 Java数组倒置...

    javabitset源码-javaewah:JavaBitSet类的压缩替代品

    还支持内存映射文件:我们可以将位图序​​列化到磁盘,然后使用 java.nio 类将它们映射到内存。 这可以避免浪费的序列化/反序列化例程。 该库还提供了标准 BitSet 类的替代品。 与 JavaEWAH 中的其他位图类一样,这...

    百度地图开发java源码-inertiaSearch:挑战赛

    百度地图开发java源码 tmp #inertiaSearch 2016年写的代码,现在觉得思路有很多提升的地方,但是毕竟努力过,还是贴在Readme.md 里面 ...对于原始的数据文件做内存映射,并做对应索引,所有索引做hash

    java开源包10

    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...

    java开源包1

    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...

    java开源包11

    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...

    java开源包6

    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...

    java开源包9

    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...

    java开源包5

    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...

Global site tag (gtag.js) - Google Analytics