一:cout,wcout输出测试
调试环境:VS2005 UNICODE
代码段如下
_setmode(fileno(stdout),_O_BINARY); TCHAR *pBuf = NULL; SafeArrayAccessData(varBLOB.parray,(void **)&pBuf); SafeArrayUnaccessData (varBLOB.parray); wcout<<pBuf<<endl; //输出应该为pBuf指向的从数据库读出的图像部分二进制数据(正确函数用法下面在介绍) cout<<&pBuf<<endl; //2 pBuf指针的地址 cout<<static_cast<void *>(pBuf)<<endl; //3 pBuf指向的二进制数据块首地址(如果想输出一个指针所指的地址,只要把此指针强制转换成 void * 即可,C++ Primer 3 中,cout一章有此例子) cout<<endl; TCHAR *test = L"adf"; cout<<test<<endl; //4 test指向的字符串常量首地址,至于为啥不是adf,原因在于test是宽字节,而cout是单字节输出函数,所以变成输出test的字符串第一个字节首地址 wcout<<test<<endl; // 此处输出为正确的adf,控制台中显示似乎还有一个空格。。 cout<<endl; char *testb = "abc"; cout<<testb<<endl; // 输出正确,且没空格 wcout<<testb<<endl; // 此处输出虽然也为字符,(与上一个例子不相反 - -!)但是字符中间有空格。。 //字符中间有空格的原因查明,是代码前有一段 _setmode(fileno(stdout),_O_BINARY);设置成二进制就会有空格。改成 _setmode(fileno(stdout),_O_TEXT);无空格
显示结果如下:
另:
TCHAR *test = L"adf"; cout<<test<<endl; //输出为宽字符"a"低字节地址0049504C wcout<<test<<endl; //输出结果为"adf"; test++; cout<<test<<endl; //输出为宽字符"a"高字节地址0049504E wcout<<test<<endl; //输出结果为"df" cout<<test[0]<<endl; // 输出结果为100,应该为a的低字节值 wcout<<test[0]<<endl; //输出结果为a cout<<test[1]<<endl; //输出结果为102,应该为a的高字节值 wcout<<test[1]<<endl; //输出结果为d cout<<L"adsafb"<<endl; //输出结果为字符串首地址
二,从数据库中读出的图像二进制数据直接输出给浏览器
_variant_t varRecord(strRecord); _variant_t varSQL(strSQL); pRePtr->Open(varSQL,varRecord,adOpenStatic,adLockReadOnly,adCmdText); if(pRePtr->GetRecordCount() == 0) { getnoneimage(); pRePtr->Close(); pRePtr.Release(); pRePtr = NULL; return TRUE; } //读出二进制数据 long lDataSize = pRePtr->GetFields()->GetItem("data")->ActualSize; ///得到数据的长度 if(lDataSize > 0) { _variant_t varBLOB; varBLOB = pRePtr->GetFields()->GetItem("data")->GetChunk(lDataSize); if(varBLOB.vt == (VT_ARRAY | VT_UI1)) ///判断数据类型是否正确,VT_UI1指无符号1字节整数(BYTE)数组 { TCHAR *pBuf = NULL; SafeArrayAccessData(varBLOB.parray,(void **)&pBuf); fflush(stdout); _setmode(_fileno(stdout),_O_TEXT); fprintf(stdout,"Content-Type:image/jpeg;/n/n"); _setmode(_fileno(stdout),_O_BINARY); cout.write((char*)pBuf,lDataSize ); //用此函数可以正确输出图像。 方法一 //wcout<<pBuf<<endl; //此函数只输出一部分就结束了,(见第一张图中的第一行),可能还需要其他步骤 PS:个人猜想,图像数据中有wcout 所认为的结束符。。 //以下几种方法,经测试均可以正常输出图像 //方法二: //long n = 0 ; //while(n < lDataSize) //lDataSize 的值为图像块数据的长度 //{ //cout<<((char*)pBuf)[n]; //正确 //n++; //} //方法三 //long n = 0 ; //while(n < lDataSize/2 ) //{ //wcout<<pBuf[n]; //n++; //} //方法四: //wcout.write(pBuf,lDataSize/2); //cout.write(pBuf,lDataSize) // 出错,因为cout 输出的是char*型 SafeArrayUnaccessData (varBLOB.parray); fflush(stdout); _setmode(_fileno(stdout),_O_TEXT);
更简单的输出方法为:
if(varBLOB.vt == (VT_ARRAY | VT_UI1)) ///判断数据类型是否正确 { TCHAR *pBuf = NULL; pBuf = (TCHAR*)(_bstr_t)(varBLOB); fflush(stdout); _setmode(_fileno(stdout),_O_TEXT); fprintf(stdout,"Content-Type:image/jpeg;/n/n"); _setmode(_fileno(stdout),_O_BINARY); wcout.write(pBuf,lDataSize/2); fflush(stdout); _setmode(_fileno(stdout),_O_TEXT); }
三,cout,wcout,printf,wprintf等函数的中文输出问题
转篇文章
需要说明的是,我的开发环境是VS 2005(标准库当然也是微软实现的),不保证其它环境下是相同的效果。
1、cout和wcout
在缺省的C locale下,cout可以直接输出中文,但对于wcout却不行(至少VS 2005下不行)。对于wcout,需要将其locale设为本地语言才能输出中文:
wcout.imbue(locale(locale(),"",LC_CTYPE)); // ①
也有人用如下语句的,但这会改变wcout的所有locale设置,比如数字“1234”会输出为“1,234”。
wcout.imbue(locale(""));
2、ofstream和wofstream
在缺省的C locale下,ofstream能正确输出中文到文件中,但不支持中文文件名;wofstream支持中文文件名,但不能向文件中输出中文。要解决这个问题,需要在打开文件之前将全局locale设为本地语言。将全局locale设为本地语言后,ofstream和wofstream的问题都解决了,但 cout和wcout却不能输出中文了。要让cout和wcout输出中文,需要将全局locale恢复原来的设置,如下所示:
locale &loc=locale::global(locale(locale(),"",LC_CTYPE)); // ②
ofstream ofs("ofs测试.txt");
wofstream wofs(L"wofs测试.txt");
locale::global(loc); // ③
ofs<<"test测试"<<1234<<endl;
wofs<<L"Another test还是测试"<<1234<<endl;
3、printf和wprintf
加上这两位C语言中的老兄,问题更加复杂。考虑如下语句(注意s的大小写):
printf("%s", "multibyte中文/n"); // ④
printf("%S", L"unicode中文/n"); // ⑤
wprintf(L"%S", "multibyte中文/n"); // ⑥
wprintf(L"%s", L"unicode中文/n"); // ⑦
缺省情况下,⑤、⑦两条语句不能输出中文,这两条语句中字符串的形式是unicode形式的。如果在所有输出语句之前加上如下语句将C语言的全局locale设置为本地语言(C语言中只有全局locale)就可以正常输出了:
setlocale(LC_CTYPE, ""); // ⑧
但这会导致cout和wcout不能输出中文(汗,的确麻烦),将C语言的全局locale恢复后cout和wcout就正常了,如下所示:
setlocale(LC_CTYPE, "C"); // ⑨
但恢复后,printf和wprintf输出Unicode文本又不正常了(输出MultiByte文本总是正常的)。总不能每写一个 printf/wprintf就设置一次然后再恢复一次吧?所以,建议不要混用iostream和printf/wprintf,实在要混用,那就让 printf/wprintf只输出MultiByte字符串,这样不需要调用setlocale(),也就不会影响到cout和wcout.
总结
总之,用iostream、printf/wprintf输出中文,有点麻烦。概括起来要点如下:
·如果要用wcout,需要在使用之前按语句①将其locale设置为本地语言;
·如果要用ofstream或wofstream,要在打开文件之前按语句②将全局locale设为本地语言并保存初始的全局locale.然后在打开文件之后,按语句③将全局locale恢复为初始值;
·不要混用iostream和printf/wprintf.如果要混用,只用printf/wprintf输出MultiByte字符串;
·单独使用printf/wprintf时,如果要输出Unicode字符串,需要按语句⑧设置C语言的全局locale.如果只输出MultiByte字符串,则不需设置。
而我自己的代码中,用wprintf输出中文需要执行以下段代码即可,且wcout也可正常输出中文
TCHAR szACP[16]; wsprintf(szACP, _T(".%d"), GetACP()); _tsetlocale(LC_CTYPE, szACP);