linux下的RandomAccessFile类

来源:互联网 发布:redis写入mysql 编辑:程序博客网 时间:2024/05/24 06:50

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