FileUtil用来操作文件。AppendFile用来写日志,使用的fopen函数;ReadSmallFile使用open函数用来读取linux内核的一些信息。
FileUtil.h
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
// Author: Shuo Chen (chenshuo at chenshuo dot com)
//
// This is a public header file, it must only include public header files.
#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, //读入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;//64K
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 : 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];//64K
off_t writtenBytes_;
};
} // namespace FileUtil
} // namespace muduo
#endif // MUDUO_BASE_FILEUTIL_H
FileUtil.cc
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
//
// Author: Shuo Chen (chenshuo at chenshuo dot com)
#include "muduo/base/FileUtil.h"
#include "muduo/base/Logging.h"
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
using namespace muduo;
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);//将日志写入文件中
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_);
}
//fopen有缓冲,open是没有缓冲
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)
{
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;//fstat函数用来 获取文件(普通文件,目录,管道,socket,字符,块()的属性
//fstat 通过文件描述符获取文件对应的属性
if (::fstat(fd_, &statbuf) == 0)//fstat用来获取文件大小,保存到缓冲区当中
{
if (S_ISREG(statbuf.st_mode))
{
*fileSize = statbuf.st_size;//stat结构体中有st_size参数就是文件大小,串给输入参数指针
content->reserve(static_cast<int>(std::min(implicit_cast<int64_t>(maxSize), *fileSize)));
}
else if (S_ISDIR(statbuf.st_mode))//S_ISDIR功能是判断一个路径是否为目录
{
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;
}
int FileUtil::ReadSmallFile::readToBuffer(int* size)
{
int err = err_;
if (fd_ >= 0)
{
ssize_t n = ::pread(fd_, buf_, sizeof(buf_)-1, 0);
if (n >= 0)
{
if (size)
{
*size = static_cast<int>(n);//static_cast强制类型转换
}
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*);