C++-文件操作

前言

日常工作中,经常遇到对文件的读写,是最基本的工作单元;
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++文件操作类

待续未完成;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

黑山老妖的笔记本

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值