• ベストアンサー

C言語でファイルをよんだあとの料理方法

基本的に.NETしか知りませんので、C言語でAPIのReadFile使用して ファイルを一気に全部バッファ読み込んだあと、 バッファから文字を一つずつ取り出すにはどうしたら いいでしょうか? Unicodeを使用することが前提で結構です。 なんか、根本的にわかってませんので。。。 よろしくお願いします。 C#とかなら、文字をインデックスで取得できますので、 C/C++となるとまったく、イメージできません。。。 ポインタを移動することで一バイトずつ操作することくらいは理解してます。

質問者が選んだベストアンサー

  • ベストアンサー
  • sha-girl
  • ベストアンサー率52% (430/816)
回答No.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かどうかは関係ありませんし保険でも無く 文字列として扱うなら必ず必要ということです。

milkoX
質問者

お礼

ありがとうございました。 大変勉強になりました。 文字列の終端のことで気になったのは今回おそらく私のどっかのミスで余計な文字が 読み込まれたので、それをきるために、そのようにされたのかなと思いましたので 質問させていただきました。 解説ですっきりしました。 .NETから入ってnative系の戻るってともてつらいです。。。 .NETが基本的なところ全部やってくれますので。。。スキルが上がりませんね。 これから出てくるPGならもっと不幸かもしれません(ある意味でです)。 #私は.NETが優れていると思います。

全文を見る
すると、全ての回答が全文表示されます。

その他の回答 (8)

  • sha-girl
  • ベストアンサー率52% (430/816)
回答No.8

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);

milkoX
質問者

お礼

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

全文を見る
すると、全ての回答が全文表示されます。
  • xcrOSgS2wY
  • ベストアンサー率50% (1006/1985)
回答No.7

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

milkoX
質問者

お礼

補足がもうできませんので、お礼のとこで^^ やっているうちに漢字が取れました。 ありがとうございます。 依然として余計な文字が読み込まれますが。。 各値も漏れてましたね。 aあ 以外の化けている値は以下です。 65021 65021 43947 43947 43947 43947 65262 もしかして、UNICODEの制御文字? 文字コードが理解できてません。。。

milkoX
質問者

補足

メモ帳でUNIOCDE保存したファイル サイズ 6 バイト 内容 aあ wReadSize 3 dw 6 です。 なにおわかりでしょうか? すいません。

全文を見る
すると、全ての回答が全文表示されます。
  • xcrOSgS2wY
  • ベストアンサー率50% (1006/1985)
回答No.6

回答No.5の補足にあるコードですが、GetFileSizeが返す値は「バイト数」で、Unicode文字の文字数ではありません。ですので、Unicode文字の文字数を得るにはsizeof(wchat_t)で割ってください。(注:ヘッダ込みの値になります。)

milkoX
質問者

補足

ご回答ありがとうございます。 なんとなくそんな気もしましたので、 テストとして固定で 2 を入れてもやってみたのです。 なんか、とくに結果がかわりませんで、そのまま ほうっておきました。 おっしゃる通りですね。 それでも結果が変わらないのはなんででしょうか。。? それと、余計な文字を読み込み以外にポインタ移動や 配列のインデックス指定で漢字が取れません。。 根本的に間違ってますでしょうか?

全文を見る
すると、全ての回答が全文表示されます。
  • sha-girl
  • ベストアンサー率52% (430/816)
回答No.5

何を悩んでいるのかわかりませんが、 例えばテキスト文書が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]からにしています。

milkoX
質問者

お礼

ご回答ありがとうございます。 > ところでUNICODE-UCS2は全ては2バイトです。ですから半角とか全角とかは関係ありません。 全くおっしゃる通りです。 私のそのように考えていました。 .NETではそのようになってますし。 しかしいざCでやってみるとあれ?なんか。。 え?うん~。。って感じでどうにもできませんでした^^; 今からもう一度やってみます。 また結果を報告いたします。

milkoX
質問者

補足

以下のようにやってみましたが、やはりできません^^; ステップ実行すると、確かに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);

全文を見る
すると、全ての回答が全文表示されます。
  • xcrOSgS2wY
  • ベストアンサー率50% (1006/1985)
回答No.4

読み込むファイルのエンコードはShift-JIS、UCS-2(いわゆるユニコード)、UTF-8、UTF-16のどれでしょうか。 参考: http://www.atmarkit.co.jp/fxml/askxmlexpert/024utf/24utf.html (マイクロソフトのCコンパイラを使うものと仮定します。) Shift-JISの場合、2バイト文字の1バイト目であるかどうかは_ismbblead()関数で判定できます。_istlead()は_UNICODEが定義されている場合常にfalseを返すので、今回の場合おそらく使用できません。(_MBCSが定義されている場合_ismbblead()を返します。) UCS-2(ユニコード)の場合、全角文字でも半角文字でも常に2バイトですから、1バイト目であるかどうかの判定は必要ありません。 UTF-8/16はよく知らないので省略します。

milkoX
質問者

お礼

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

全文を見る
すると、全ての回答が全文表示されます。
  • ttyp03
  • ベストアンサー率28% (277/960)
回答No.3

#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 ); } こんなんでよろしいでしょうか? 的外れなら補足お願いします。

milkoX
質問者

補足

へんな質問ですいません。 全角、半角が混ざっているファイルですので、 forのループごとに同じ量の移動ができないです。 全角かどうかの判定がしたいですが、 ソース内部でUNICODEを#defineしているため _istleadでしたっけ?が使えないようです。 どんな方法でもいいですが、 あabいc のような文字の場合 あ a b い c と取り出したいだけです。

全文を見る
すると、全ての回答が全文表示されます。
  • ttyp03
  • ベストアンサー率28% (277/960)
回答No.2

例えば 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 ); }

milkoX
質問者

お礼

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

全文を見る
すると、全ての回答が全文表示されます。
  • 6dou_rinne
  • ベストアンサー率25% (1361/5264)
回答No.1

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

milkoX
質問者

お礼

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

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • C言語のvoid型ポインタ変数について。

    C言語のvoid型ポインタ変数について。 C言語のvoid型ポインタ変数について質問があります。 組み込み系の開発を行っているのですが、現在使用しているシステムで、 提供されている "API" を介してアプリケーション部のソフト作成を行っています。 この "API" ですが、引数の多くはvoid型ポインタとなっています。 ある人がこの引数がvoid型となっているのを見て、 『なんでvoid型なんや??、C言語でアセンブラと違うんやから、void型なんかにしない方が良い』 とおっしゃいました。 この意味がよくわからなかったのですが、なぜ void型はよろしくないんでしょうか? -- 僕が思うに、APIなんやから引数を void型ポインタ にすることでどんな型にも対応できる 汎用的であると感じ、逆にこの方が良いのではと感じたのですが。。 -API例---- int _exApiKannsuu( char in_data, void* out_data ) "in_data" をもとに "out_data" を取得する。 どーやらこの "out_data" が void型 であるのががよくないらしい・・

  • C言語において2バイト文字を検出するには?

    こんにちは。 C言語において、char型ポインタが指している文字が、2バイト文字の1バイト目かどうかを確認する事ができれば、文字列から2バイト文字を検出できると思うのですが、やり方が分かりません。 検索してみても、ややこしい事ばかり書かれていて、すっきりとした答えが見つかりませんでした。 何かいい方法を知っておられる方がいらっしゃれば、是非アドバイスを頂きたいと思います。 では、よろしくお願い致します。

  • C言語の勉強方法

    こんにちは。 今C言語の勉強方法で悩んでいます。 私のC言語暦は、大学の授業の時に、文法一通りを覚えました。(当時はオセロゲームの次の一手を考えるようなアプリを作りました。) ポインタに関しては、柴田望洋さんの「C言語ポインタの極意」という本を少し読みました。ぼんやりと理解しているような状態です。K&Rの本は概ね理解できます。(演習問題はやっていません。) 仕事としてしているわけではなく、本はいろいろ読んでいるのですが、あまり自分でサンプルコードを打ってみたりはしていません。演習問題も解いていません。 APIに関する知識は乏しいです。アルゴリズムとデータ構造は、ヒントがないと、自力では書く自信がありません。基本情報処理技術者の資格も持っていません。 こういったレベルですが、これからどういった勉強をすればいいでしょうか?アドバイスを頂けるとありがたいです。

  • 不具合が発生(API・C言語)

    WINDOWS APIをc言語でプログラムしているものです。 こちらのプログラムを書いたのですが、 http://onegaisimasune.web.fc2.com/main8.txt 左クリックで線を引くのですが、 線を引いていると普通の文字は消えないのですが、 ある操作をした整数を表示させるようにすると、 その整数が変わってしまいます。 どうしたら直るのでしょうか。 宜しくお願い致します。

  • C言語で ポインタって どういうメリットがあるの?

    C言語で ポインタって どういうメリットがあるのでしょうか? 使用例とかも教えてくれたら うれしいです

  • C言語に関することについて教えてください

    学校の問題集にでてきた問題がわかりません、どうか教えてください 1 プログラムの役割、必要性について説明せよ 2 プログラムにおける変数と定数の役割を説明せよ。また、ローカル変数の有効な範囲について説明せよ。 3 C言語で使う変数が他について、宣言子と、printf関数、scanf関数それぞれにおいて対応する書式指定子を対応表にせよ。また、変数名を決める際に守るべき文法上の規則と、プログラマとして配慮すべき事項を説明せよ。 4 配列について、その役割と定義方法を説明せよ。 5 コンピュータにおける文字処理に必須なアスキーコードについて説明せよ。 6 C言語における文字列について、文字列定数、文字列変数を説明せよ。 7 C言語における繰り返し処理の文法(for,while,do~while)を、プログラムコード列を示して説明せよ。 8 C言語における条件判断の文法(if,else,else if)を、プログラム列を示して説明せよ。 9 繰り返し、条件判断において利用する論理式(等値演算子、関係演算子、論理演算子等で記迷する式)について、その記迷の方法を論理和、論理積も含めて説明せよ。 10 変数のアドレスについて説明せよ。また、ポインタについて、アドレスとの関連性を踏まえて、その役割と定義方法を説明し、具体的な使い方のプログラムコード例を示せ。 11 ポインタと配列の関係について、ポインタによる配列操作を列に説明せよ。 12 関数について、その役割と定義方法について説明せよ(戻りがた、関数名、引数リスト)。また、自作関数をそれらを利用するmain関数のプログラムコード例を示せ。 13 scanf関数の戻り値について、その内容を説明して、どのような際に利用すると便利か、プログラムコード例を示して説明せよ。 14 引数にポインタを利用する関数のプログラムコード例を示して、ポインタの必要性、重要性を説明せよ。 15 構造体について、その役割と定義方法を説明し、具体的な使い方のプログラムコード例を示せ。 16 ファイルポインタについて説明し、ファイル入出力の方法についてプログラムコード例を示して説明せよ。

  • C言語で計算機をつくりたい

    大学でC言語の基礎の基礎(入門書レベル)を終了したばかりのものです。 一通りの関数とポインタなどは扱えるようになったので、C言語で実際に使えるプログラムを作りたいのです。 最終的には自分でよく使う統計関係の処理(不偏分散)などを行いたいのですが、いきなりそこまではできないのでまずは電卓を作ろうと思い立ちました。 根本的な考え方(どういった関数を使うか、その流れなど)だけで結構ですので、アドバイスを下さい。 お勧めの本、URL等ございましたら教えていただければ幸いです。

  • コンソールにUNICODE (C#)

    Console.WriteがUNICODEを出力してくれません。 Console.Write("(UNICODEを含んだ文字列)"); としてもUNICODE依存の文字は全部?になってしまいます。 Windows2000、XPのコンソールにはIMEやクリップボードからUNICODEが入力できるのは確認できているし、CからAPIのWriteConsoleWを使った場合でもUNICODEが出力できることは確認しています。

  • C言語 ダブルポインタを引数にもつAPI

    GetBuf ( char ** address, size_t *dataSize ); 第1引数: バッファの先頭アドレスをかえす 第2引数: バッファサイズをByte単位で返す 戻り値 1:成功      -1 取得失敗 typedef struct Test_t{ char* tempAddr; /* 先頭アドレスを格納 */ int bufSize; /* サイズを格納 */ } test_t 上記のAPIから情報を取得し、以下の構造体にデータを保持しようとしていますが GetBuffのダブルポインタの情報を構造体のメンバtempAddrに格納するにはどうしたらよいでしょうか このAPIのように引数でダブルポインタを使用するケースは一般的なのでしょうか? 教えていただけるとうれしいです。 よろしくお願い致します。

  • C言語

    今、独学でC言語を勉強しているんですが。 大きく、 条件処理、繰り返し処理、配列、関数、2次元配列、文字列、構造体、ファイル処理、乱数、検索、バブル・ソート、ポインタ まではやったんですが(参考書で勉強)。 その次になにを勉強したらよく分からないので、 何を勉強するべきか教えてください。 将来的にこれっと言った作りたいものは決めていません。 お願いします。