Windows API/ファイル入出力
ファイルの入出力

Win32APIには、CreateFile関数などのファイル入出力の専用コマンドが用意されている。
ファイルの入出力

しかし、Win32APIでも標準C言語のfopen関数などのC言語規格の関数も使える。
ファイルの入出力

しかしWindowsAPIやVisual C++ の標準設定ではfopen関数などの古いC言語の関数が禁じられている場合があるので、
ファイルの入出力

その場合、使用を許可するために、下記のように#pragma warning(disable:4996)を下記のような位置に加える必要がある。
ファイルの入出力

のように。
ファイルの入出力

初心者にとっては、fopenなどC言語規格の関数を使うほうが、書店などに標準C言語の入門書も多いので、勉強が簡単だろう。
ファイルの入出力

ウィザードで自動作成したコードに、ファイル入出力のコードを追記するのが、簡単である。
ファイルの入出力

さて、CreateFile関数を使う場合、たとえば、「test.txt」というファイルを作成したい場合なら、
ファイルの入出力

の下に、下記のように書き加える。
ファイルの入出力

ウィザードの自動作成したコードに上記コードを追加したコードを、コンパイルする。
ファイルの入出力

成功すれば、特にメッセージは表示されないが、パソコンでソースコードのあるフォルダに、「test.txt」というファイルが加わっているのが分かる。
ファイルの入出力

この「test.txt」は拡張子のとおり、通常のテキストファイルであるので、test.txt のアイコンをダブルクリックするなどして開くと、文字を書き足したり保存することもできる。
ファイルの入出力

上述のコードのように、Win32API用の、無印C言語のファイル入出力関数ではない(つまりfopenなどではない)、ファイル入出力の関数がある。
ファイルの入出力

C言語のfopenなども、stdio.h をインクルードすればWin32APIでも使用可能であるが、しかし、TCHAR型の扱いの際に、特殊な操作が必要になってしまう。
ファイルの入出力

なので、Win32APIでは、なるべくCreateFileなどのウィンドウズAPI用のファイル関数を使うほうが簡単である。
ファイルの入出力

なお、Win32 API にかぎらず、
ファイルの入出力

一般に、ファイルの入出力のプログラミングでは、
ファイルの入出力

まず、ファイルを操作する際、
ファイルの入出力

などの特徴がある。
ファイルの入出力

また、ファイルを作成したりオープンした直後に、本当にその作業が成功したかどうかの確認のためのコードを入れるのが一般的である。
ファイルの入出力

なぜなら、ファイル入出力の関数は、パソコンのハードディスクを書き換えるので、エラーが起きた際、大きな被害に発展しかねない。
ファイルの入出力

なので、そのような誤作動にそなえて、ファイルのオープンなどが上手くいったかを確認する必要がある。
ファイルの入出力

そして、もしファイルのオープンに失敗した場合、終了する処理をコードに書くのが一般的である。(上記のコードでは、 return 1 で関数を終了させている。)
ファイルの入出力

CreateFile() 関数の機能は、その名とは違い、この機能はファイルを作成またはオープン(開く)する機能である。
ファイルの入出力

やや不正確な説明をするが、わかりやすく言うと CreateFile() 関数が作成しているものは、ファイル操作用ハンドルに必要な設定情報である。より正確に言うと、ハンドル(上記のコードでは hFile )がファイルを操作できるようにするために必要な諸設定を、 CreateFile() 関数は作成している。
ファイルの入出力

設定情報を作成しただけでは、どのハンドルでファイルを扱うかは指定されてないので、なので
ファイルの入出力

のように、ハンドル (上記の例では hFile )を指定する必要がある。
ファイルの入出力

C言語の入門書では、「変数は、入れ物(いれもの)である」と習ったのを思い出そう。ハンドル変数( hFile )に、ファイル操作用の設定情報( createFile で作成された設定情報)を入れる必要がある。
ファイルの入出力

そして、このファイル操作用ハンドルの設定の作成をする際に、目的のファイルのオープンもされる仕様になっている。(CreateFileの第一引数で、"test.txt" のように、対象のファイルを指定しているので、どのファイルを開く必要があるかを、この関数を使う関数の実行時点でOSが既に知っている。)
ファイルの入出力

すでに存在するファイルに読み書きをしたい場合にも、 CreateFile() を使って対象のファイルをオープンする必要がある。
ファイルの入出力

CreateFile() は、引数での指定によって、ファイル作成やファイルオープンなどの動作を指定できる。
ファイルの入出力

CreateFile() によって作成されたファイルハンドルは、自動的に開かれる。
ファイルの入出力

なので、目的のファイル処理が終わったら、
ファイルの入出力

CloseHandle() でファイルハンドルを閉じる必要がある。
ファイルの入出力

とあるが、いくつもある引数の意味は、それぞれ
ファイルの入出力

を設定している。
ファイルの入出力

正確な情報は、マイクロソフトmsdn を参照せよ。
ファイルの入出力

読み取りモードでアクセスする場合には、
ファイルの入出力

アクセスモードを
ファイルの入出力

にする。
ファイルの入出力

書き込みモードでアクセスする場合には、
ファイルの入出力

アクセスモードを
ファイルの入出力

にする。
ファイルの入出力

「共有モード」とは何かというと、上記のプログラムがファイルを開いている間、後続のアクセス関数がアクセスできるかどうかを指定することです。
ファイルの入出力

共有モードを「0」にすると、ファイルハンドルを閉じてからでないと、ほかのプログラムがアクセスできません。
ファイルの入出力

FILE_SHARE_READ に設定すると、ハンドルを閉じなくても、後続アクセスは読み込みだけ可能になります。
ファイルの入出力

同様に、 FILE_SHARE_WRITE に設定すると、ハンドルを閉じなくても、後続アクセスは書き込みだけ可能になります。
ファイルの入出力

難しいので、説明を省略。詳しくは マイクロソフトmsdn を参照せよ。
ファイルの入出力

NULL にすれば、特に指定しないことになります。
ファイルの入出力

名前こそ「作成方法」ですが(マイクロソフトMSDNがそう呼んでいる)、これは、ファイルが存在するとき(もしくは存在しないとき)、どう処理するかの指定です。
ファイルの入出力

CREATE_NEW なら、
ファイルの入出力

という意味です。
ファイルの入出力

他にも指定子はいろいろとありますが、すべて説明すると長くなってしまうので、詳しくは MSDN などを参考にしてください。
ファイルの入出力

ファイルの属性を、「読み込み専用」とか、いろいろと設定できるのですが、初心者にはめんどくさいので、何も設定しないでおきましょう。
ファイルの入出力

FILE_ATTRIBUTE_NORMAL を指定すれば、何も設定しないことになります。
ファイルの入出力

難しいので説明を省略。
ファイルの入出力

よく分からなければ、 NULL を指定しとけばいい。
ファイルの入出力

詳しくは、 マイクロソフト MSDN を参照せよ。
ファイルの入出力

まず、Win32APIには、ReadFile関数などのファイル入出力の専用コマンドが用意されている。
ファイルの入出力

しかし、Win32APIでも標準C言語のfgets関数などのC言語規格の関数も使える。しかし、ワイド文字を扱う場合、fgetwsになることに注意しよう。
ファイルの入出力

初心者にとっては、fgetwsなどC言語の関数を使うほうが簡単だろう。
ファイルの入出力

さて、Win32 API でテキストファイルなどの読み書きをする際、文字コードに気をつけなければならない。
ファイルの入出力

文字コードは、マイクロソフトの各ソフトウェアの標準設定に合わせておくのが、簡単である。
ファイルの入出力

アクセサリ「メモ帳」などテキストエディタの文字コードは、WindowsではANSIが標準の文字コードなので、メモ帳で作成したテキストファイルの文字コードをANSIに合わせておくのが簡単である。テキストファイルの文字コードを「ANSI」に設定するには、「名前をつけて保存」の際に「文字コード」の欄を「ANSI」にすれば良い。
ファイルの入出力

なお、マイクロソフト社の言う「ANSI」とは、けっして本物のANSI(いわゆるASCII(アスキー)コード)ではなく、マクロソフト社コード番号 CP932 という、ASCIIを拡張して日本JIS漢字規格など各国の規格などを追加したマイクロソフト社独自の文字コードのことである。日本では Shift-JIS として知られる。
ファイルの入出力

Visual Studio の文字コードは当面のあいだ、いじらないのが安全であるが、もし、すでにいじってしまった場合、UnicodeがVisual Studioの標準設定なので、Unicodeにすればいい。
ファイルの入出力

また、各アプリの文字コードと、Visual Stuido の文字コードとは、上述のように、別々のコードの場合があるので、混同しないように気をつけること。
ファイルの入出力

読み取らせたいテキストファイルの文字列型をどうすればいいか分からない場合、
ファイルの入出力

日本語の場合、ワイド文字型 wchar_t を使わないと、TextOutするのが困難になる。 char型でも不可能ではないかもしれないが、かなり面倒くさいので、ワイド文字型で説明する。
ファイルの入出力

例として
ファイルの入出力

としよう。
ファイルの入出力

まず、このテキストファイルの文字コードを「ANSI」に設定する。「名前をつけて保存」で、「文字コード」の欄を「ANSI」にすれば良い。
ファイルの入出力

いっぽう、Win32APIのプログラミングでは、まず、読み取った文字列を格納するための変数を、グローバル変数で、
ファイルの入出力

のように wchar_t 型の文字配列を宣言する。
ファイルの入出力

グローバル変数にする理由は、ファイル読み取りの関数と、画面表示などの別の関数で、読み取り結果を共有するので、グローバル変数で宣言する必要があるからである。
ファイルの入出力

そして次に、プログラム中のファイル読み取りを実行したい箇所で、
ファイルの入出力

などとして、str1 に読み取ったワイド文字を入れる。
ファイルの入出力

wcschr とは、 msdn に書いてあるが、ワイド型の文字列中で、ある文字(引数で指定する)が初めて出現する場所を見つけて、その位置を返す関数である。
ファイルの入出力

標準C言語に、strchr という、文字を検索して位置を返す関数がある。wcschr は strchr のワイド文字版である。
ファイルの入出力

上記のプログラム例では、改行文字\nを見つけて、それをヌル文字\0に置き変えている。ファイル検索の処理プログラムでよく使う定石なテクニックである。
ファイルの入出力

あとは、例えば読み取った文字列を表示したいなら、単に WM_PAINT で
ファイルの入出力

のように、すれば済む。
ファイルの入出力

座標(30,80)の位置に
ファイルの入出力

(カギ括弧なしの状態で)と表示される。
ファイルの入出力

なぜ、このような wchar_t で宣言するという仕組みになってるかというと、
ファイルの入出力

もちろん第一の理由は「マイクロソフト社がこういう風に作ってしまったから」であるが(マイクロソフト社の独自規格の問題なので)、
ファイルの入出力

別の理由もある。
ファイルの入出力

「Windowsではシステム内部の(ユーザーからは直接操作できない部分の)文字コードでは(自称)『Unicode』が使われており、
ファイルの入出力

一方、Windowsのシステム外部の(ユーザーの操作する)メモ長などのOS付属アクセサリやMSエクセルなどオフィスソフトの標準の文字コードでは(自称)『ANSI』コードが標準として使われているから」
ファイルの入出力

という事情がある。(マイクロソフト社の独自規格は、時代によって変更される可能性があるので(マイクロソフト社の都合により)、変更されても対応できるように、技術的な背景事情を把握しておく必要がある。)
ファイルの入出力

そして、TextOutなどWin32APIのいくつかの関数では、Windowsのシステム内部では出力文字の管理は Unicode で行っているようである。
ファイルの入出力

しかし、Windowsにおけるchar型は、どうやらASCIIコードや自称「ANSI」(Shift-JIS)を前提としてコンパイラ内部で処理しているようである。
ファイルの入出力

このため、Windowsシステム内部の「Unicode」とWindowsシステム外部の「ANSI」という、これら2種類の文字コードの調整のため wchar_型 で宣言する手間が生じるようである。
ファイルの入出力

もうひとつの理由として、英数字以外の文字の、バイト数の扱いがある。
ファイルの入出力

本来、char型が1バイト型だとしたら、日本語文字などの2バイト文字は入らないハズであるが、しかし過去の経緯により、コマンドプロンプト画面用プログラムではchar型にも漢字を格納できてしまうし、printfなどで日本語もコマンドプロンプト画面に表示できてしまう。
ファイルの入出力

しかし、TextOutなどWin32API専用の関数では、より厳密に型の管理をしているようであり、コマンドプロンプト画面とは違うようである。
ファイルの入出力

TextOutなどWin32API専用の関数では、char型でなく wchar_t で宣言しないと、日本語を格納しづらい。
ファイルの入出力

上述のような様々な理由が合わさり、win32APIでは、日本語文字の格納は、wchar_t 型で行うのが望ましいだろう。
ファイルの入出力

もし、すでに char 型やfprintf関数などで外部ファイルの文字列を読み書きするソースコードのある場合、わざわざ宣言時の型 wchar_t 型 や TCHAR型などで読み取るように書き換えなくても、
ファイルの入出力

WideCharToMultiByte() 関数 などの、文字列のための型変換の関数があるので、この関数による関数を、適切な箇所に追加すればいい。
ファイルの入出力

なお WideCharToMultiByte() 関数 の場合、これを使えば文字列の型をワイド型からマルチバイトに変換できる。windows7以降(Win7も含む)のWindowsでは、普通のテキストファイルを標準C言語にある関数(fopen や fgets など)や文字列型(char 型)で外部ファイルとの読み書きをする場合、Windows内部では読み書き後の文字列データはワイド文字列として処理されている場合があるので、その場合には、この関数だけでマルチバイト文字に変換できる。