muduo源码解析12-fileutil命名空间
fileutil命名空间
fileutil命名空间主要是实现了对于文件的一系列操作
设计实现了两个类:ReadSmallFile和AppendFile
分别用于对文件的读和写操作
注意之前没有使用stringspiece头文件中的定义
因此所有用到stringpiece的东西全部换成std::string即可
ReadSmallFile类:
这个类主要就是实现了对于文件的读操作,可以把文件数据读到string中,也可以保存到类内部字符数组中去。
主要是关于文件操作的一些函数
ReadSmallFile成员变量:
private: int m_fd; //文件描述符 int m_err; //错误码 char m_buf[kBufferSize]; //保存数据的数组
//类中数组的大小
static const int kBufferSize=60*1024;
需要注意最多只能读64KB的数据,超过64KB就只读64KB,因为内部字符数组大小有限
ReadSmallFile成员函数:
public: ReadSmallFile(string filename); ~ReadSmallFile(); //把文件数据读到content中去,文件大小保存到filesize,修改时间保存到 //modifyTime,创建时间保存到createTime template<typename string> int readToString(int maxsize,string* content,int64_t* filesize, int64_t* modifyTime,int64_t* createTime); //把文件读到缓冲区中去,实际上读到类内部m_buf数组中去 int readToBuffer(int* size); //返回类中m_buf数组 const char* buffer() const;
构造函数里打开文件,析构函数里关闭文件。
AppendFile类:
这个类就与上面的那个类相对应,上面是读文件,这个就是写文件,只提供了最简单的append操作,就是把数据追加到文件尾部。
AppendFile成员变量:
private: FILE* m_fp; //文件指针 char m_buffer[64*1024]; //保存数据 off_t m_writtenBytes; //已经写入的字节数
搞不懂为啥又使用fopen,fclose等函数了,跟上面的open,close文件操作函数不一样了。。不过功能没啥区别
AppendFile成员函数:
public: //构造函数,打开一个文件 explicit AppendFile(string filename); //关闭文件 ~AppendFile(); //向文件中写logline,长度为len void append(const char* logline,size_t len); //::fflush(m_fp) void flush(); //返回已经写入文件的字节数 off_t writtenBytes() const {return m_writtenBytes;} private: //使用fwrite_unlocked来实现写文件 size_t write(const char* logline,size_t len);
同样是构造函数里打开文件,析构函数里关闭文件,只提供了文件尾部追加数据,和清空缓冲区的操作。
fileutil头文件:
/* fileutil命名空间主要是实现了对于文件的一系列操作 设计实现了两个类:ReadSmallFile和AppendFile 分别用于对文件的读和写操作 之前没有使用stringspiece头文件中的定义 因此所有用到stringpiece的东西全部换成std::string即可 */ #ifndef FILEUTIL_H #define FILEUTIL_H #include"base/types.h" #include"base/noncopyable.h" //#include"base/stringpiece.h" //stringpiece舍弃不用了,自己用std::string来实现欠缺的功能 namespace mymuduo { namespace fileutil { //顾名思义,读取小文件的类 class ReadSmallFile:noncopyable { public: ReadSmallFile(string filename); ~ReadSmallFile(); //把文件数据读到content中去,文件大小保存到filesize,修改时间保存到 //modifyTime,创建时间保存到createTime template<typename string> int readToString(int maxsize,string* content,int64_t* filesize, int64_t* modifyTime,int64_t* createTime); //把文件读到缓冲区中去,实际上读到类内部m_buf数组中去 int readToBuffer(int* size); //返回类中m_buf数组 const char* buffer() const; //类中数组的大小 static const int kBufferSize=60*1024; private: int m_fd; //文件描述符 int m_err; //错误码 char m_buf[kBufferSize]; //保存数据的数组 }; //利用ReadSmallFile中的readToString函数完成readFile函数 template<typename string> int readFile(string 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); } class AppendFile:noncopyable { public: //构造函数,打开一个文件 explicit AppendFile(string filename); //关闭文件 ~AppendFile(); //向文件中写logline,长度为len void append(const char* logline,size_t len); //::fflush(m_fp) void flush(); //返回已经写入文件的字节数 off_t writtenBytes() const {return m_writtenBytes;} private: //使用fwrite_unlocked来实现写文件 size_t write(const char* logline,size_t len); FILE* m_fp; //文件指针 char m_buffer[64*1024]; //保存数据 off_t m_writtenBytes; //已经写入的字节数 }; }//namespace fileutil }//namespace mymuduo #endif // FILEUTIL_H
fileutil源文件:
#include "fileutil.h" #include"base/logging.h" #include<assert.h> #include<errno.h> #include<fcntl.h> #include<stdio.h> #include<sys/stat.h> #include<unistd.h> namespace mymuduo{ namespace fileutil { //构造函数中执行open打开文件操作 ReadSmallFile::ReadSmallFile(string filename) :m_fd(::open(filename.data(),O_RDONLY|O_CLOEXEC)),m_err(0) { m_buf[0]='\0'; //文件若是打开失败,设置错误码信息 if(m_fd<0) m_err=errno; } //析构函数中关闭文件 ReadSmallFile::~ReadSmallFile() { if(m_fd) ::close(m_fd); } //把文件数据读入到content中,大小保存到filesize,修改时间保存到modifyTime //创建时间保存到createTime template <typename string> int ReadSmallFile::readToString(int maxsize,string* content, int64_t* filesize,int64_t* modifyTime,int64_t* createTime) { static_assert (sizeof(off_t)==8,"_FILE_OFFSET_BITS = 64" ); assert(content!=NULL);//保证可以传入到content中 if(m_fd<0) return m_err; //保证文件描述符正确 int err=m_err; //返回值err,可根据判断是否出错 content->clear(); //先清空缓冲区 if(filesize) //保证filesize不是NULL,可以传入 { //该结构体用于获取文件信息,文件大小,修改时间,创建时间等信息 struct stat statbuf; if(::fstat(m_fd,&statbuf)==0) //获取文件信息 { if(S_ISREG(statbuf.st_mode)) //是否是一个常规文件 { *filesize=statbuf.st_size; //保存文件大小 //重新分配一下string的内存空间,保证为min(maxsize,*filesize) 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; } //开始拷贝文件数据到string中 while(content->size()<implicit_cast<size_t>(maxsize)) { //一次要读取的数据量=min(maxsize-content->size(),60*1024) size_t toRead=std::min(implicit_cast<size_t>(maxsize)-content->size(), sizeof(m_buf)); //实际读取了n个字节的数据量 ssize_t n=::read(m_fd,m_buf,toRead); if(n>0) content->append(m_buf,n); else { if(n<0)err=errno; break; } } return err; //返回状态信息,可判断是否有出错 } int ReadSmallFile::readToBuffer(int *size) { int err=m_err; if(m_fd<=0)return err; ssize_t n=::pread(m_fd,m_buf,sizeof (m_buf)-1,0); if(n>=0) { if(size) *size=static_cast<int>(n);//保存大小 m_buf[n]='\0';//数组最后结束符'\0' }else err=errno; return err; } AppendFile::AppendFile(string filename) :m_fp(::fopen(filename.data(),"ae")), //e for O_CLOEXEC m_writtenBytes(0) { assert(m_fp); //保证写入的文件确实存在 ::setbuffer(m_fp,m_buffer,sizeof(m_buffer)); } AppendFile::~AppendFile() { ::fclose(m_fp); } void AppendFile::append(const char *logline, size_t len) { //实际写入了n个字节 size_t n=write(logline,len); size_t remain=len-n; //剩余remain个字节 while(remain>0) //保证全部写入 { size_t x=write(logline+n,remain); if(x==0) { int err=ferror(m_fp); if(err) fprintf(stderr, "AppendFile::append() failed %s\n", strerror_tl(err)); break; } n+=x; remain=len-n; } m_writtenBytes+=len; } void AppendFile::flush() { ::fflush(m_fp); } size_t AppendFile::write(const char *logline, size_t len) { return ::fwrite_unlocked(logline,1,len,m_fp); } //提供了两个模板 template int readFile(string filename,int maxSize,string* content, int64_t* ,int64_t*,int64_t*); template int ReadSmallFile::readToString(int maxSize,string* content,int64_t*, int64_t*,int64_t*); }//namespace fileutil }//namespace mymuduo
测试:
#include"base/fileutil.h" #include<iostream> using namespace std; namespace mymuduo{ namespace currentthread { void cacheTid() { } } } int main() { //添加数据到文件./test.txt中 /*mymuduo::fileutil::AppendFile apf("./test.txt"); string data="stat 结构定义于:/usr/include/sys/stat.h 文件中"; apf.append(data.data(),data.size()); */ //从./test.txt中读取数据 mymuduo::fileutil::ReadSmallFile rdf("./test.txt"); string strbuf; int64_t filesize=0,modifyTime=0,createTime=0; rdf.readToString(64*1024,&strbuf,&filesize,&modifyTime,&createTime); std::cout<<strbuf<<std::endl<<filesize<<" "<< modifyTime<<" "<<createTime<<std::endl; std::cout<<"over...\n"; }
需要注意,只有在apf对象和rdf对象析构时文件才能正确关闭,这两个类都没有提供close函数,只允许在对象析构时关闭文件。

浙公网安备 33010602011771号