O_DIRECT方式读取文件示例
简介:
#include fcntl.h>
#include stdio.h>
#include stdlib.h>
#include sys/stat.
- #include fcntl.h>
- #include stdio.h>
- #include stdlib.h>
- #include sys/stat.h>
- #include sys/types.h>
- #include sys/time.h>
- #include unistd.h>
- #include glog/logging.h>
- #include gflags/gflags.h>
-
- // 读文件类
- class CFileReader
- {
- public:
- CFileReader()
- : _buffer(NULL)
- {
- }
-
- ~CFileReader()
- {
- free(_buffer);
- }
-
- bool open(const char* filepath)
- {
- // 以O_DIRECT方式打开文件
- int fd = ::open(filepath, O_RDONLY | O_DIRECT);
- if (-1 == fd)
- {
- LOG(ERROR) "open " filepath " error: " strerror(errno);
- return false;
- }
-
- // 取得文件大小,以便一次性将文件读取出来
- struct stat st;
- if (-1 == fstat(fd, &st))
- {
- LOG(ERROR) "stat " filepath " error: " strerror(errno);
- close(fd);
- return false;
- }
-
- // 分配足以容纳整个文件的Buffer
- // 由于以O_DIRECT方式读取,所以需要按页对齐
- size_t size = st.st_size + (getpagesize() - st.st_size%getpagesize());
- posix_memalign((void**)&_buffer, getpagesize(), size);
- if (NULL == _buffer)
- {
- LOG(ERROR) "malloc failed";
- close(fd);
- return false;
- }
-
- // 将整个文件读取_buffer中
- int bytes_read = read(fd, _buffer, size);
- if (-1 == bytes_read)
- {
- LOG(ERROR) "read " filepath " error: " strerror(errno);
- close(fd);
- free(_buffer);
- _buffer = NULL;
- return false;
- }
- else if (bytes_read != size)
- {
- // 两组测试输出数据:
- // FileSize(212000000) => AlignSize(212000768) -> RealSize(212000000)
- // FileSize(2120000000) => AlignSize(2120003584) -> RealSize(2120000000)
- printf("FileSize(%d) => AlignSize(%d) -> RealSize(%d)\n", st.st_size, size, bytes_read);
- }
-
- return true;
- }
-
- // 从文件中读取一个节点数据
- // offset:偏移量
- // return:返回指向记录的指针
- template class P>
- const P* get_record(uint64_t offset) const
- {
- return reinterpret_castP*>(_buffer + offset);
- }
-
- // 取得文件所有的记录
- template class P>
- const P** get_all_record() const
- {
- return reinterpret_castP**>(_buffer);
- }
-
- private:
- char* _buffer;
- };
-
- // 用于计时
- class TimeWatcher
- {
- public:
- TimeWatcher(const std::string& tip)
- : _tip(tip)
- {
- struct timeval now;
- gettimeofday(&now, NULL);
-
- _now_msec = (now.tv_sec * 1000) + (now.tv_usec / 1000);
- }
-
- ~TimeWatcher()
- {
- struct timeval now;
- gettimeofday(&now, NULL);
-
- time_t cur_msec = (now.tv_sec * 1000) + (now.tv_usec / 1000);
- LOG(INFO) _tip " spend " cur_msec - _now_msec "ms";
- }
-
- private:
- std::string _tip;
- time_t _now_msec;
- };
-
- struct User
- {
- int32_t age;
- int32_t hight;
- int32_t weight;
- char bitmap[50*4];
- };
-
-
- // 用于生成测试文件
- bool make_test_file(const char* filepath, int num_records)
- {
- int fd = open(filepath, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
- if (-1 == fd)
- {
- LOG(ERROR) "open " filepath " error: " strerror(errno);
- return false;
- }
-
- User user;
- TimeWatcher time_watcher("write");
-
- for (int i=0; inum_records; ++i)
- {
- user.age = i;
- user.hight = i + i;
- user.weight = i * i;
-
- if (-1 == write(fd, &user, sizeof(user)))
- {
- LOG(ERROR) "write " filepath " error: " strerror(errno);
- close(fd);
- return false;
- }
- }
-
- close(fd);
- return true;
- }
-
- // 模拟随机读取
- void random_read(const CFileReader& file_reader, int num_random)
- {
- int *index = new int[num_random];
-
- for (int i=0; inum_random; ++i)
- {
- srandom(time(NULL));
- index[i] = random() % num_random;
- }
-
-
- TimeWatcher time_watcher("randmon read");
- for (int i=0; inum_random; ++i)
- {
- file_reader.get_recordstruct User>(index[i]);
- }
- }
-
- // 执行测试
- void test()
- {
- int num_records1 = 1000000;
- int num_records2 = 10000000;
- std::string file1 = "./file_1000000";
- std::string file2 = "./file_10000000";
-
- if (make_test_file(file1.c_str(), 1000000)
- && make_test_file(file2.c_str(), 10000000))
- {
- printf("to read, press ENTER to continue ...\n");
- getchar();
-
- CFileReader file_reader1;
-
- {
- TimeWatcher time_watcher("open");
- if (!file_reader1.open(file1.c_str()))
- {
- return;
- }
- }
-
- random_read(file_reader1, 1000000);
- random_read(file_reader1, 3000000);
-
- CFileReader file_reader2;
-
- {
- TimeWatcher time_watcher("open");
- if (!file_reader2.open(file2.c_str()))
- {
- return;
- }
- }
-
- random_read(file_reader2, 1000000);
- random_read(file_reader2, 3000000);
- }
- }
-
- int main(int argc, char* argv[])
- {
- test();
- return 0;
- }