class ReadSmallFile : boost::noncopyable
{
public:
ReadSmallFile(StringArg filename);
~ReadSmallFile();
// return errno
template<typename String>
int readToString(int maxSize,//最大的长度
String* content,//dest
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,//读取文件,是对ReadSmallFile的一个包装。
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 : boost::noncopyable
{
public:
explicit AppendFile(StringArg filename);
~AppendFile();
void append(const char* logline, const size_t len);
void flush();
size_t writtenBytes() const { return writtenBytes_; }
private:
size_t write(const char* logline, size_t len);
FILE* fp_;
char buffer_[64*1024];
size_t writtenBytes_;
};
FileUtil::AppendFile::AppendFile(StringArg filename)
: fp_(::fopen(filename.c_str(), "ae")), // 'e' for O_CLOEXEC//这里用了fopen
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);//调用fwrite
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_);
}
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,//将文件读到content
String* content,
int64_t* fileSize,
int64_t* modifyTime,
int64_t* createTime)
{
BOOST_STATIC_ASSERT(sizeof(off_t) == 8);
assert(content != NULL);
int err = err_;
if (fd_ >= 0)
{
content->clear();
if (fileSize)//那为什么content就不检查呢?
{
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)));//预留大小。取文件和可读的max的min
}
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)//读出n字节后,追加到content
{
content->append(buf_, n);
}
else//n==0表示读到文件末尾
{
if (n < 0)//出错
{
err = errno;
}
break;
}
}
}
return err;
}
int FileUtil::ReadSmallFile::readToBuffer(int* size)
{
int err = err_;
if (fd_ >= 0)
{
ssize_t n = ::pread(fd_, buf_, sizeof(buf_)-1, 0);//读文件到buf,size是实际读出的大小。@4是文件偏移游标。
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*);
#ifndef MUDUO_STD_STRING
template int FileUtil::readFile(StringArg filename,
int maxSize,
std::string* content,
int64_t*, int64_t*, int64_t*);
template int FileUtil::ReadSmallFile::readToString(
int maxSize,
std::string* content,
int64_t*, int64_t*, int64_t*);
#endif