久しぶりに書いたらかなり忘れていたので、ここに残しておく。
Linux / macOS の場合
基本手順
- open でファイルを開く
- fstat でファイル サイズを取得
- mmap でメモリ上に写像
- メモリ上に出現したファイル(データ)にアクセスなど...
- munmap でメモリ上から消去
- close でファイルを閉じる
Windows の場合
基本手順
- CreateFileA / CreateFileW でファイル ハンドルを取得
- GetFileSizeEx でファイル サイズを取得
- CreateFileMappingA / CreateFileMappingW でマッピング用ハンドルを取得
- MapViewOfFile でメモリ上に写像
- メモリ上に出現したファイル(データ)にアクセスなど...
- UnmapViewOfFile でメモリ上から消去
- CloseHandle でマッピング用ハンドルとファイル ハンドルを閉じる
サンプルプログラム
読み取り専用で処理しています。
sample.cpp
#if !defined(_WINDOWS) && (_WIN32 || _WIN64)
#define _WINDOWS 1
#endif
#if _WINDOWS
#include <Windows.h>
#else
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#endif
#include <algorithm>
#include <iostream>
/*
* 読み取り専用でファイル全体をメモリ上に写像
*/
struct mapped_file
{
#if _WINDOWS
HANDLE m_hFile;
HANDLE m_hMap;
#else
int fd;
#endif
bool opened;
void *addr;
size_t size;
// コンストラクタ.
mapped_file(const char *path)
{
#if _WINDOWS
m_hFile = INVALID_HANDLE_VALUE;
m_hMap = NULL;
#else
fd = -1;
#endif
opened = false;
addr = NULL;
size = 0;
opened = open(path);
}
// デストラクタ.
~mapped_file()
{
close();
}
// ファイルを開いて、全体をメモリ上に写像する.
bool open(const char* path)
{
close();
#if _WINDOWS
// ファイルを開く.
m_hFile = ::CreateFileA(path,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (m_hFile == INVALID_HANDLE_VALUE)
return false;
// ファイル サイズを得る.
LARGE_INTEGER fsize;
if (!::GetFileSizeEx(m_hFile, &fsize))
{
close();
return false;
}
// ファイル サイズが 0 なら終了.
size = size_t((std::uint64_t(fsize.HighPart) << 32) + fsize.LowPart);
if (size == 0)
{
opened = true;
addr = NULL;
return true;
}
// ファイル写像オブジェクトを作る.
m_hMap = ::CreateFileMappingA(m_hFile,
NULL,
PAGE_READONLY,
fsize.HighPart,
fsize.LowPart,
NULL);
if (m_hMap == NULL)
{
close();
return false;
}
// メモリ上にファイル全体を写像.
addr = ::MapViewOfFile(m_hMap, FILE_MAP_READ, 0, 0, size);
if (addr == NULL)
{
close();
return false;
}
opened = true;
return true;
#else
// ファイルを開く.
fd = ::open(path, O_RDONLY);
if (fd < 0)
return false;
// ファイル サイズを得る.
struct stat stbuf;
if (::fstat(fd, &stbuf) < 0)
{
close();
return false;
}
// ファイル サイズが 0 なら終了.
size = size_t(stbuf.st_size);
if (size == 0)
{
opened = true;
return true;
}
// メモリ上にファイル全体を写像.
addr = ::mmap(NULL,
size,
PROT_READ,
MAP_FILE | MAP_PRIVATE,
fd,
0);
if (addr == MAP_FAILED)
{
close();
return false;
}
opened = true;
return true;
#endif
}
// 破棄.
void close()
{
#if _WINDOWS
if (size > 0 && !::UnmapViewOfFile(addr))
std::cerr << "error: UnmapViewOfFile" << std::endl;
if (m_hMap != NULL && !::CloseHandle(m_hMap))
std::cerr << "error: CloseHandle(m_hMap)" << std::endl;
if (m_hFile != INVALID_HANDLE_VALUE && !::CloseHandle(m_hFile))
std::cerr << "error: CloseHandle(m_hFile)" << std::endl;
m_hFile = INVALID_HANDLE_VALUE;
m_hMap = NULL;
#else
if (size > 0 && ::munmap(addr, size) < 0)
std::cerr << "error: munmap" << std::endl;
if (fd >= 0 && ::close(fd) < 0)
std::cerr << "error: close(" << fd << ")" << std::endl;
fd = -1;
#endif
opened = false;
addr = NULL;
size = 0;
}
};
/*
*
*/
int main(int argc, char** argv)
{
if (argc != 2)
{
std::cout << "Usage: " << argv[0] << " FILE" << std::endl;
return 1;
}
static const char hex[] = "0123456789abcdef";
const char* path = argv[1];
mapped_file file(path);
if (!file.opened)
{
std::cout << "open error: " << path << std::endl;
return 2;
}
// バイナリ出力.
std::cout << "File: " << path << std::endl
<< "Size: "
<< "0x" << std::hex << file.size << std::dec
<< " (" << file.size << ')' << std::endl;
int aw = 0;
for (size_t s = file.size - 1; s > 0; s >>= 4, aw += 4);
aw = std::max<int>(aw, 16) - 4;
const char* data = (const char*)file.addr;
for (size_t y = 0; y < file.size; y += 16)
{
size_t r = file.size - y;
size_t n = (r < 16) ? r : 16;
for (int b = aw; b >= 0; b -= 4)
std::cout << hex[(y >> b) & 15];
std::cout << ':';
for (size_t x = 0; x < n; ++x)
{
char d = data[y + x];
std::cout << ' ';
std::cout << hex[(d >> 4) & 15];
std::cout << hex[(d >> 0) & 15];
}
for (size_t x = n; x < 16; ++x)
std::cout << " ";
std::cout << " ";
for (size_t x = 0; x < n; ++x)
{
char d = data[y + x];
std::cout << ((0x20 <= d && d <= 0x7e) ? d : '.');
}
std::cout << std::endl;
}
return 0;
}
// Local Variables:
// c-basic-offset: 4
// indent-tabs-mode: nil
// tab-width: 4
// End:
実行結果
$ clang++ -O sample.cpp && ./a.out sample.cpp
File: sample.cpp
Size: 0x16e0 (5856)
0000: 23 69 66 20 21 64 65 66 69 6e 65 64 28 5f 57 49 #if !defined(_WI
0010: 4e 44 4f 57 53 29 20 26 26 20 28 5f 57 49 4e 33 NDOWS) && (_WIN3
0020: 32 20 7c 7c 20 5f 57 49 4e 36 34 29 0a 23 64 65 2 || _WIN64).#de
0030: 66 69 6e 65 20 5f 57 49 4e 44 4f 57 53 20 20 31 fine _WINDOWS 1
~~~(略)~~~
16c0: 64 65 3a 20 6e 69 6c 0a 2f 2f 20 74 61 62 2d 77 de: nil.// tab-w
16d0: 69 64 74 68 3a 20 34 0a 2f 2f 20 45 6e 64 3a 0a idth: 4.// End:.