一:cout,wcout輸出測試
調試環境:VS2005 UNICODE
程式碼片段如下
_setmode(fileno(stdout),_O_BINARY);<br />TCHAR *pBuf = NULL;<br />SafeArrayAccessData(varBLOB.parray,(void **)&pBuf);<br />SafeArrayUnaccessData (varBLOB.parray);</p><p>wcout<<pBuf<<endl; //輸出應該為pBuf指向的從資料庫讀出的映像部分位元據(正確函數用法下面在介紹)<br />cout<<&pBuf<<endl; //2 pBuf指標的地址<br />cout<<static_cast<void *>(pBuf)<<endl; //3 pBuf指向的位元據塊首地址(如果想輸出一個指標所指的地址,只要把此指標強制轉換成 void * 即可,C++ Primer 3 中,cout一章有此例子)</p><p>cout<<endl;<br />TCHAR *test = L"adf";<br />cout<<test<<endl; //4 test指向的字串常量首地址,至於為啥不是adf,原因在於test是寬位元組,而cout是單位元組輸出函數,所以變成輸出test的字串第一個位元組首地址</p><p>wcout<<test<<endl; // 此處輸出為正確的adf,控制台中顯示似乎還有一個空格。。</p><p>cout<<endl;<br />char *testb = "abc";<br />cout<<testb<<endl; // 輸出正確,且沒空格<br />wcout<<testb<<endl; // 此處輸出雖然也為字元,(與上一個例子不相反 - -!)但是字元中間有空格。。<br />//字元中間有空格的原因查明,是代碼前有一段 _setmode(fileno(stdout),_O_BINARY);設定成二進位就會有空格。改成 _setmode(fileno(stdout),_O_TEXT);無空格<br />
顯示結果如下:
另:
TCHAR *test = L"adf";<br />cout<<test<<endl; //輸出為寬字元"a"低位元組地址0049504C<br />wcout<<test<<endl; //輸出結果為"adf";<br />test++;<br />cout<<test<<endl; //輸出為寬字元"a"高位元組地址0049504E<br />wcout<<test<<endl; //輸出結果為"df"<br />cout<<test[0]<<endl; // 輸出結果為100,應該為a的低位元組值<br />wcout<<test[0]<<endl; //輸出結果為a<br />cout<<test[1]<<endl; //輸出結果為102,應該為a的高位元組值<br />wcout<<test[1]<<endl; //輸出結果為d</p><p>cout<<L"adsafb"<<endl; //輸出結果為字串首地址
二,從資料庫中讀出的映像位元據直接輸出給瀏覽器
_variant_t varRecord(strRecord);<br />_variant_t varSQL(strSQL);</p><p>pRePtr->Open(varSQL,varRecord,adOpenStatic,adLockReadOnly,adCmdText);</p><p>if(pRePtr->GetRecordCount() == 0)<br />{<br />getnoneimage();<br />pRePtr->Close();<br />pRePtr.Release();<br />pRePtr = NULL;<br />return TRUE;<br />}</p><p>//讀出位元據<br />long lDataSize = pRePtr->GetFields()->GetItem("data")->ActualSize;///得到資料的長度<br />if(lDataSize > 0)<br />{<br />_variant_t varBLOB;<br />varBLOB = pRePtr->GetFields()->GetItem("data")->GetChunk(lDataSize);<br />if(varBLOB.vt == (VT_ARRAY | VT_UI1)) ///判斷資料類型是否正確,VT_UI1指無符號1位元組整數(BYTE)數組</p><p>{<br />TCHAR *pBuf = NULL;<br />SafeArrayAccessData(varBLOB.parray,(void **)&pBuf);<br />fflush(stdout);<br />_setmode(_fileno(stdout),_O_TEXT);<br />fprintf(stdout,"Content-Type:image/jpeg;/n/n");<br />_setmode(_fileno(stdout),_O_BINARY);<br />cout.write((char*)pBuf,lDataSize ); //用此函數可以正確輸出映像。 方法一<br /> //wcout<<pBuf<<endl; //此函數只輸出一部分就結束了,(見第一張圖中的第一行),可能還需要其他步驟 PS:個人猜想,映像資料中有wcout 所認為的結束符。。</p><p>//以下幾種方法,經測試均可以正常輸出映像</p><p>//方法二: </p><p>//long n = 0 ;</p><p>//while(n < lDataSize) //lDataSize 的值為映像塊資料的長度</p><p>//{<br />//cout<<((char*)pBuf)[n]; //正確<br />//n++;<br />//}</p><p>//方法三<br />//long n = 0 ;</p><p>//while(n < lDataSize/2 )<br />//{</p><p>//wcout<<pBuf[n];<br />//n++;<br />//}</p><p>//方法四:<br />//wcout.write(pBuf,lDataSize/2); </p><p>//cout.write(pBuf,lDataSize) // 出錯,因為cout 輸出的是char*型<br />SafeArrayUnaccessData (varBLOB.parray);<br />fflush(stdout);<br />_setmode(_fileno(stdout),_O_TEXT);<br />
更簡單的輸出方法為:
if(varBLOB.vt == (VT_ARRAY | VT_UI1)) ///判斷資料類型是否正確<br />{</p><p>TCHAR *pBuf = NULL;<br />pBuf = (TCHAR*)(_bstr_t)(varBLOB);</p><p>fflush(stdout);<br />_setmode(_fileno(stdout),_O_TEXT);<br />fprintf(stdout,"Content-Type:image/jpeg;/n/n");<br />_setmode(_fileno(stdout),_O_BINARY);<br />wcout.write(pBuf,lDataSize/2);<br />fflush(stdout);<br />_setmode(_fileno(stdout),_O_TEXT);<br />}
三,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];<br />wsprintf(szACP, _T(".%d"), GetACP());<br />_tsetlocale(LC_CTYPE, szACP);