关于c++的文件编码的研究
今天很有成就感,倒不是做出了多牛的东西,而是终于可以动态的进行编码的各种转换了。
其实这个用到的是网上一搜一大片的iconv,目前有windows版和linux版,linux下的很容易找到,直接装上就可以进行开发了,windows下的包可以通过这个链接下载:win-iconv-0.0.4.zip,直接将放入工程内,就可以使用了。
下面给出我自己的测试代码(基于文件的):
#include <iostream> #include <stdlib.h> #include <stdio.h> #include <fstream> #include "include/iconv.h" using namespace std; int main(void) { string src(""); char buf[4096]; int fileLen = 0; ifstream file1("sohu.htm"); while(!file1.eof()) { memset(buf, 0, 4096); file1.read(buf, 4096); int readLen = file1.gcount(); buf[readLen] = '\0'; printf("readline: \n %s\n", buf); src.append(buf); fileLen += readLen; } file1.close(); char *dest = new char[src.length() * 2 + 1]; /* 格式化转换后的字串 */ memset(dest, 0, src.length() * 2 + 1); size_t src_len = src.length(); size_t dst_len = src.length() * 2; //注意:我用了一块2倍于源数据长度的buffer const char *in = src.c_str(); char *out = dest; iconv_t cd; cd = iconv_open("utf-8", "gb2312"); /* 将GB2312字符集转换为UTF-8字符集 */ if ((iconv_t)-1 == cd) { printf("iconv_open err %d\n", errno); return -1; } if(iconv(cd, &in, &src_len, &out, &dst_len) == -1) /* 执行转换 */ { printf("iconv_open err %d\n", errno); return -1; } ofstream file2("out.txt"); file2.write(dest, src.length() * 2 - dst_len); file2.close(); iconv_close(cd); /* 执行清理 */ return 0; }
我在写代码的时候,遇到了两种错误:
(1)返回errno=7,即E2BIG
问题原因:目的内存的大小不够
解决办法:就是使用的分配2倍于源数据大小的空间,由于编码转换会导致数据量的变化
(2)返回errno=42,即ENOMSG
问题原因:源数据的编码与iconv_open输入的源编码不同
解决办法:就是找到源数据的真正编码,使用uchardet对字符串进行分析得出真正的编码格式
如何使用uchardet?
uchardet_t m_uchardet = uchardet_new(); if(m_uchardet) { if(uchardet_handle_data(m_uchardet, m_content.c_str(), m_content.length()) == 0) { uchardet_data_end(m_uchardet); m_charSet.assign(uchardet_get_charset(m_uchardet)); } } uchardet_delete(m_uchardet);
uchardet源码下载路径:
类似的,对内存中的数据进行编码转换也可以用这个方法,最终输出的文件编码格式就是当初设置的目标编码格式。