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指定檔案應被映射到進程空間的起始地址,一般被指定一個null 指標,此時選擇起始地址的任務留給核心來完成。函數的傳回值為最後檔案對應到進程空間的地址,進程可直接操作起始地址為該值的有效地址。
########################################################################################
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