muduo FileUtil

文章目录
  1. 1. AppendFile
  2. 2. ReadSmallFile
  3. 3. 参考资料
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#ifndef MUDUO_BASE_FILEUTIL_H
#define MUDUO_BASE_FILEUTIL_H

#include "muduo/base/noncopyable.h"
#include "muduo/base/StringPiece.h"
#include <sys/types.h> // for off_t

namespace muduo
{
namespace FileUtil
{

// read small file < 64KB
class ReadSmallFile : noncopyable
{
public:
ReadSmallFile(StringArg filename);
~ReadSmallFile();

// return errno
template<typename String>
int readToString(int maxSize,
String* content,
int64_t* fileSize,
int64_t* modifyTime,
int64_t* createTime);

/// Read at maxium kBufferSize into buf_
// return errno
int readToBuffer(int* size);

const char* buffer() const { return buf_; }

static const int kBufferSize = 64*1024;

private:
int fd_;
int err_;
char buf_[kBufferSize];
};

// read the file content, returns errno if error happens.
template<typename String>
int readFile(StringArg filename,
int maxSize,
String* content,
int64_t* fileSize = NULL,
int64_t* modifyTime = NULL,
int64_t* createTime = NULL)
{
ReadSmallFile file(filename);
return file.readToString(maxSize, content, fileSize, modifyTime, createTime);
}

// not thread safe
class AppendFile : noncopyable
{
public:
explicit AppendFile(StringArg filename);

~AppendFile();

void append(const char* logline, size_t len);

void flush();

off_t writtenBytes() const { return writtenBytes_; }

private:

size_t write(const char* logline, size_t len);

FILE* fp_;
char buffer_[64*1024];
off_t writtenBytes_;
};

} // namespace FileUtil
} // namespace muduo

#endif // MUDUO_BASE_FILEUTIL_H

AppendFile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
FileUtil::AppendFile::AppendFile(StringArg filename)
: fp_(::fopen(filename.c_str(), "ae")), // 'e' for O_CLOEXEC 'a' 表示追加
writtenBytes_(0)
{
assert(fp_);
::setbuffer(fp_, buffer_, sizeof buffer_);
// posix_fadvise POSIX_FADV_DONTNEED ?
}

FileUtil::AppendFile::~AppendFile()
{
::fclose(fp_);
}

void FileUtil::AppendFile::append(const char* logline, const size_t len)
{
// 写入文件
size_t n = write(logline, len);
size_t remain = len - n;
while (remain > 0)
{
size_t x = write(logline + n, remain);
// 写入失败
if (x == 0)
{
int err = ferror(fp_);
if (err)
{
fprintf(stderr, "AppendFile::append() failed %s\n", strerror_tl(err));
}
break;
}
// 继续写入
n += x;
remain = len - n; // remain -= x
}
// 更新已经写入的总字节数
writtenBytes_ += len;
}

// 刷新文件流
void FileUtil::AppendFile::flush()
{
::fflush(fp_);
}

size_t FileUtil::AppendFile::write(const char* logline, size_t len)
{
// #undef fwrite_unlocked
// 写文件的不加锁版本,线程不安全
return ::fwrite_unlocked(logline, 1, len, fp_);
}

ReadSmallFile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
FileUtil::ReadSmallFile::ReadSmallFile(StringArg filename)
: fd_(::open(filename.c_str(), O_RDONLY | O_CLOEXEC)), // 只读 打开文件并记录文件描述符
err_(0)
{
// 清空缓冲区
buf_[0] = '\0';
if (fd_ < 0)
{
err_ = errno;
}
}

FileUtil::ReadSmallFile::~ReadSmallFile()
{
if (fd_ >= 0)
{
::close(fd_); // FIXME: check EINTR
}
}

// return errno
template<typename String>
int FileUtil::ReadSmallFile::readToString(int maxSize,
String* content,
int64_t* fileSize,
int64_t* modifyTime,
int64_t* createTime)
{
// 判断是否占 8 位
static_assert(sizeof(off_t) == 8, "_FILE_OFFSET_BITS = 64");
assert(content != NULL);
int err = err_;
if (fd_ >= 0)
{
content->clear();

if (fileSize)
{
// 获取文件信息
struct stat statbuf;
if (::fstat(fd_, &statbuf) == 0)
{ // 是否是常规文件
if (S_ISREG(statbuf.st_mode))
{
// 获得文件大小
*fileSize = statbuf.st_size;
// 申请空间
content->reserve(static_cast<int>(std::min(implicit_cast<int64_t>(maxSize), *fileSize)));
}
else if (S_ISDIR(statbuf.st_mode)) // 是目录
{
err = EISDIR;
}
if (modifyTime) // 更新时间
{
*modifyTime = statbuf.st_mtime;
}
if (createTime) // 创建时间
{
*createTime = statbuf.st_ctime;
}
}
else
{
err = errno;
}
}

while (content->size() < implicit_cast<size_t>(maxSize))
{
// 要读的字节数
size_t toRead = std::min(implicit_cast<size_t>(maxSize) - content->size(), sizeof(buf_));
ssize_t n = ::read(fd_, buf_, toRead);
if (n > 0)
{
content->append(buf_, n);
}
else
{
if (n < 0)
{
err = errno;
}
break;
}
}
}
return err;
}


// 将文件内容读入缓冲区, 将文件大小赋值给 size
int FileUtil::ReadSmallFile::readToBuffer(int* size)
{
int err = err_;
if (fd_ >= 0)
{
//pread() reads up to count bytes from file descriptor fd at offset offset (from the start of the
//file) into the buffer starting at buf. The file offset is not changed.
ssize_t n = ::pread(fd_, buf_, sizeof(buf_)-1, 0);
if (n >= 0)
{
if (size)
{
*size = static_cast<int>(n);
}
buf_[n] = '\0';
}
else
{
err = errno;
}
}
return err;
}

template int FileUtil::readFile(StringArg filename,
int maxSize,
string* content,
int64_t*, int64_t*, int64_t*);

template int FileUtil::ReadSmallFile::readToString(
int maxSize,
string* content,
int64_t*, int64_t*, int64_t*);

参考资料