简介
文件IO属于IO的基础操作,网上也有好多资料,写法挺多的,看了很多零零碎碎的文章,这里进行一个总结。
这章的函数将为后面JSON读写提供支持
代码在Window10 Visual Studio 2019可以正常运行,没有在Linux上运行测试过。
完整代码在项目BaseFileIO.h文件中
为了显示在读写过程中的数据,每个函数看着可能有点长。
用到的头文件
#include #include #include #include #include //用于转码和解码 写(ASCLL)
//覆盖写入 bool OverWriteFile(const char* fileName, const char* content) { cout << "\nMBaseIO::OverWriteFile:\n"; //打开文件 std::ofstream truncfile(fileName, std::ios::out | std::ios::trunc //模式:重写 ); if (!truncfile.is_open()) { cout << fileName << " Open fail" << endl; return false; } //写入 truncfile.write(content, std::strlen(content)); //关闭 truncfile.close(); cout << "strlen(content):" << strlen(content) << endl; return true; } //追加写入 bool AppendFile(const char* fileName, const char* content) { cout << "\nMBaseIO::AppendFile:\n"; std::ofstream appfile(fileName, std::ios::out | std::ios::app //模式:追加 ); if (!appfile) { cout << fileName << " Open fail" << endl; return false; } appfile.write(content, std::strlen(content)); appfile.close(); cout << "strlen(content):" << strlen(content) << endl; return true; } 测试用例
//文件 const char* truncFileName = "./file/truncFile.txt"; const char* appFileName = "./file/appFile.txt"; //内容 const char* content = "abcdefgh"; //写入 for (int i = 0; i < 2; i++) { OverWriteFile(truncFileName, content); AppendFile(appFileName, content); } 输出
MBaseIO::OverWriteFile: strlen(content):8 MBaseIO::AppendFile: strlen(content):8 MBaseIO::OverWriteFile: strlen(content):8 MBaseIO::AppendFile: strlen(content):8 读(ASCLL)
//获取窄字符串(以char*为缓冲) char* GetChars(const char* fileName) { cout << "\nMBaseIO::GetChars:\n"; char* buffer = nullptr; //打开文件(输入|文件指针置于末尾) std::ifstream ifs(fileName,std::ios::in | std::ios::ate); if (!ifs) { cout << fileName << "文件打开失败\n"; return buffer; } //获取文件大小 size_t size = static_cast<size_t>(ifs.tellg()); //文件指针重置到首位 ifs.seekg(0, ifs.beg); //Array buffer buffer = new char[size+1]; ifs.read(buffer, size); buffer[size] = 0; ifs.close(); cout << "gcount:" << ifs.gcount() << "\t"; cout << "size:" << size << "\t\t"; cout << "strlen: " << strlen(buffer) << endl; cout << buffer << endl; return buffer; } //获取窄字符串(以vector为缓冲) char* GetCharsV(const char* fileName) { cout << "\nMBaseIO::GetCharsV:\n"; char* res = nullptr; std::ifstream ifs(fileName, std::ifstream::in | std::ios::ate ); if (!ifs) { cout << fileName << "文件打开失败\n"; return NULL; } size_t size = static_cast<size_t>(ifs.tellg()); ifs.seekg(0, ifs.beg); //申请vector缓冲区 std::vector<char> vec(size + 1, 0); ifs.read(vec.data(), size); ifs.close(); //不能直接将vec的数据拷贝给char*,因为在函数作用域结束之后,没有用new创建的vector里的char都会跟着vector释放。 //res = vec.data(); res = new char[vec.size()]; strncpy_s(res, vec.size(), vec.data(), vec.size()); cout << "gcount:" << ifs.gcount() << "\t"; cout << "size:" << size << "\t\t"; cout << "strlen:" << strlen(res) << "\t"; cout << "vec.size(): " << vec.size() << endl; cout << res << endl; return res; } 测试用例
//读取 char* p1 = GetChars(truncFileName); char* p2 = GetCharsV(appFileName); //释放空间 delete[] p1; delete[] p2; 输出
MBaseIO::GetChars: gcount:8 size:8 strlen: 8 abcdefgh MBaseIO::GetCharsV: gcount:16 size:16 strlen:16 vec.size(): 17 abcdefghabcdefgh 申请数组缓冲区中为什么+1
+1是为了给EOF留出空位,为什么要设置EOF?大多数情况下无影响,但在某些字符串函数,没有EOF会产生错误。
strlen函数只会测量\0(结束符,ASCLL值就是0)之前的字符数
写(UTF-8)
在使用wcout、wofstream、wifstream之前,必须先进行本地化设置
可以使用下面的方法对全局进行本地化设置,也可以使用std::wcout.imbue(std::locale("chs"));的方式进行设置
int main() { setlocale(LC_ALL, "chs"); //第二篇,普通文件读写 BaseTest(); return 0; } 将之前的窄字符处理方法全部换成换字符的。
并且要使用codecvt_utf8设置解码和编码的方式。
//覆盖写入UTF8 bool OverWriteUTF8(const char* fileName, const wchar_t* content) { cout << "\nMBaseIO::OverWriteUTF8:\n"; std::wofstream wof; wof.open(fileName, std::ios::out | std::ios::trunc ); if (!wof.is_open()) { cout << fileName << "Open fail" << endl; return false; } std::codecvt_utf8<wchar_t, 0x10ffff, std::consume_header>* codecvtToUnicode = new std::codecvt_utf8 < wchar_t, 0x10ffff, std::consume_header >; wof.imbue(std::locale(wof.getloc(), codecvtToUnicode)); wof.write(content, wcslen(content)); wof.close(); cout << "wcslen(content):"<<wcslen(content) << endl; return true; } 测试用例
一共4+4+1+3+3+6=21个字符,英语,换行,阿拉伯数字,简体中文,繁体中文,俄语
const char* writeUTF8FileName = "./file/write-utf8.txt"; const wchar_t* UTF8Content = L"abcd1234\n厄萨斯厄薩斯Атрокс"; OverWriteUTF8(writeUTF8FileName, UTF8Content); 输出
MBaseIO::OverWriteUTF8: wcslen(content):21 读(UTF-8)
略显复杂
//获取宽字符串(以wchar_t*为缓冲) wchar_t* GetWChars(const char* fileName) { cout << "\nMBaseIO::GetWChars:\n"; wchar_t* buffer = nullptr; std::wifstream ifs(fileName, std::wifstream::in | std::wifstream::ate ); if (!ifs) { cout << fileName << "文件打开失败\n"; return buffer; } //需要设置解码方式 std::codecvt_utf8<wchar_t, 0x10ffff, std::consume_header>* codecvtToUnicode = new std::codecvt_utf8 < wchar_t, 0x10ffff, std::consume_header >; ifs.imbue(std::locale(ifs.getloc(), codecvtToUnicode)); //这里测量出来的size并不是wchar_t的数量,而是以char为单位的数量, size_t size = static_cast<size_t>(ifs.tellg()); ifs.seekg(0, ifs.beg); //必须要将数组进行初始化,否则会导致后面的wcout无法输出 buffer = new wchar_t[size + 1]; wmemset(buffer, 0, size + 1); ifs.read(buffer, size); ifs.close(); size_t realSize = wcslen(buffer); if (realSize == 0) { return nullptr; } cout << "gcount:" << ifs.gcount() << "\t"; cout << "size:" << size << "\t\t"; cout << "realSize:" << realSize << "\t"; cout << "wcslen(buffer):" << wcslen(buffer) << "\t"; //如果实际大小比之前分配的空间小,则缩小分配的空间 if (realSize < size) { realSize++; wchar_t* res = new wchar_t[realSize]; wmemmove(res, buffer, realSize); delete[] buffer; cout << "wcslen(res): " << wcslen(res) << endl; wcout << res << endl; return res; } else { wcout << buffer << endl; return buffer; } } //获取宽字符串(以vector为缓冲) wchar_t* GetWCharsV(const char* fileName) { cout << "\nMBaseIO::GetWCharsV:\n"; std::wifstream ifs(fileName, std::wifstream::in | std::wifstream::ate ); if (!ifs) { cout << fileName << "文件打开失败\n"; return NULL; } std::codecvt_utf8<wchar_t,
管理员
上一篇:
盛大素材包wzl解析