WideCharToMutiByte出现中文乱码

解决XML乱码问题
本文介绍了一个通过SOCKET从服务器获取XML文件并保存至本地的过程中遇到的乱码问题及解决方案。作者通过调整WideCharToMultiByte函数的参数,避免了在字符串末尾添加额外的NULL字符,从而解决了乱码问题。

这个小问题困了我一天一夜了,本来今天都计划写XML处理的代码了,结果又耽搁了一天。幸好后头还搞出来了。

我想写个程序,通过SOCKET获得服务器的XML文件,然后保存到本地。获取文件是搞定了,但是保存成文件时老出现乱码。

以下是会出现乱码的代码片断:

void CTecClientDlg::OnBnClickedbtnlogin()
{
    // TODO: 登陆按钮,登陆后下载数据。
   WORD version;
   WSADATA wsaData;
   int rVal=0;
   version=MAKEWORD(1,1);
   WSAStartup(version,(LPWSADATA)&wsaData); 
   SOCKET theSocket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
   if(theSocket==SOCKET_ERROR)
   {
       return;
   }
   SOCKADDR_IN serverInfo;
   serverInfo.sin_family=PF_INET;
   serverInfo.sin_addr.s_addr=inet_addr("192.168.0.3");
   serverInfo.sin_port=htons(6603);
   rVal=connect(theSocket,(LPSOCKADDR)&serverInfo,sizeof(serverInfo));
   if(rVal==SOCKET_ERROR)
   {
       return;
   }
   //==========================关键是这个片段
   CFile xmlFile(_T("Data.xml"),CFile::modeCreate|CFile::modeWrite);  
   wchar_t buf[200]; 
   int strLast=0;
   do{
        memset(buf,0,200*sizeof(wchar_t));
        strLast=recv(theSocket,(char*)buf,200*sizeof(wchar_t),0);
        if(strLast<=0)
        {//如果读取的长度不正常,退出循环。
            break;
        }  
        //倒数第三个参数为0,函数功能变为:返回buf的char类型容量。下面才好动态分配一个char*的内存空间。
        DWORD charLen=WideCharToMultiByte(CP_UTF8,0,buf,-1,NULL,0,NULL,FALSE);
        char* MutiByteBuf;
        MutiByteBuf=new char[charLen];
        WideCharToMultiByte(CP_UTF8,0,buf,-1,MutiByteBuf,charLen,NULL,FALSE);        
        xmlFile.Write(MutiByteBuf,charLen);      
        delete [] MutiByteBuf;  
   }while(strLast>0);
   xmlFile.Close();
   closesocket(theSocket);
   WSACleanup();
}

过程很辛苦,但结果很简单。

TIP:WideCharToMultiByte的第四个参数为-1,那么第三个参数buf的长度就是buf内容长度+一个NULL。

就是因为加的这个NULL导致我的程序在第二次循环后,时不时的出现乱码,非常恼火。

下面是可以正常工作的代码。

void CTecClientDlg::OnBnClickedbtnlogin()
{
    // TODO: 登陆按钮,登陆后下载数据。
   WORD version;
   WSADATA wsaData;
   int rVal=0;
   version=MAKEWORD(1,1);
   WSAStartup(version,(LPWSADATA)&wsaData);
   SOCKET theSocket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
   if(theSocket==SOCKET_ERROR)
   {
       return;
   }
   SOCKADDR_IN serverInfo;
   serverInfo.sin_family=PF_INET;
   serverInfo.sin_addr.s_addr=inet_addr("192.168.0.3");
   serverInfo.sin_port=htons(6603);
   rVal=connect(theSocket,(LPSOCKADDR)&serverInfo,sizeof(serverInfo));
   if(rVal==SOCKET_ERROR)
   {
       return;
   }
   CFile xmlFile(_T("Data.xml"),CFile::modeCreate|CFile::modeWrite);
   wchar_t buf[200];
   int strLast=0;
   do{
        memset(buf,0,200*sizeof(wchar_t));
        strLast=recv(theSocket,(char*)buf,200*sizeof(wchar_t),0);
        if(strLast<=0)
        {
            break;
        }
       /**

          *

          *就是这个地方,第四个参数我没有使用-1,而是使用了精确的长度 strLast/2,这样就不会在末尾追加了。

          *下面一处的调用也是一样的。

        **/
        DWORD charLen=WideCharToMultiByte(CP_UTF8,0,buf,strLast/2,NULL,0,NULL,FALSE);
        char* MutiByteBuf;
        MutiByteBuf=new char[charLen];
        WideCharToMultiByte(CP_UTF8,0,buf,strLast/2,MutiByteBuf,charLen,NULL,FALSE);
        xmlFile.Write(MutiByteBuf,charLen);
        delete [] MutiByteBuf; 
   }while(strLast>0);  
   xmlFile.Close(); 
   closesocket(theSocket);
   WSACleanup();
}
### Java 汉字乱码解决方案 #### 统一字符编码设置 为了防止Java程序中的汉字乱码问题,在编写源代码时应确保默认编码为所需类型,通常是UTF-8。可以通过IDE配置来更改项目的默认编码格式并更新现有文件以适应新的编码标准[^2]。 #### 使用恰当的流处理类 当读取或写入带有特定编码的数据时,应该利用`InputStreamReader`和`OutputStreamWriter`这样的辅助类指定正确的字符集名称作为参数传递给构造函数。这有助于保持数据传输过程中的一致性和准确性[^1]。 对于向文件中写入带编码的信息而言,可以采用如下改进后的代码片段: ```java import java.io.BufferedWriter; import java.io.FileOutputStream; import java.io.OutputStreamWriter; import java.io.IOException; public class WriteFileWithProperEncoding { public static void main(String[] args) throws IOException { String content = "正确地写入文件!"; try (BufferedWriter writer = new BufferedWriter( new OutputStreamWriter(new FileOutputStream("output.txt"), "UTF-8"))) { writer.write(content); } } } ``` 此段代码展示了如何通过显式指明输出流使用的字符编码(`UTF-8`)来避免潜在的乱码现象发生。 #### 处理已存在的GBK编码文件 如果遇到即使选择了UTF-8仍然存在乱码的情况,则可能是因为某些文件原本是以GBK编码保存下来的;此时应当尝试切换到GBK模式下打开这些文件,并注意在编辑完成后重新保存前关闭它们而不做任何改动以防破坏原有结构[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值