文件操作的几种方式
使用CRT函数
文件操作可以使用C语言运行时库来完成,CRT提供的fxxx()函数如下表所示
函数 | 含义 |
---|---|
fopen | 打开指定文件名的文件 |
fclose | 关闭文件 |
fwrite | 向文件写入指定的数据 |
fread | 从文件中读取指定长度的数据 |
fgetc | 从文本文件中读取一个字符 |
fgets | 从文件文件中读取一串字符 |
fputc | 向文本文件写入一个字符 |
fputs | 向文本文件中写入一个字符串 |
feof | 判断文件是否到达文件结尾 |
ftell | 获得当前位置相对于文件首的位移,该位移值等于文件所含字节数 |
fseek | 移到文件的某一个特殊位置 |
FILE* fopen(const char* filename, const char* mode)
标志 | 含义 |
---|---|
r | 读模式,如果文件不存在则会失败 |
w | 写模式,如果文件已存在则会清空其内容 |
a | 追加模式,写入的内容追加在原有内容之后,如果文件不存在则会自动创建 |
r+ | 读写模式(文件必须存在) |
w+ | 读写模式,如果文件已存在则会清空其内容 |
a+ | 读+追加模式 |
t | 文本方式 |
b | 二进制方式 |
ccs=ENCODING | 文件编码方式,可指定ENCODING=UTF-8、UTF-16LE、UNICODE |
//以读写方式,UNICODE编码打开某文件
FILE* fp = fopen("filename.txt", "rw, ccs=UNICODE");
使用C++标准库std::fstream
和文件有关系的输入/输出类主要在头文件中被定义,ifstream, ofstream, fstream
ofstream out("test.out");
out << "hello world!";
fstream提供的文件操作函数
函数 | 含义 |
---|---|
open | 打开文件 |
close | 关闭文件 |
is_open | 判断当前文件是否打开 |
//open函数的原型
void open
(
const char* filename,
ios_base::openmode mode = ios_base::in|ios_base::out,
int _Port = (int)ios_base::_Openprot
);
void open
(
const char* filename,//wchar_t
ios_base::openmode mode
);
ios_base::openmode标志
标志 | 含义 |
---|---|
ios::app | 追加模式,新输出的内容就追加在原文件内容的后面 |
ios::ate | 文件打开后定位到文件尾,ios::app就包含此属性 |
ios::binary | 二进制方式打开文件,默认是文本方式 |
ios::in | 文件以输入方式打开 |
ios::out | 文件以输出方式打开 |
ios::trunc | 阶段模式,如果文件存在就把文件长度设置为0 |
ios::nocreate | 如果文件不存在就不创建 |
ios_noreplace | 如果文件已存在则不替换 |
一般fstream进行文件操作的流程为
- 调用
fstream::fopen()
创建打开文件 - 通过流操作,使用fstream完成输入输出,如
out << "hello world!";
- 调用
fstream::close()
关闭文件
使用WINDOWS API
个人感觉使用windows api去读写文件太笨重了
函数 | 含义 |
---|---|
CreateFile | 创建,打开文件,返回文件句柄 |
CloseHandle | 关闭文件句柄 |
ReadFile | 从文件中读取数据 |
WriteFile | 向文件中写入数据 |
SetFilePointer | 设置文件读写指针 |
LockFile | 锁定文件 |
UnlockFile | 解锁文件 |
CopyFile | 赋值指定文件的源文件到新命名的文件 |
DeleteFile | 删除文件 |
MoveFile | 移动文件 |
ReplaceFile | 替换文件,并指定是否备份 |
GetFileAttirbutes | 获取文件的属性 |
GetFileSize | 获取文件的大小 |
GetFileType | 获取文件的类型 |
GetFullPathName | 获取文件的完整路径名 |
SearchPath | 在指定路径下搜索满足条件的文件 |
FindFirstFile | 查找符合指定名称的第一个文件 |
FindNextFile | 查找符合指定名称的下一个文件,与FindFirstFile配合使用 |
HANDLE WINAPI CreateFile
(
__in LPCTSTR lpFileName,
__in DWORD dwDesiredAccess,
__in DWORD dwShareMode,
__in LPSECURITY_ATTRIBUTES lpSecurityAttributes,
__in DWORD dwCreationDisposition,
__in DWORD dwFlagsAndAttributes,
__in HANDLE hTemplateFile
);
使用MFC::CFile
CFile对HANDLE操作文件进行了封装
CFile(HANDLE hFile);
CFile(LPCTSTR lpszFileName, UINT nOpenFlags);
标志 | 含义 |
---|---|
CFile::modeCreate | 创建新文件,如果文件已存在,则将其长度变为0 |
CFile::modeNoTruncate | 与modeCreate组合使用,如果文件已存在,不会将长度变为0 |
CFile::modeRread | 只读 |
CFile::modeReadWrite | 读写 |
CFile::modeWrite | 只写 |
CFile::modeNoInherit | 组织改文件被子项继承 |
CFile::shareDenyNone | 以共享模式打开文件,不会禁止其他进程对文件读写 |
CFile::shareDenyRead | 禁止其他进程对文件的读操作 |
CFile::shareDenyWrite | 禁止其他进程对文件的写操作 |
CFile::shareExclusive | 以独占模式打开文件,禁止其他进程对文件的读写 |
CFile::typeText | 以文本方式打开文件 |
CFile::typeBinary | 以二进制方式打开文件 |
CFile操作函数
函数 | 含义 |
---|---|
Open | 打开文件 |
Close | 关闭文件 |
Flush | 刷新待写的数据 |
Read | 从当前位置读取数据 |
Write | 向当前位置写入数据 |
GetLength | 获取文件的大小 |
Seek | 定位文件指针至指定位置 |
SeekToBegin | 定位文件指针至文件头 |
SeekToEnd | 定位文件指针至文件尾 |
GetFileName | 获取文件名称 “NOTEPAD.EXE” |
GetFilePath | 获取文件路径 "C:\Windows\Notepad.exe |
GetFileTitle | 获取文件标题 “Notepad” |
GetPosition | 获取当前文件指针 |
GetStatus | 获取当前文件状态 |
properties文件读取
#配置文件
hotelName=同福客栈
boss=佟湘玉
maxClients=20
case=20.25
isOpen=true
class CProperty
{
public:
CProperty(CString value);
CString GetString(void);
int GetInteger(void);
double GetDouble(void);
bool GetBoolean(void);
private:
CString _value;
};
CProperty::CProperty(CString value) : _value(value)
{}
CString CProperty::GetString(void)
{
return _value;
}
int CProperty::GetInteger(void)
{
return atoi(LPCTSTR(_value));
}
double CProperty::GetDouble(void)
{
return atof(LPCTSTR(_value));
}
bool CProperty::GetBoolean(void)
{
return CString("true").CompareNoCase(_value) == 0;
}
class CProperties
{
public:
CProperty* GetProperty(CString name);
~CProperties(void);
int LoadFrom(ifstream &in);
private:
CMapStringToPtr _map;
};
CProperty* CProperties::GetProperty(CString name)
{
void *pa = NULL;
if (_map.Lookup(name, pa))
return static_cast<CProperty*>(pa);
return NULL;
}
CProperties::~CProperties(void)
{
POSITION pos;
CString key;
void *pa = NULL;
for (pos = _map.GetStartPosition(); pos != NULL;)
{
_map.GetNextAssoc(pos, key, pa);
delete pa;
}
}
int CProperties::LoadFrom(ifstream &in)
{
int lines = 0;
while (!in.eof())
{
char line[256] = {0};
in.getline(line, 255);
string s = line;
//emtpy line
if (s.empty())
continue;
//注释行
if (s[0]=='#' || s[0]== ';')
continue;
int i = s.find("=");
//没有=的行
if (i < 0)
continue;
string key = s.substr(0, i);
string value = s.substr(i+1);
_map.SetAt(CString(key.c_str()), new CProperty(CString(value.c_str())));
lines++;
}
return lines;
}
int main()
{
CProperties ps;
ifstream in("sample.properties");
ps.LoadFrom(in);
CString hotelName = ps.GetProperty("hotelName")->GetString();
CString boss = ps.GetProperty("boss")->GetString();
//...
return 0;
}
INI文件的读取
[boot loader]
timeout=30
default=multi(0)disk(0)rdisk(0)partition(1)\WINDOWS
[operating systems]
...
ini文件类型有点类似于properties文件,但是它多了一个section的概念,用于分段
函数 | 含义 |
---|---|
GetProfileInt | 从win.ini文件指定section中读取一个int属性值 |
GetProfileSection | 从win.ini指定的section中获取所有的属性 |
GEtProfileString | 从win.ini指定section中读取一个文本属性值 |
WriteProfileSection | 向win.ini文件中写入一个section |
WriteProfileString | 向win.ini文件指定section中写入一个文本属性值 |
GetPrivateProfileInt | 从指定的ini文件的section中读取一个int属性值 |
GetPrivateProfileSection | 从指定的ini文件中读取指定的section |
GetPrivateProfileSectionNames | 从指定的ini文件中读取所有的section名 |
GetPrivateProfileString | 从指定的ini文件的section中读取一个文本属性值 |
GetPrivateProfileStruct | 从指定的ini文件的Section中读取一个结构属性值 |
WritePrivateProfileSection | 向指定的ini文件写入一个section |
WritePrivateProfileString | 向指定的ini文件的section写入一个文本属性值 |
WritePrivateProfileStruct | 向指定的ini文件的section写入一个结构属性值 |
CSV文件的读取
csv文件常用语程序之间数据交互格式
- 每条记录占一行
- 记录间的值以逗号为分隔符
- 逗号前后的空白符会被忽略
- 如果值中包含逗号,换行符,空格,双引号,则该值必须用双引号引起来
- 值中双引号用双引号表示
class CRow
{
public:
CRow(CStringArray *row);
int GetColumnCount();
CString GetColumn(int i);
private:
CStringArray *_row;
};
CRow::CRow(CStringArray *row) : _row(row)
{
}
int CRow::GetColumnCount()
{
return _row->GetCount();
}
CString CRow::GetColumn(int i)
{
return _row->GetAt(i);
}
class CSheet
{
public:
CSheet();
~CSheet();
int LoadFrom(ifstream &in);
int GetRowCount();
CRow GetRow(int i);
private:
CTypedPtrArray<CPtrArray, CStringArray*> _rows;
};
CSheet::CSheet()
{}
CSheet::~CSheet()
{
for (int i = 0; i < _rows.GetCount(); i++)
{
delete _rows.GetAt(i);
}
}
int CSheet::LoadFrom(ifstream &in)
{
int lines = 0;
while (!in.eof())
{
char line[256] = {0};//256可以调整
in.getline(line, 255);
CString s = line;
if (s.IsEmpty())
continue;
if (s[0] == '#')
continue;
CStringArray *pRow = new CStringArray;
int i = 0;
CString token = s.Tokenize(_T(",\t"), i);
while (token != _T(""))
{
pRow->Add(token);
token = s.Tokenize(_T(",\t"), i);
}
_rows.Add(pRow);
lines++;
}
return lines;
}
int CSheet::GetRowCount()
{
return _rows.GetCount();
}
CRow CSheet::GetRow(int i)
{
return CRow(_rows.GetAt(i));
}
int main()
{
ifstream in("test.csv");
CSheet sheet;
sheet.LoadFrom(in);
for (int i = 0; i < sheet.GetRowCount(); i++)
{
_tprintf(_T("[%02d] "), i);
CRow row = sheet.GetRow(i);
for (int j = 0; j < row.GetColumnCount(); j++)
{
CString s = row.GetColumn(j);
_tprintf(_T("%s/"), s);
}
_tprintf(_T("\r\n"), i);
}
}
使用二进制文件
使用MFC::CArchive
,至于纯粹读写二进制文件的就不举例了,介绍MFC::CArchive
- 继承CObject类
- 覆盖Serialize()函数
class CPerson : public CObject
{
DECLARE_SERIAL(CPerson)
public:
CPerson();
CPerson(CString name, int age, bool gender = true);
~CPerson();
CString GetName();
CString GetWords();
void SetWords(CString words);
int GetAge();
bool isMale();
void Say();
void Say(CString msg);
//重载
virtual void Serialize(CArchive &ar);
private:
CString _name;
int _age;
bool _gender;
CString _words;
};
//相关函数略
void CPerson::Serialize(CArchive &ar)
{
if (ar.IsStoring())
{
ar << this->_name << this->_age << this->_gender << this->words;
}
else
{
ar >> this->_name >> this->_age >> this->_gender >> this->words;
}
}
int main()
{
/*
setlocale函数原形为:char *setlocale( int category, const char *locale );
支持的 locale 分类常量:LC_ALL、LC_COLLATE、LC_CTYPE、LC_MONETARY、LC_NUMERIC、LC_TIME
头文件:<locale.h>
所支持的操作系统为: Win 95, Win NT
对于简体中文可以使用如下设置:setlocale( LC_ALL, "chs" ); (编码ANSI)
调用setlocale原因:
在C/C++语言标准中定义了其运行时的字符集环境为"C",是ASCII字符集的一个子集,mbstowcs在工作时会将cstr中所包含的字符串看作是ASCII编码的字符,而不认为是一个包含有chs编码的字符串,所以会将每一个中文拆成2个ASCII编码进行转换,结果是会形成4个wchar_t的字符组成的串。
通过调用setlocale( LC_ALL, "chs" )函数,告诉mbstowcs目前cstr串中包含的是chs编码的字符串.
这个函数会改变整个应用程序的字符集编码方式,需要调用setlocale( LC_ALL, "C" )函数来还原。
应用场景:
针对无法读取中文路径下的文件的问题,在解析配置文件前,加入一句: setlocale(LC_ALL,"chs");即可
*/
setlocale(LC_ALL, "chs");
CPerson tong(_T("佟湘玉"), 28, false);
tong.SetWords(_T("额滴神啊..."));
CPerson bai(_T("白展堂"), 27, true);
bai.SetWords(_T("葵花点穴手!"));
//写入
CFile oFile(_T("persons.archive"), CFile::modeCreate|CFile::modeWrite);
CArchive oar(&oFile, CArchive::store);
oar << &tong << &bai;
oar.Close();
oFile.Close();
//读取
CFile iFile(_T("persons.archive"), CFile::modeRead);
CArchive iar(&iFile, CArchive::load);
CPerson* p1, *p2;
iar >> p1 >> p2;
delete p1;
delete p2;
return 0;
}
WINDOWS资源文件的读取
Windows资源是一个特殊的存储形式,它通常存在于EXE或DLL模块中,Windows程序通常使用资源来存储程序需要
的图标,工具栏等信息。但也可以在某些合适的场合下考虑采用资源文件作为反持久化的介质.
“合适的场合” :当前运行的程序其资源文件在运行时是只读的,所以说资源文件不适合那些需要动态更新的信息,它必须是在设计阶段就能确定的信息。举个例子,一些下拉框的信息可能来自于某些字典表,而这些字典项的内容在程序的运行期间是不变的。这个时候可以考虑采用资源文件。另外一种场合是,如果程序中需要创建一个word文件,可能需要一个word模板,或者说我们的access程序库可能需要一个空白的模板,而我们不希望在程序发布的时候多带一个文件,这个时候就可以使用资源文件了
函数 | 含义 |
---|---|
LoadAccelerators | 加载快捷键资源 |
LoadBitmap | 加载位图资源 |
LoadCursor | 加载光标资源 |
LoadIcon | 加载图标资源 |
LoadMenu | 加载菜单资源 |
LoadString | 加载字符串资源 |
---------- | -------------- |
FindResource | 从指定模块中加载指定名称,类型的资源 |
SizeofResource | 获取资源数据的长度 |
LoadResource | 加载指定的资源至内存 |
Lockresource | 锁定指定资源,并返回指向资源数据的指针 |
FreeResource | 释放指定的资源 |
加载某个资源的步骤
- 使用
LoadLibrary()
加载模块,或者获取当前应用程序的模块 - 调用
FindResource()
从指定模块中查找指定的资源,返回该资源的句柄 - 调用
SizeofResource()
获取资源数据的长度 - 调用
LoadResource()
将资源加载到内存中 - 调用
LockResource()
锁定资源,并返回指向资源数据的指针 - 通过数据指针操作数据
- 使用完毕,调用
FreeResource()
释放指定的资源
//举例加载一个word资源
//打开资源视图,导入一个word文档,资源类型定义为WORD,资源名称为IDR_WORD1
#include "stdafx.h"
#include "ResLoader.h"
CWinApp theApp;
int main()
{
int retCode = 0;
if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
{
_tprintf(_T("MFC 初始化失败!\n"));
retCode = 1;
}
else
{
HRSRC hRes = FindResource(theApp.m_hInstance, MAKEINTRESOURCE(IDR_WORD1), _T("WORD"));
DWORD len = SizeofResource(theApp.m_hInstance, hRes);
HGLOBAL hg = LoadResource(theApp.m_hInstance, hRes);
LPVOID lp = (LPSTR)LockResource(hg);
//将资源中的内容保存至某个word文件中
CFile file;
file.Open(_T("out.doc"), CFile::modeWrite|CFile::modeCreate);
char* cp = static_cast<char*>(lp);
for (int i = 0; i < len; i++)
file.Write(cp++, 1);
CString filePath = file.GetFilePath();
file.Close();
//open doc
ShellExecute(NULL, _T("open"), filePath, NULL, NULL, SW_SHOW);
FreeResource(hg);
}
return retCode;
}
XML文件
有相对应的C++库,windows下可以考虑使用MsXML
json文件
rapidjson读写即可
数据库文件 mysql, sqlite等
略