常用文件读写(1)

27 篇文章 2 订阅

文件操作的几种方式

使用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进行文件操作的流程为

  1. 调用fstream::fopen()创建打开文件
  2. 通过流操作,使用fstream完成输入输出,如out << "hello world!";
  3. 调用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文件常用语程序之间数据交互格式

  1. 每条记录占一行
  2. 记录间的值以逗号为分隔符
  3. 逗号前后的空白符会被忽略
  4. 如果值中包含逗号,换行符,空格,双引号,则该值必须用双引号引起来
  5. 值中双引号用双引号表示
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

  1. 继承CObject类
  2. 覆盖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释放指定的资源

加载某个资源的步骤

  1. 使用LoadLibrary()加载模块,或者获取当前应用程序的模块
  2. 调用FindResource()从指定模块中查找指定的资源,返回该资源的句柄
  3. 调用SizeofResource()获取资源数据的长度
  4. 调用LoadResource()将资源加载到内存中
  5. 调用LockResource()锁定资源,并返回指向资源数据的指针
  6. 通过数据指针操作数据
  7. 使用完毕,调用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等

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值