iconv使用方法


iconv使用方法


在多线程环境中,iconv本身是不支持多线程安全的。
比如在代码段中:

iconv_t cd = iconv_open(tocode, fromcode);
if (cd == (iconv_t)-1) {
exit(1);
}
iconv(cd, &inbuf, &len, &outbuf, &buflen);
iconv_close(cd);
多线程环境中,iconv_open不断打开资源,虽然iconv_close能够释放,但是并不能立即释放资源,这样造成内存泄漏。

比较正确的方法是静态地初始化iconv_open和析构iconv_close,或对上面代码段进行锁机制可实现线程安全。



############################

网上典型的代码是这一段:

[cpp]  view plain copy
  1. char* ConvertEnc( char *encFrom, char *encTo, const char * in)  
  2. {  
  3.     static char bufin[1024], bufout[1024], *sin, *sout;  
  4.     int lenin, lenout, ret;  
  5.     iconv_t c_pt;  
  6.   
  7.     if ((c_pt = iconv_open(encTo, encFrom)) == (iconv_t)-1)  
  8.     {  
  9.         printf("iconv_open false: %s ==> %s", encFrom, encTo);  
  10.         return NULL;  
  11.     }  
  12.     iconv(c_pt, NULL, NULL, NULL, NULL);  
  13.   
  14.     lenin  = strlen(in) + 1;  
  15.     lenout = 1024;  
  16.     sin    = (char *)in;  
  17.     sout   = bufout;  
  18.     ret = iconv(c_pt, (const char**)&sin, (size_t *)&lenin, &sout, (size_t *)&lenout);  
  19.   
  20.     if (ret == -1)  
  21.     {  
  22.         return NULL;  
  23.     }  
  24.     iconv_close(c_pt);  
  25.   
  26.     return bufout;  
  27. }  
这段代码里面有3个问题:
1.没有重复使用初始化后的iconv_t。
2.lenin  = strlen(in) + 1这行代码在某些情况下有问题。
3.转换缓冲区是一个固定值。


我根据iconv官网上的文档重写了相关代码,官网地址如下:

http://www.gnu.org/savannah-checkouts/gnu/libiconv


代码如下

[cpp]  view plain copy
  1. #ifndef _ICONV_PAIR_HXX_  
  2. #define _ICONV_PAIR_HXX_  
  3.   
  4. #include <string>  
  5. #include <iconv/include/iconv.h>  
  6.   
  7. class IconvPair  
  8. {  
  9.     enum   
  10.     {  
  11.         INIT_BUFFER = 4096  
  12.     };  
  13.   
  14. public:  
  15.     IconvPair(const std::string &toCode, const std::string &fromCode);  
  16.     ~IconvPair();  
  17.   
  18. private:  
  19.     IconvPair(const IconvPair&);  
  20.     IconvPair& operator=(const IconvPair&);  
  21.   
  22. public:  
  23.     friend bool operator<(const IconvPair &lhs, const IconvPair &rhs)  
  24.     {  
  25.         if (lhs.mToCode < rhs.mToCode)  
  26.         {  
  27.             return true;  
  28.         }  
  29.         else if (lhs.mToCode > rhs.mToCode)  
  30.         {  
  31.             return false;  
  32.         }  
  33.   
  34.         return lhs.mFromCode <=rhs.mFromCode ? true : false;  
  35.     }  
  36.   
  37.     const char* buffer() const {return mBuffer;}  
  38.     size_t bufferLen() const {return mBufferLen;}  
  39.     size_t contentLen() const {return mContentLen;}  
  40.   
  41.     size_t convert(const char **inBuffer, size_t *inBytesLeft);  
  42.   
  43. private:  
  44.     void incBuffer();  
  45.   
  46. private:  
  47.     std::string mToCode;  
  48.     std::string mFromCode;  
  49.     iconv_t mIconv;  
  50.     char *mBuffer;  
  51.     size_t mBufferLen;  
  52.     size_t mContentLen;  
  53. };  
  54.   
  55. #endif  

[cpp]  view plain copy
  1. #include "statistics/IconvPair.hxx"  
  2. #include <cstdlib>  
  3. #include <cerrno>  
  4. #include <cassert>  
  5. #include <climits>  
  6. #include <exception>  
  7.   
  8. IconvPair::IconvPair(const std::string &toCode, const std::string &fromCode)  
  9.     : mToCode(toCode)  
  10.     , mFromCode(fromCode)  
  11.     , mIconv(reinterpret_cast<iconv_t>(-1))  
  12.     , mBuffer(NULL)  
  13.     , mBufferLen(0)  
  14.     , mContentLen(0)  
  15. {  
  16.     if (mToCode.empty() || mFromCode.empty())  
  17.     {  
  18.         throw std::exception();  
  19.     }  
  20.   
  21.     mBufferLen = INIT_BUFFER;  
  22.     mBuffer = reinterpret_cast<char*>(malloc(mBufferLen));  
  23.     if (NULL == mBuffer)  
  24.     {  
  25.         throw std::bad_alloc();  
  26.     }  
  27.   
  28.     mIconv = iconv_open(toCode.c_str(), fromCode.c_str());  
  29.     if (reinterpret_cast<iconv_t>(-1) == mIconv)  
  30.     {  
  31.         throw std::exception();  
  32.     }  
  33. }  
  34.   
  35. IconvPair::~IconvPair()  
  36. {  
  37.     if (reinterpret_cast<iconv_t>(-1) != mIconv)  
  38.     {  
  39.         iconv_close(mIconv);  
  40.     }  
  41.   
  42.     free(mBuffer);  
  43. }  
  44.   
  45. size_t IconvPair::convert(const char **inBuffer, size_t *inBytesLeft)  
  46. {  
  47.     assert((NULL != mBuffer) && (reinterpret_cast<iconv_t>(-1) != mIconv));  
  48.     assert((NULL != inBuffer) && (NULL != *inBuffer) && (NULL != inBytesLeft));  
  49.   
  50.     iconv(mIconv, NULL, NULL, NULL, NULL);  
  51.   
  52.     char *outBuffer = mBuffer;  
  53.     size_t outBytesLeft = mBufferLen;  
  54.     size_t ret = iconv(mIconv, inBuffer, inBytesLeft, &outBuffer,  
  55.         &outBytesLeft);  
  56.     while ((UINT_MAX == ret) && (0 == outBytesLeft)/*(E2BIG == errno)*/)  
  57.     {  
  58.         size_t oldBufferLen = mBufferLen;  
  59.         incBuffer();  
  60.   
  61.         outBuffer = mBuffer + oldBufferLen;  
  62.         outBytesLeft = mBufferLen - oldBufferLen;  
  63.         ret = iconv(mIconv, inBuffer, inBytesLeft, &outBuffer,  
  64.             &outBytesLeft);  
  65.     }  
  66.   
  67.     mContentLen = mBufferLen - outBytesLeft;  
  68.     if (0 == outBytesLeft)  
  69.     {  
  70.         incBuffer();  
  71.     }  
  72.     mBuffer[mContentLen] = 0;  
  73.     return ret;  
  74. }  
  75.   
  76. void IconvPair::incBuffer()  
  77. {  
  78.     mBufferLen *= 2;  
  79.     mBuffer = reinterpret_cast<char*>(realloc(mBuffer, mBufferLen));  
  80.     if (NULL == mBuffer)  
  81.     {  
  82.         throw std::bad_alloc();  
  83.     }  
  84. }  



测试代码块如下:

[cpp]  view plain copy
  1. void UnitTest::testIconv()  
  2. {  
  3.     const size_t pageSize = 4096;  
  4.     IconvPair g2u("utf-8""gb2312");  
  5.   
  6.     char array[pageSize] = {'a'};  
  7.     const char *inArray = array;  
  8.     size_t inArrayLen = pageSize;  
  9.     size_t ret = g2u.convert(&inArray, &inArrayLen);  
  10.     CPPUNIT_ASSERT((0 == ret) && ((pageSize * 2) == g2u.bufferLen()));  
  11.   
  12.     char *buffer = reinterpret_cast<char*>(malloc(1024 * 1024 * sizeof(char)));  
  13.     CPPUNIT_ASSERT(NULL != buffer);  
  14.   
  15.     FILE *f = fopen("league2012b.htm""r");  
  16.     CPPUNIT_ASSERT(NULL != f);  
  17.     size_t fileLen = 0;  
  18.     while (!feof(f))  
  19.     {  
  20.         fileLen += fread(buffer + fileLen, 1, pageSize, f);  
  21.     }  
  22.     fclose(f);  
  23.   
  24.     const char *bufferIn = buffer;  
  25.     ret = g2u.convert(&bufferIn, &fileLen);  
  26.     CPPUNIT_ASSERT(0 == ret);  
  27.   
  28.     f = fopen("league2012b.txt""w");  
  29.     CPPUNIT_ASSERT(NULL != f);  
  30.     fwrite(g2u.buffer(), 1, g2u.contentLen(), f);  
  31.     fclose(f);  
  32.   
  33.     free(buffer);  
  34. }  

由于直接将测试代码块中的league2012b.htm复制到CSDN的代码块中会有问题,所以只好请大家直接用快盘共享出来的链接自己下载了。链接地址如下

http://www.kuaipan.cn/file/id_19631556775674797.htm


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值