前言
日常工作中,经常遇到对文件的读写,是最基本的工作单元;
C++中对文件读写,一般使用FILE(C语言)和 ifstream/ofstream/fstream(C++);
在这里记录下工作中常用用法;
一、C语言文件读写
主要使用了C标准库的<stdio.h>
提供了多个文件操作的接口函数;
有如下:
1.文件打开: FILE *fopen(const char *filename, const char *mode);
2.文件关闭:int fclose(FILE *stream);
3.文件定位:int fseek(FILE *stream, long offset, int fromwhere);
4.文件读取:size_t fread( void *restrict buffer, size_t size, size_t count, FILE *restrict stream );
5.文件写入:size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
6.获取当前文件操作位置:long ftell(FILE *stream);
7.检测流上的文件结束符:int feof(FILE *stream);
1.1文件操作类
由于在使用FILE时,需要自己打开文件,使用结束后关闭文件;工作中往往遇到异常或者错误时,FILE*指针指向的对象没有释放,造成句柄泄漏;又由于部分项目使用C99的标准,还不支持使用C++11的智能指针,也没有必要为了这个小功能而引入boost库;
参照RAII(Resource Acquisition Is Initialization)“资源获取就是初始化”,写了一个操作文件的类;
1.1.1 源码
代码如下:
#pragma once
#include <string>
#include <exception>
#include <memory>
#define nullptr NULL
namespace Tool
{
#define READ_BINARY "rb"
#define WRITE_BINARY "wb"
#define WRITE_ADD_BINARY "ab+"
#define SIZE_ONE_BUF 1024
#define ERROR -1
#define ONE_ITEM 1
#define ZERO 0
#ifdef _CRT_SECURE_NO_WARNINGS
#define FOPEN_(pFile, file_name, read_write_mode) pFile = fopen(file_name, read_write_mode)
#else
#define FOPEN_(pFile, file_name, read_write_mode) fopen_s(&pFile, file_name, read_write_mode)
#endif // _CRT_SECURE_NO_WARNINGS
class FileOpenException :public std::exception
{
public:
FileOpenException() :context("") {}
FileOpenException(std::string context) :context(context) {}
const char* what() const throw()
{
std::string text = "Error! The file open failed!" + context + "\n";
return text.c_str();
}
private:
std::string context;
};
class File_ptr
{
FILE *pfile_;
size_t size_;
public:
static size_t GetFileSize(std::string file_path)
{
File_ptr in_file(file_path, READ_BINARY);
return in_file.GetFileSize();
}
public:
File_ptr() :pfile_(nullptr), size_(ERROR) {}
File_ptr(FILE* pp) :pfile_(pp), size_(ERROR) {}
File_ptr(const char* pFileName, const char *pMode) :size_(ERROR)
{
FOPEN_(pfile_, pFileName, pMode);
if (pfile_ == nullptr)
{
throw FileOpenException(pFileName);
}
}
File_ptr(std::string fileName, const char *pMode) :size_(ERROR)
{
FOPEN_(pfile_, fileName.c_str(), pMode);
if (pfile_ == nullptr)
{
throw FileOpenException(fileName);
}
}
void SetPath(std::string fileName, const char *pMode)
{
this->size_ = ERROR;
FOPEN_(pfile_, fileName.c_str(), pMode);
if (pfile_ == nullptr)
{
throw FileOpenException(fileName);
}
}
~File_ptr() { Close(); }
void Close()
{
if (pfile_ != nullptr)
{
fclose(pfile_);
pfile_ = nullptr;
}
}
bool IsAvailable() { return pfile_ != nullptr; }
bool IsEof() { return feof(pfile_) != ZERO; }
size_t SetOffset(int offset, int offset_mode)
{
size_t beforePos = ftell(pfile_);
fseek(pfile_, offset, offset_mode);
return beforePos;
}
int GetCurrentOffset()
{
return ftell(pfile_);
}
std::string GetLine()
{
char buf[SIZE_ONE_BUF] = { ZERO };
memset(buf, 0, SIZE_ONE_BUF);
fgets(buf, SIZE_ONE_BUF, pfile_);
return std::string(buf);
}
size_t GetFileSize()
{
if (size_ == -1)
{
size_ = GetRemainingSize();
}
return size_;
}
size_t GetRemainingSize()
{
int remainingSize = ZERO;
int curPos = ftell(pfile_);
fseek(pfile_, ZERO, SEEK_END);
remainingSize = ftell(pfile_);
fseek(pfile_, curPos, SEEK_SET);
return remainingSize;
}
operator FILE*() { return pfile_; }
template<typename T>
void SetNext(T value)
{
fwrite(&value, sizeof(T), ONE_ITEM, pfile_);
}
template<typename T>
void SetNext(T* value)
{
fwrite(value, sizeof(T), ONE_ITEM, pfile_);
}
template<>
void SetNext<std::string>(std::string content)
{
fwrite(content.c_str(), ONE_ITEM, strlen(content.c_str()), pfile_);
}
template<typename T>
T GetNext()
{
T value(ZERO);
fread(&value, sizeof(T), ONE_ITEM, pfile_);
return value;
}
template<typename T>
size_t SetNextBuf(T* pInbuf, size_t size = ONE_ITEM)
{
return fwrite(pInbuf, sizeof(T), size, pfile_);
}
template<typename T>
void SetNextBuf_InShortType(T* pInbuf, size_t size)
{
short* pTmpBuf = new short[size];
for (size_t i = 0; i < size; i++)
{
pTmpBuf[i] = pInbuf[i];
}
fwrite(pTmpBuf, sizeof(short), size, pfile_);
delete[] pTmpBuf;
}
template<typename T>
size_t GetNextBuf(T* pBuf, size_t size = ONE_ITEM)
{
memset(pBuf, 0, sizeof(T)*size);
return fread(pBuf, sizeof(T), size, pfile_);
}
template<typename T>
size_t GetNextBuf(std::shared_ptr<T> pBuf, size_t size = ONE_ITEM)
{
memset(pBuf.get(), ZERO, sizeof(T)*size);
return fread(pBuf.get(), sizeof(T), size, pfile_);
}
};
}
注意:由于没有将拷贝构造函数和赋值构造函数设置为private;在File_ptr对象进行赋值时的崩溃,不过我一般不会做这种操作,暂时没有对这个东西进行修改;
1.1.2 调用实例
列举几个常用的函数,其他函数自己代码,应该也能知道是怎么了,不再赘述;
1.1.2.1 打开文件
使用构造函数,传入要操作的文件名称和对应的模式,如果文件为空或者被其他程序占用,构造函数会throw异常;
#define READ_BINARY "rb"// 读操作
#define WRITE_BINARY "wb"// 写操作
#define WRITE_ADD_BINARY "ab+"// 追加读写操作
File_ptr(std::string fileName, const char *pMode)
1.1.2.2 关闭文件
可以手动调用Close函数,也可以在File_ptr对象作用域和生存周期结束后,自动关闭;
void Close()
1.1.2.3 获取文件大小
size_t GetFileSize()
1.1.2.4 设置文件操作位置
size_t SetOffset(int offset, int offset_mode)
offset_mode 有三种模式:SEEK_SET/SEEK_CUR/SEEK_END;
SEEK_SET:从文件开始位置开始,移动offset个字节;
SEEK_CUR:从文件当前位置开始,移动offset个字节;
SEEK_END:从文件结束位置开始,移动offset个字节;
offset可正可负;
1.1.2.5 读取文件
// 写入一个T类型的变量
template<typename T>void SetNext(T value);
// 写入一个T*指向的变量
template<typename T>void SetNext(T* value);
// 写入一个字符串
template<>void SetNext<std::string>(std::string content);
// 写入一个缓存区,如果个数没有指定,则默认为1;
template<typename T>size_t SetNextBuf(T* pBuf, size_t size = ONE_ITEM);
// 写入一个缓存区,转换为short类型存入文件;
template<typename T>void SetNextBuf_InShortType(T* pInbuf, size_t size);
1.1.2.6 写入文件
// 从文件中,读取一个T类型的值;
template<typename T>T GetNext();
// 从文件中,读取一个缓存区,默认个数为1;
template<typename T>size_t GetNextBuf(T* pBuf, size_t size = ONE_ITEM);
// 从文件中,使用智能指针,读取一个T类型的值;
template<typename T>size_t GetNextBuf(std::shared_ptr<T> pBuf, size_t size = ONE_ITEM);
1.1.2.7 实际使用例子
File_ptr in_file("F:\\rect.dat", READ_BINARY);
size_t in_size = in_file.GetFileSize() / sizeof(short);
short* pInBuf = new short[in_size] {0};
in_file.GetNextBuf(pInBuf, in_size);
int age = in_file.GetNext<int>();
char sex = in_file.GetNext<char>();
File_ptr out_file("F:\\out.dat", WRITE_BINARY);
out_file.SetNextBuf(pInBuf, in_size);
out_file.SetNext(age);
out_file.SetNext(sex);
二、C++文件操作类
待续未完成;