OS: Windows XP
開発ツール: VS 2005 VC++
アプリ: MFC/SDI
プロジェクト: Unicode文字セット使用
Unicodeファイルと通常のANSIファイルを共用できるアプリを
作っています。
上記の環境でビルドするので、ANSIファイル(テキストデータが
入っている)を読み込むときは、MuliByteToWideChar関数を使って
変換しますが、読み込んだ文字列の末尾にヘンな文字列(ゴミ)が
くっつきます。
例えば、
「連休は晴天でしょう(改行)かなりの人出が予想されます(改行)」
と入っているファイルを読むと、
「連休は・・・(2つ目の改行)ヘ’’’オオオオ」
となります。
下記のコードのどこがまずいか、あるいは別の方法を教えてください。
よろしくお願いいたします。
CFile f;
f.Open(_T("Test.CSV"), CFile::modeRead);
int nByteFile = (int)f.GetLength();
char *cANSI = new char[nByteFile+1];
f.Read(cANSI, nByteFile+1);
wchar_t *wcRead = new TCHAR[nByteFile+1];
int nLen = ::MultiByteToWideChar(CP_ACP, 0, cANSI, -1, NULL, 0);
::MultiByteToWideChar(CP_ACP, 0, cANSI, -1, wcRead, nLen);
delete [] cANSI;
delete [] wcRead;
オープンしたファイルを一度バッファにコピーしたらいいと思います。
普通に終端文字がないだけなのでは?
CFile::Readでは文字列だと思って読み込んでいないので、
終端文字を付加する機能はありません。
f.Read(cANSI, nByteFile);
cANSI[ nByteFile ] = '\0';
としてみてはどうでしょうか?
ちなみに、CStringのコンストラクタならば、
wchar_t*型でもchar*型でもTCHAR型の文字列を作れます。
http://msdn2.microsoft.com/ja-jp/library/cws1zdt8.aspx
> ::MultiByteToWideChar(CP_ACP, 0, cANSI, -1, NULL, 0);
-1を指定するにはcANSIがNULL終端である必要があります。
Blueさんもご指摘のように提示されているコードでは
NULL終端であることは保証されません。
ついでですが、せっかく
> int nLen = ::MultiByteToWideChar(CP_ACP, 0, cANSI, -1, NULL, 0);
としているのですから
> wchar_t *wcRead = new TCHAR[nByteFile+1];
の部分を1回目のMultiByteToWideCharの後に移動して
new TCHAR[nLen + 1]にした方がメモリ使用量を抑えられますよ。
たぶん様、Blue様、kure様
素速い応答、ありがとうございました。速いので驚きました。
cANSI[ nByteFile ] = '\0';
と、終端文字を付加することで、解決しました。
メモリ節約のアドバイスも有益です。ありがとうございました。
補足です。
> メモリ節約のアドバイス
これが当てはまるのはDBCS(Double Byte Character Set)
以外のMBCSのケースで、1文字3バイト以上が必要になるケースです。
コードを見るとCP_ACPを渡しており、環境次第ではDBCSじゃないケースが
あるかもしれません。その場合にメモリの節約になります。
提示されたコードはファイルサイズでnewしており
変換前のデータが1文字3バイトとすればUTF-16に変換すると1文字2バイトに
なりますのでその分メモリの節約になるということです。
> wchar_t *wcRead = new TCHAR[nByteFile+1];
これを
wchar_t *wcRead = new wchar_t[nByteFile+1];
のようにしないのは何か理由があるのでしょうか?
(wchar_t と TCHAR)
kure様の補足は、理解できました。有り難うございす。
RAPT様のご指摘ですが、wchar_t と TCHAR の使い分けは、特に意図は
ありません。よく解らずにそうしています。
コンパイルのとき同じになるのではないかと思っていますが、どうなんでしょうか。
TCHARはマクロ次第でコンパイル時の実際の方が変わるので、
同じになる設定にすることはできますが、常に同じとは限りません。
char になってしまうと、おそらくコンパイルエラーになりますので、
検出はできるはずですが…。
Ban様 ありがとうございます。
wchar_t *wcRead = new wchar_t[nByteFile+1];
と書くことにします。
ツイート | ![]() |