MultiByteToWideCharでゴミが付かないようにするには

解決


ジャグラーV  2006-05-01 23:40:53  No: 61585

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;


たぶん  2006-05-01 23:42:54  No: 61586

オープンしたファイルを一度バッファにコピーしたらいいと思います。


Blue  2006-05-01 23:44:25  No: 61587

普通に終端文字がないだけなのでは?
CFile::Readでは文字列だと思って読み込んでいないので、
終端文字を付加する機能はありません。

f.Read(cANSI, nByteFile);
cANSI[ nByteFile ] = '\0';

としてみてはどうでしょうか?


Blue  2006-05-01 23:55:11  No: 61588

ちなみに、CStringのコンストラクタならば、
wchar_t*型でもchar*型でもTCHAR型の文字列を作れます。
http://msdn2.microsoft.com/ja-jp/library/cws1zdt8.aspx


kure  2006-05-02 00:03:16  No: 61589

> ::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]にした方がメモリ使用量を抑えられますよ。


ジャグラー  2006-05-02 00:44:24  No: 61590

たぶん様、Blue様、kure様
素速い応答、ありがとうございました。速いので驚きました。

cANSI[ nByteFile ] = '\0';
と、終端文字を付加することで、解決しました。
メモリ節約のアドバイスも有益です。ありがとうございました。


kure  2006-05-02 01:59:06  No: 61591

補足です。

> メモリ節約のアドバイス

これが当てはまるのはDBCS(Double Byte Character Set)
以外のMBCSのケースで、1文字3バイト以上が必要になるケースです。

コードを見るとCP_ACPを渡しており、環境次第ではDBCSじゃないケースが
あるかもしれません。その場合にメモリの節約になります。

提示されたコードはファイルサイズでnewしており
変換前のデータが1文字3バイトとすればUTF-16に変換すると1文字2バイトに
なりますのでその分メモリの節約になるということです。


RAPT  2006-05-02 05:38:04  No: 61592

> wchar_t *wcRead = new TCHAR[nByteFile+1];
これを
wchar_t *wcRead = new wchar_t[nByteFile+1];
のようにしないのは何か理由があるのでしょうか?
(wchar_t と TCHAR)


ジャグラーV  2006-05-02 07:51:49  No: 61593

kure様の補足は、理解できました。有り難うございす。
RAPT様のご指摘ですが、wchar_t と TCHAR の使い分けは、特に意図は
ありません。よく解らずにそうしています。
コンパイルのとき同じになるのではないかと思っていますが、どうなんでしょうか。


Ban  2006-05-02 08:03:40  No: 61594

TCHARはマクロ次第でコンパイル時の実際の方が変わるので、
同じになる設定にすることはできますが、常に同じとは限りません。
char になってしまうと、おそらくコンパイルエラーになりますので、
検出はできるはずですが…。


ジャグラーV  2006-05-02 17:26:37  No: 61595

Ban様  ありがとうございます。
wchar_t *wcRead = new wchar_t[nByteFile+1];
と書くことにします。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加