出入社会,首先接触的一个任务就是,获取.csv文件内容,将其解析出来。其中的附加项就是获取文件的编码格式进行判断。而我,理解错意思了,理解成了要获取编码格式并将其修改。不过,我完成了。现在分享一下。
1、首先,获取.csv文件的编码。
获取文件编码,需要使用到一个第三方库。网上很多资料说判断编码格式都不全面,不能完整的获取编码格式。我找到了一个能够获取完整编码格式的库。附上链接:https://github.com/lml123-1/uchardet
1、拉取下来后放到任意有权限的目录。如下图所示:
2、 可以打开 INSTALL文件查看编译命令。或者输入以下命令进行编译。
mkdir build; cd build
#需要说明的是下面的 /usr 可以换成其它的目录,不过运行程序时要链接到库才可以跑
cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release
make #编译
sudo make install #生成动态静态库到'/usr'目录下
3、 接下来我们就可以编写获取编码的程序了:
#include <uchardet.h>
void MyCsv::DetectFile(int iFIndex, string &strUchar)
{
char *cStr;
uchardet_t handle = uchardet_new();
// m_iFiles[iFIndex]:相当于文件描述符 m_files[iFIndex]:相当于文件名
m_iFiles[iFIndex].open(m_files[iFIndex].c_str(), std::ios::in);
m_iFiles[iFIndex].seekg(0, std::ios::end);
long long llLen = m_iFiles[iFIndex].tellg(); //获取文件长度
cStr = new char[llLen];
memset(cStr, 0, llLen);
m_iFiles[iFIndex].seekg(std::ios::beg);
m_iFiles[iFIndex].read(cStr, llLen);
m_iFiles[iFIndex].close();
if (uchardet_handle_data(handle, cStr, llLen) != 0)
{
APP_INFO_EX("handle data error");
delete[] cStr;
return;
}
uchardet_data_end(handle);
const char *cStrset = uchardet_get_charset(handle); //得到文件的编码格式
if (*cStrset)
{
strUchar = cStrset;
}
else
{
strUchar = "unknown";
}
APP_INFO_EX("[{}]", strUchar); //这是一个打印信息的宏
delete[] cStr;
}
2、转换编码
需要清楚iconv这个转换编码的库。是linux自带的开源库。
#include <iostream>
#include <iconv.h>
#include <fstream>
#include <string.h>
#include <cstdio>
using namespace std;
bool CodeToCsvCode()
{
char *buffer;
char *nbuffer;
size_t inLen = 65536;
size_t llLen;
string strRet = "GB18030";
fstream f1;
iconv_t ct = iconv_open("UTF-8", strRet.c_str());
if (ct == (iconv_t) - 1)
{
cout << "1\n";
return false;
}
buffer = new char[inLen];
nbuffer = new char[inLen];
cout << "2\n";
f1.open("test.txt", std::ios::in);
f1.seekg(0, std::ios::end);
llLen = f1.tellg();
f1.seekg(0, std::ios::beg);
memset(buffer, 0, 65536);
memset(nbuffer, 0, 65536);
f1.read(buffer, llLen = llLen > 65536 ? 65536 : llLen);
f1.close();
char *oldstr = buffer;
char *newstr = nbuffer;
cout << strlen(buffer) << " " << llLen << " 3\n";
if (oldstr == NULL || &oldstr == nullptr || newstr == NULL || &newstr == nullptr)
{
delete [] buffer;
delete [] nbuffer;
cout << "5\n";
return false;
}
cout << oldstr << "---" << newstr;
//下面这个函数如果参数传错了很容易死机,内存越界
if (iconv(ct, &oldstr, &llLen, &newstr, &inLen) == (size_t) - 1)
{
cout << "4 " << oldstr << newstr;
delete [] buffer;
delete [] nbuffer;
iconv_close(ct);
return false;
}
cout << "6\n";
cout << nbuffer << "----" << buffer << "\n";
f1.open("test2.txt", std::ios::out | std::ios::trunc);
f1 << nbuffer;
f1.close();
iconv_close(ct);
delete [] buffer;
delete [] nbuffer;
return true;
}
int main()
{
CodeToCsvCode();
return 0;
}