アプリ版:「スタンプのみでお礼する」機能のリリースについて

基本的に.NETしか知りませんので、C言語でAPIのReadFile使用して
ファイルを一気に全部バッファ読み込んだあと、
バッファから文字を一つずつ取り出すにはどうしたら
いいでしょうか?
Unicodeを使用することが前提で結構です。

なんか、根本的にわかってませんので。。。
よろしくお願いします。
C#とかなら、文字をインデックスで取得できますので、
C/C++となるとまったく、イメージできません。。。
ポインタを移動することで一バイトずつ操作することくらいは理解してます。

A 回答 (9件)

うーん。

それはC言語の基礎ですが
C言語は文字列の終端に0をいれます。
buffer[wReadSize/sizeof(wchar_t)] = 0;
と同じことですか。
明示的にUNICODEのNULL文字 L'\0'としています。
別に文字列として扱わないなら必要ありません。

しかし今回は
MessageBox関数に使用する為、bufferを文字列として扱う必要がある為
NULL文字をいれました。
mallocでwReadSize + sizeof(wchar_t) としているのも
NULL文字をいれるため文字数+1文字しているのです。

どんな言語でもそうですが、文字列を扱うには2通りの方法があって
今回のように文字列の終端に終端を表すNULL文字をいれる仕組みと
最初に文字数があってその後ろに文字列がくる仕組みです。
でなければコンピューターはどこまでが文字列なのか判断出来ません。

>この部分ってUNICODEファイルを読むときで必ず必要でしょうか?
>保険のようものでしょうか?
つまりUNICODEかどうかは関係ありませんし保険でも無く
文字列として扱うなら必ず必要ということです。
    • good
    • 0
この回答へのお礼

ありがとうございました。

大変勉強になりました。
文字列の終端のことで気になったのは今回おそらく私のどっかのミスで余計な文字が
読み込まれたので、それをきるために、そのようにされたのかなと思いましたので
質問させていただきました。
解説ですっきりしました。

.NETから入ってnative系の戻るってともてつらいです。。。
.NETが基本的なところ全部やってくれますので。。。スキルが上がりませんね。
これから出てくるPGならもっと不幸かもしれません(ある意味でです)。
#私は.NETが優れていると思います。

お礼日時:2005/09/02 10:32

HANDLE hFile = CreateFile( "text.txt", GENERIC_READ , 0 , NULL ,


OPEN_EXISTING , FILE_ATTRIBUTE_NORMAL , NULL);
DWORD wReadSize = GetFileSize(hFile , NULL);
wchar_t* buffer = (wchar_t*)malloc( wReadSize + sizeof(wchar_t) );
DWORD dw;
ReadFile( hFile , buffer , wReadSize , &dw , NULL );
buffer[wReadSize/sizeof(wchar_t)] = L'\0';
::MessageBox( NULL , buffer , L"test" , MB_OK );
free(buffer);
CloseHandle(hFile);
    • good
    • 0
この回答へのお礼

そのまま回答書いてくださいましたね<(_ _)>
ファイル読めてますね。ありがとうございます。
> buffer[wReadSize/sizeof(wchar_t)] = L'\0';
この部分ってUNICODEファイルを読むときで必ず必要でしょうか?
ほかのコードのファイルでも必要?
それとも、余計なものを確保される可能があるので、保険のようものでしょうか?

お礼日時:2005/09/02 02:02

開いているファイルのバイト数はいくつでしょうか。

可能であれば、ファイル内の各バイトの値も教えてください。

プログラム内で使用している各変数に最終的に設定されている値と、ファイルを読み込んだ後のバッファ内の値はいくつでしょうか。(ハンドルの値、ポインタの値は不要です。)

この回答への補足

メモ帳でUNIOCDE保存したファイル
サイズ 6 バイト
内容 aあ

wReadSize 3
dw 6

です。
なにおわかりでしょうか?
すいません。

補足日時:2005/09/02 01:29
    • good
    • 0
この回答へのお礼

補足がもうできませんので、お礼のとこで^^
やっているうちに漢字が取れました。
ありがとうございます。
依然として余計な文字が読み込まれますが。。

各値も漏れてましたね。
aあ 以外の化けている値は以下です。
65021
65021
43947
43947
43947
43947
65262

もしかして、UNICODEの制御文字?

文字コードが理解できてません。。。

お礼日時:2005/09/02 01:41

回答No.5の補足にあるコードですが、GetFileSizeが返す値は「バイト数」で、Unicode文字の文字数ではありません。

ですので、Unicode文字の文字数を得るにはsizeof(wchat_t)で割ってください。(注:ヘッダ込みの値になります。)

この回答への補足

ご回答ありがとうございます。

なんとなくそんな気もしましたので、
テストとして固定で 2 を入れてもやってみたのです。
なんか、とくに結果がかわりませんで、そのまま
ほうっておきました。
おっしゃる通りですね。

それでも結果が変わらないのはなんででしょうか。。?

それと、余計な文字を読み込み以外にポインタ移動や
配列のインデックス指定で漢字が取れません。。

根本的に間違ってますでしょうか?

補足日時:2005/09/02 01:03
    • good
    • 0

何を悩んでいるのかわかりませんが、


例えばテキスト文書が1000文字なら
wchar_t buffer[1000];
とでも用意してください。
(wchar_tはワイド文字の型です。U
NICODEを宣言しているならTCHARでも同じです。)

BOOL ReadFile(
HANDLE hFile, // ファイルのハンドル
LPVOID lpBuffer, // データバッファ
DWORD nNumberOfBytesToRead, // 読み取り対象のバイト数
LPDWORD lpNumberOfBytesRead, // 読み取ったバイト数
LPOVERLAPPED lpOverlapped // オーバーラップ構造体のバッファ
);
がReadFileの定義ですが

DWORD dw;
ReadFile( hFile , buffer , sizeof(wchar_t) * 1000 , &dw , NULL );
これで

buffer[1]・・・あ
buffer[2]・・・a
buffer[3]・・・b
buffer[4]・・・い
buffer[5]・・・c



とはいっているはずです。
ところでUNICODE-UCS2は全ては2バイトです。ですから半角とか全角とかは関係ありません。
まずメモ帳等でUNICODE形式を保存すればわかりますがテキストファイル
の最初にFF FE またはFE FFがつきます。これはLittleEndianかBigEndianの指標で
Windowsの標準はlittle endianです。
それを考慮してbuffer[0]からではなくbuffer[1]からにしています。

この回答への補足

以下のようにやってみましたが、やはりできません^^;
ステップ実行すると、確かにbufferに読み込まれるんですが、
最後に意味不明の文字が入ってしまいます。
ファイルはメモ帳でUNICODEで保存しました。
aあ
の2文字が入ってます。
bufferの値は正確に再現できません。化けてますので、おそらく投稿するとさらに違う変な文字になったりしてます。
bufferのポインタを移動するとやはり全角の文字は取れません。。
配列でもやってみましたが、同じ結果でした。

すいません。どんなところがおかしいでしょうか?
きっとおかしいでしょうが、発見できませんです。。。

HANDLE hFile = CreateFile( ファイル名, GENERIC_READ , 0 , NULL ,
OPEN_EXISTING , FILE_ATTRIBUTE_NORMAL , NULL);

DWORD wReadSize = GetFileSize(hFile , NULL);

wchar_t* buffer = (wchar_t*)malloc( sizeof(wchar_t) * wReadSize );

DWORD dw;

ReadFile( hFile , buffer , sizeof(wchar_t) * wReadSize , &dw , NULL );

free(buffer);

CloseHandle(hFile);

補足日時:2005/09/01 23:53
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。

> ところでUNICODE-UCS2は全ては2バイトです。ですから半角とか全角とかは関係ありません。

全くおっしゃる通りです。
私のそのように考えていました。
.NETではそのようになってますし。
しかしいざCでやってみるとあれ?なんか。。
え?うん~。。って感じでどうにもできませんでした^^;

今からもう一度やってみます。
また結果を報告いたします。

お礼日時:2005/09/01 22:37

読み込むファイルのエンコードはShift-JIS、UCS-2(いわゆるユニコード)、UTF-8、UTF-16のどれでしょうか。



参考:
http://www.atmarkit.co.jp/fxml/askxmlexpert/024u …

(マイクロソフトのCコンパイラを使うものと仮定します。)

Shift-JISの場合、2バイト文字の1バイト目であるかどうかは_ismbblead()関数で判定できます。_istlead()は_UNICODEが定義されている場合常にfalseを返すので、今回の場合おそらく使用できません。(_MBCSが定義されている場合_ismbblead()を返します。)

UCS-2(ユニコード)の場合、全角文字でも半角文字でも常に2バイトですから、1バイト目であるかどうかの判定は必要ありません。

UTF-8/16はよく知らないので省略します。
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。

お礼日時:2005/09/01 22:32

#2です。


例で書いたソースはあくまでもバイトごとに読み込むサンプルとして挙げただけですので、あとはご自分で作ってもらえればと思ったのですが・・・

とりあえずUnicodeの細かい処理は省いて(良くわからないので)1文字=4バイトとした場合のソースを書いておきます。

単純に文字で表示させます。
for( i = 0; i < len; i+=4 ){
printf( "%.4s\n", &p[i] );
}

一旦バッファに取り込むなら。
char w[5];
for( i = 0; i < len; i+=4 ){
strncpy( w, &p[i], 4 );
printf( "%s\n", w );
}

こんなんでよろしいでしょうか?
的外れなら補足お願いします。

この回答への補足

へんな質問ですいません。
全角、半角が混ざっているファイルですので、
forのループごとに同じ量の移動ができないです。
全角かどうかの判定がしたいですが、
ソース内部でUNICODEを#defineしているため
_istleadでしたっけ?が使えないようです。

どんな方法でもいいですが、
あabいc
のような文字の場合

a
b

c
と取り出したいだけです。

補足日時:2005/09/01 16:04
    • good
    • 0

例えば char* p に読み込んだとしたら、p[0] が0バイト目のデータです。


全データを16進で表示するサンプルを書いておきます。
len は ReadFile の4番目の引数の値(読み込んだバイト数)と思ってください。

例:
for( i = 0; i < len; i++ ){
printf( "%02x\n", p[i] );
}

もしくはポインタを使うならこうなります。

for( i = 0; i < len; i++, p++ ){
printf( "%02x\n", *p );
}
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。

すいませんです。いい忘れました。
全角、半角は混ざったファイルで
読み込んだ内容を"文字"として一つずと取り出すには
どうしたらいいでしょうか。書いていただいたサンプルがもしすでにそうなっていれば
もうすこし解説をいただけないでしょうか?
どうしても、一バイトずつ表示しているように見えてしまいます。
これでは2バイト文字は。。。?
すいません。

お礼日時:2005/09/01 13:56

ファイルの形式がどうなっているかにもよりますが、一文字ずつ取り出したいのならバッファから1バイトずつ配列にでもコピーすればいいのではないでしょうか。

    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。

お礼日時:2005/09/01 22:32

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!