linux下的RandomAccessFile类
备注:以下写得基本上是胡说八道,(但是不想删除)请阅读此页面的朋友换个页面或者换个博客浏览,谢谢-----飞羽飞之猪
当遇到以下情况
1 当读写大于内存大小的文件
2 当不想加载整个文件而需要读写文件某部分
Java的RandomAccessFile可能非常实用和方便
此类的实例支持对随机访问文件的读取和写入。随机访问文件的行为类似存储在文件系统中的一个大型 byte 数组。存在指向该隐含数组的光标或索引,称为文件指针;输入操作从文件指针开始读取字节,并随着对字节的读取而前移此文件指针。如果随机访问文件以读取/写入模式创建,则输出操作也可用;输出操作从文件指针开始写入字节,并随着对字节的写入而前移此文件指针。写入隐含数组的当前末尾之后的输出操作导致该数组扩展。该文件指针可以通过 getFilePointer 方法读取,并通过 seek 方法设置。
如果在linux下面要实现这样的功能,可以使用mmap(系统调用)
下面首先介绍下mmap的使用,并写出一个简单的用mmap实现的RandomAccessFile的C++类,以满足用C++解决一开始提到的两种情况的需要。
mmap介绍
mmap例子
RandomAccessFile的C++实现
#######################################################################################
mmap介绍
mmap的定义:
void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);
函数参数解析:
参数fd为即将映射到进程空间的文件描述字,一般由open()返回.
len是映射到调用进程地址空间的字节数,它从被映射文件开头offset个字节开始算起。
prot参数指定共享内存的访问权限。可取如下几个值的或:PROT_READ(可读),PROT_WRITE(可写),PROT_EXEC(可执行),PROT_NONE(不可访问)。
flags由以下几个常值指定:MAP_SHARED, MAP_PRIVATE, MAP_FIXED。其中,MAP_SHARED,MAP_PRIVATE必选其一,而MAP_FIXED则不推荐使用。
offset参数一般设为0,表示从文件头开始映射。
参数addr指定文件应被映射到进程空间的起始地址,一般被指定一个空指针,此时选择起始地址的任务留给内核来完成。函数的返回值为最后文件映射到进程空间的地址,进程可直接操作起始地址为该值的有效地址。
########################################################################################
mmap例子
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
int main()
{
//mmap第五个参数fd就是调用open()获得的,如果为-1则打开文件失败
int fd;
if ( (fd = open("./file", O_RDWR|O_CREAT, S_IRWXU)) < 0){
printf("open file wrong!");
return 1;
}
//mmap第二个参数len就是调用fstat()获得的,正常情况下不应该返回-1
struct stat file_stat;
if ( fstat( fd, &file_stat) < 0 )
{
printf(" fstat wrong");
return 1;
}
//mmap第一个参数一般为NULL,详情见上面的mmap参数说明
//mmap最六个参数为文件起始映射处,一般为0表示文件开始
void *start_fp;
if( ( start_fp = mmap(NULL, file_stat.st_size, PROT_READ, MAP_SHARED, fd, 0 )) == MAP_FAILED)
{
printf("mmap wrong");
return 1;
}
//
snprintf( (char *)start_fp, 4, "test");
msync( start_fp, file_stat.st_size, MS_ASYNC);
//munmap类似与Java的RandomAccessFile的close()函数,关闭文件映射功能。参数为映射返回的void*指针和映射文件长度,可以把它当成一般IO功能的关闭功能。
if ( munmap( start_fp, file_stat.st_size ) < 0 )
{
printf("munmap wrong");
return 1;
}
}
内存映射的一般步骤:
用open系统调用打开文件, 并返回描述符fd.
用mmap建立内存映射, 并返回映射首地址指针start.
对映射(文件)进行各种操作, 显示(printf), 修改(sprintf).
用munmap(void *start, size_t lenght)关闭内存映射.
用close系统调用关闭文件fd.
############################################################################
RandomAccessFile的C++实现
下面是用mmap的一个RandomAccessFile的C++类实现,封装一些看上去"不怎么友好"的代码.
这个类只实现了读取char的功能,没有实现类似Java的RandomAccessFile可以读取任意类型的数据的功能。
在centos5,g++ 4.1.2 环境下测试可用
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
//081125 snail
class RandomAccessFile
{
public:
RandomAccessFile(const char* filePath);
~RandomAccessFile();
bool isOpen()
{
return open_ok;
}
long length()
{
long size = 0;
if (open_ok)
{
size = m_file_stat.st_size;
}
return size;
}
void seek(long pos)
{
if (pos > m_file_stat.st_size)
{
pos = m_file_stat.st_size;
}
m_offset = pos;
}
char readChar()
{
return m_file[m_offset];
}
const char* getError()
{
return m_error;
}
private:
bool open_ok;//RamomAccessFile is prepared ok
char* m_file;//if is prepared ok,m_file stands for handle of RandomAccessFile
char* m_error;//if is not prepared ok,m_error stands for error message
struct stat m_file_stat;//stands for info of file which to be RandomAccess
long m_offset;//offset to start of file
};
RandomAccessFile::RandomAccessFile(const char* filePath) :
m_offset(0), open_ok(true)
{
int fd;
if ((fd = open("./file", O_RDWR | O_CREAT, S_IRWXU)) < 0)
{
m_error = "open file wrong!";
open_ok = false;;
}
if (open_ok)
{
if (fstat(fd, &m_file_stat) < 0)
{
m_error = "fstat wrong";
open_ok = false;
}
}
if (open_ok)
{
if ((m_file = (char*) mmap(NULL, m_file_stat.st_size, PROT_READ,
MAP_SHARED, fd, m_offset)) == MAP_FAILED)
{
m_error = "mmap wrong";
open_ok = false;
}
}
}
RandomAccessFile::~RandomAccessFile()
{
if (open_ok)
{
if (munmap(m_file, m_file_stat.st_size) < 0)
{
printf("munmap wrong");
}
}
}
int main()
{
RandomAccessFile* raf = new RandomAccessFile("./file");
if (raf->isOpen())
{
//printf("randomaccess file is prepared!/n");
printf("raf length()-->%d/n", raf->length());
raf->seek(0);
printf("%c/n", raf->readChar());
}
else
{
printf(raf->getError());
}
delete raf;
}
#############################################################################
参考:
http://blog.csdn.net/dai_weitao/archive/2007/07/25/1707559.aspx
http://blog.csdn.net/eroswang/archive/2007/11/30/1908842.aspx
http://blog.csai.cn/user1/16820/archives/2008/25456.html