こんにちは､ そしてお帰りなさい｡
この講義では､ ファイルへのアクセスについてお話したいと思います｡
つまり､ ディスク上のファイルには名前があり､ ファイル名の命名規則はOSによって決められているのです｡
プログラムが動作しているOSによって､ 名前を調整する必要があるかもしれません｡
プログラムがWindowsとLinuxで動作している場合､ 実際のディレクトリ構造も異なります｡
そのため､ フォワードスラッシュやバックワードスラッシュを使用する場合は､ プログラム側で調整する必要があります｡
しかし､ ほとんどの場合､ 名前は比較的､ 同じ命名規則などを持っています｡
でも､ 調整しなければならない可能性もありますよね｡
プログラムは､ ファイルポインタまたはストリームポインタを通じてファイルを参照する｡
ファイル以外でも動作するので､ 実は､ 先ほども触れましたが､
標準のio関数はどのデバイスでも動作するのです｡
つまり､ ファイルポインタと呼ばれていますが､ 本当はストリームポインタと呼ぶべきものなのです｡
プログラム実行時に､ ファイルポインタとファイルをプログラム的に関連付けます｡
つまり､ プログラムの中でポインターを作り､ それをファイル型にして､
読み書きをするときにファイルを表すようにするのです｡
このファイルポインターは､ 名前ではなく､ 実際にファイルを指し示すより効果的な方法として使用しています｡
なぜなら､ 名前は少し異なる場合があるからです｡
ポインターは､ 実際に指しているものを表すことになります｡
また､ ポインターを再利用して､ さまざまな場面で異なるファイルを指すことができます｡
ファイルポインタは､ ストリームを表す構造体型のファイルを指し示す｡
実際にファイル構造を見て､ その中にあるものをすべて確認することができます｡
しかし､ ファイルの読み書きや更新を行うかどうか､
データを保存しているメモリ上のバッファのアドレス､ 次の操作のためのファイル内の現在位置へのポインタなどの情報が含まれています｡
書き込みと読み込みを行う場所なので､ ポジションが重要だと述べました｡
そして､ 入出力ファイルの操作によって､ これらの情報をすべて構造体の中に設定することができます｡
入出力ファイルの操作では､ ファイルを開くときに､ 実際に読み込むか書き込むかを指定することになります｡
また､ これから説明するシークなどの方法で､ 現在の位置を変更することもできます｡
プログラム内で複数のファイルを同時に使用する場合は､ ファイルごとに別のファイルポインタを作成する必要があります｡
ファイルポインタを再利用できるのは､ 読み込みと書き込みを別々のタイミングで行う場合のみです｡
一度に開くことができるファイルの数には制限があります｡
標準的なIOの制限を見ることができ､ 定数f open
maxが定義されていますが､ どのオペレーティングシステムで実行しているかによります｡
しかし､ 通常､ 一度に大量のファイルを作成したり開いたりすることは避けたいものです｡
ファイルの書き込みや読み出しは､ ハードディスクに書き込むわけですから､ 高価な操作になります｡
メモリに書き込むほど高速ではないので時間がかかり､
プログラムの応答性が悪くなることもあるので
10個のファイルを開いて､ 同時に10個のファイルで書き込みをするようなことは避けたいものです｡
ファイルを開くには､ 読み書きの前に行う最初のステップとなる｡
そこで､ ファイルを開くと呼ばれる処理によって､
特定の外部ファイル名と最終的なポインタ全体を関連付けたいと考えます｡
ファイルを開いて見る方法は､ open関数を呼び出すことです｡
これは､ 読み書きに使用できるファイルポインタを返します｡
また､ ファイルポインタは､ ディスク上の特定の外部ファイルを指すことになります｡
Fのopenは､ ファイル名を取ることになる｡
fオープンは､ 読み書きをする前にしなければならないことです｡
通常､ 最初の操作になります｡
そして､ これらの関数のほとんどがそうであるように､ すべてstandardioで定義されているのです｡ h.
以下､ fの公募の定義です｡
戻り値がファイルポインタであることがわかると思います｡
すべて大文字で､ ファイル構造です｡
だからオールキャプスファイル｡
名前とモードを受け取りますが､ この制限はC11のものなので気にしないでください｡
本当に名前とモードへの文字ポインタを取るだけです｡
この関数の最初の引数は､ ファイル名を表す文字列へのポインタなので､
二重引用符で囲まれていることになります｡
名前を明示的に指定するか､ 文字列のアドレスを含む文字ポインタを使用することができます｡
つまり､ 文字列を作成してリテラルテキストに代入し､ その文字列を関数に渡すこともできますし､
関数呼び出しの内部で二重引用符で囲んで渡すこともできるのです｡
ファイル名は､ ユーザーからの入力としてコマンドラインから取得することもできますし､
プログラム側で定数として定義することもできます｡
読み書きをするのがいつも同じファイルで､ 名前が重要でないなら､
定数として参照すればいいのです｡
プログラムがもっと柔軟であれば､ ユーザーから何を読み､ 何を書きたいかという入力を得ることができます｡
f open関数の第2引数には､ ファイルモードを表す文字列を指定する｡
これは､ ファイルを読むか､ 書き込むか､ 追記するかなど､
ファイルに対して何をしたいかを指定するものです｡
ファイルモード指定は､ 二重引用符で囲まれた文字列で､
最終的にたくさん使うことになるものをいくつか紹介します｡
f openの呼び出しが成功した場合､ そのファイルポインタを全角で返します｡
そして､ このファイルポインタを利用して､
標準IOヘッダ内の他の入出力関数を呼び出すことができます｡
何らかの理由でファイルを開くことができない場合､ f openはnullを返すことになります｡
つまり､ 読み書きを始める前に､ ポインタがNULLでないことを確認する必要があるのです｡
ここで紹介したのは､ ファイルモードです｡
ファイルモードは､ f open 呼び出しの2番目のパラメータであることを思い出してください｡
これは､ ファイルに対して何をしたいかを指定するもので､ すべて二重引用符の中に入っています｡
つまり､ wとしたら､ テキストファイルを書き込み用に開くということです｡
aを実行した場合は､ テキストファイルを開いて追記することを意味し､ 書き込みはすべてファイルの末尾に行われます｡
rをすると､ テキストファイルを開いて読んでくれます｡
どれかにプラスをつけると､ 基本的にファイルが存在しない場合は作成されます｡
つまり､ wプラスファイルを開くと､ 更新のためにそれを開き､ ファイルが存在すれば0に切り捨て､
存在しなければ新しいファイルを作成する可能性があるのです｡
他のものでは､ 書き込みや読み取りが行われるため､ ファイルが存在しなければなりません｡
プラスも同じで､ 既存のファイルの末尾に追加､ 更新するために開くか､
ファイルが存在しない場合は作成します｡
そして､ rプラスは更新用のテキストファイルを開きますが､ そこは空っぽになるので､
ファイルを作成することはありません｡
だから､ 読書はrプラスを見たら読書も筆談もすればいいんです｡
他のプラスとは少し違っていて､ 存在しないファイルを実際に作っているのです｡
書き込みモード｡
myfileという名前の既存のテキストファイルに書き込みたい場合｡
txtの場合､ ファイルポインタを全角で作成することになります｡
nullに設定し､ 初期化する｡
そして､ ファイルを別の文字ポインタ､ myfileとして作成することになるでしょう｡
txt
を最初のパラメータとして渡し､ f open と言うだけです｡
F ファイル名を開き､ 二重引用符で囲んで w を指定すると､ 書き込み用にファイルが開かれ､
ファイルポインタが返されます｡
そのため､ 課題の左側にpファイルがありますね｡
そして､ pファイルがnullと等しくないことを確認します｡
なぜなら､ もしNULLだったら､ ファイル名が間違っているとか､
存在しないとか､ 何らかの理由でオープンに失敗したら､ そこに書き込むことができないからです｡
だから､ 開かない場合は必ずFチェックを行い､ 何らかの情報をプリントアウトしておきたいものです｡
このコードは､ ファイルを開き､ そのファイルをmyfileという名前に関連付けます｡
txt をファイルポインタ fp ファイルに置き換えてください｡
wモードは､ ファイルへの書き込みのみ可能で､ 読み込みはできないことを意味します｡
my file that textという名前のファイルが存在しない場合､
f openを呼び出すと､ この名前の新しいファイルが作成されます｡
これは､ f openにwオプションをつけた場合の話です｡
そして､ 前のモードで見たように､ w plusはファイルが存在しなければ作成しますが､
同時にファイルをゼロに切り詰めます｡
というのが違いますねw
wは存在しなければ作成しますが､ 0に切り捨てることはありません｡
つまり､ これがファイルを開くための標準的な方法であり､ ダブルクォートの中にあるwを使うのです｡
パス指定をせずにファイル名だけを指定した場合､
つまりこの例でやったように､ パス記憶はディレクトリの名前になります｡
もし､ ディレクトリの名前を提供しなければ､ プログラムが実行されている場所のカレントディレクトリにそのファイルがあると仮定します｡
もし､ 実際にプログラムディレクトリ以外の場所にあるファイルを開きたい場合は､
パス全体を指定する必要があります｡
それを絶対パスといいます｡
パスを指定しない場合は､ 通常､ 相対パスとなり､ プログラムが実行されている場所からの相対パスとなります｡
そのため､ 絶対パスと相対パスのどちらを指定しても構いませんが､
位置が分かっていることを確認し､ 正しい方を指定してください｡
相対的なパスは､ 依存性がないため､ 通常､ より良いものです｡
もし誰かがそのファイルを移動させたとしても､ それがどこに移動したかは関係ありません｡
ドットスラッシュを使えば､ プログラムが動作している場所からの相対パスで､
ディレクトリを2つほどさかのぼることができます｡
絶対パスで指定する場合､ Windowsであればc
colon program filesのような形になります｡
そして､ もしそのファイルが移動したら､ プログラムはそれを開くことができなくなる｡
したがって､ 書き込みのためにファイルを開くと､ ファイルリンクはゼロに切り捨てられ､
最初の操作では既存のデータの先頭に位置することになります｡
以前にファイルに書き込まれたデータは､ 書き込み操作によって失われ､
上書きされます｡
だから､ その上でプラスアルファを提供しなくても､ また､ 読み書きができないだけなんです｡
これは書き込みのみです｡
Wは右のみ｡
Wプラスとは､ 読み書きができることです｡
アペンドモード｡
既存のテキストファイルを上書きするのではなく､ 追加したい場合は､ aモードを指定することができます｡
これは依存です｡
これは､ 以前に書き込まれたデータの末尾にファイルを配置するものです｡
ファイルが存在しない場合は､ 新規に作成します｡
この例では､ 2番目のパラメータを二重引用符で囲まれたaに変更するだけで､
myfileの末尾に追加されます｡ のテキストを表示します｡
そして､ 毎回必ず戻り値がnullかどうかをテストすることを忘れないでください｡
if p file is not equal to nullは必ず実行したいところです｡
アペンドモードでファイルを開くと､ 各書き込み操作でファイル内のデータの末尾に位置することになります｡
すべての書き込み操作は､ ファイルにデータを追加し､ このモードでは既存のコンテンツを更新することはできません､
それはすべて最後にあります｡
リードモードでは､ ファイルを開いてファイルを読み込むことができます｡
二重引用符の中のrを使うだけです｡
これは読み取り専用で､ 書き込みはできません｡
rプラスをやれば､ 読み書きができるようになる｡
つまり､ 他の呼び出しと同じように､ fオープンして､ ファイル名を渡し､
二重引用符で囲んでrすると､ ファイル・ポインタが返されるのです｡
また､ ファイルの位置をデータの先頭に合わせます｡
ファイルを読み込むだけなら､ すでに存在しているはずです｡
空のファイルを読み込むことはない｡
つまり､ ファイルが存在しないので､ ファイルを作成するという選択肢はなく､
単に空になるか､ ファイルの相手がNULLであることが返されるだけです｡
存在しないファイルを読み込むために開こうとすると､
ヌルポインタを返します｡
もし､ それが存在し､ かつ空であれば､ 何もデータを返さないだけです｡
fオープンからの戻り値は必ず確認したい｡
改めて読むと､ 大事なことですね｡
なぜなら､ もしそれがヌルポインターなら､ プログラムはクラッシュし､ 何か悪いことをすることになるからです｡
ファイル名を変更する｡
これでファイルの開き方がわかった｡
ファイルを開くのが最初の操作で､ モードとファイル名を指定します｡
これにより､ ファイルポインタが返され､ それを使って他のことができるようになります｡
ファイル名の変更は時に重要です｡
とても簡単なことです｡
リネーム機能を使うだけです｡
旧名称と新名称を定数文字ポインタとして受け取り､
intを返す｡
返される整数は､ 名前の変更が成功した場合はゼロ､
そうでない場合は非ゼロになります｡
renameを呼び出すときは､ ファイルを開いていてはいけません｡
そうでなければ､ 使用中なので失敗します｡ 使用中のファイル名を変更することはできません｡
ここでできることは､ renameと言い､ 古いファイル名と新しいファイル名を渡すだけです｡
この例では､ windowsのファイルへのパスを使用しています｡
そして､ コロンが見えるからこそ､ それがウィンドウであることがわかると｡
また､ バックスラッシュが2回あることにも気づかれることでしょう｡
その理由は､ バックスラッシュがcの特殊文字であるためです｡
バックスラッシュnは行のフィードバックです｡
バックスラッシュ r はキャリッジリターンです｡
つまり､ バックスラッシュはプログラムの中で特別な意味を持っているのです｡
ですから､ 実際にバックスラッシュをディレクトリ内のパスに使いたい場合､ それはwindowsがそうであるように､
2つ用意する必要があるのです｡
そして､ ここではmyfileの名前を変更しています｡ txtでtempディレクトリを探す｡
それをmy file underscore copyにリネームしています｡ テキストをtemptディレクトリに保存します｡
そして､ それが1と等しくなければ､ 失敗するのです｡
失敗したという出力が出るだけです｡
それ以外の場合は､ 印刷が成功します｡
これは､ myfileの名前を変更することになります｡ txtをtempディレクトリにある私のファイルコピーにコピーしてください｡
ファイルパスが正しくない場合や､ ファイルが存在しない場合は､
リネームができません｡
また､ ファイルを閉じることもできるので､ ファイルを開くときは必ずこの操作を行いたい｡
ですから､ ファイルそのものを使い終わったら､ そのファイルを解放するようにオペレーティングシステムに指示したいのです｡
同時に開くことができるファイルの数には制限があることを忘れないでください｡
f close関数を呼び出すことで行うことができます｡
F closeは､ 引数としてファイルポインタを受け付ける｡
ファイルポインタは､ ファイルを表すことを忘れないでください｡
eofを返します｡
Eofはint型です｡
エラーが発生した場合､ eof を返す｡
EofはEnd of File Characterと呼ばれる特殊文字です｡
standardioで定義されています｡ h を負の整数とする｡
通常､ マイナス1と同等です｡
f クローズが成功した場合､ 0を返す｡
だから､ 不成功の場合はeofを確認することができます｡
ポインタでf close passと言うだけで､ ポインタをNULLにすることができ､
f closeを呼んだ結果､ ポインタ､ pファイル､ 物理ファイル間の接続が切断されます｡
P ファイルは､ 読み取り､ 書き込み､ または追加､ 名前変更のためのファイルへのアクセスに使用できなくなりました｡
ファイルへの書き込みが行われている場合､ データが失われないように､ 出力バッファの現在の内容がファイルに書き込まれます｡
そのため､ データの整合性に問題はなく､ 別のスレッドで書き込まれていたとしても､
実際にファイルを閉じることはありません｡
だから､ スレッドセーフなんです｡
スレッドの話はしていませんが､ それはもっと高度な概念です｡
しかし､ そこでプログラムの実行点を複数持つことができます｡
使い終わったらすぐにファイルを閉じるのが良いプログラミングの習慣であるのと同じように､
ファイルを閉じるのも同じです｡
出力データの損失から保護します｡
また､ ファイル名を変更したり削除したりする前に､
ファイルを閉じる必要があります｡
ファイルの削除はいかがでしょうか｡
remove関数を呼び出すと､ ファイルを削除することができます｡
これは､ standardioでも宣言されています｡ h.
ファイル操作はすべて標準的に宣言されています｡ ioh
cのヘッダーファイルがインストールされている場所であれば､ いつでもこのヘッダーファイルを見に行くことができます｡
つまり､ ファイル名を削除するというだけですね｡
ここでは､ ファイルポインタを使用する必要はありません｡
実際にファイルが開いていなくても削除できるからというだけでしょう｡
リネームも同様で､ リネームや削除が失敗するため､ 実際にファイルを開いてはいけないからです｡
myfileという名前のファイルを削除することになる｡ txtをカレントディレクトリから削除します｡
これは相対的なパスを提供しているのです｡
プログラムが実行されている場所ならどこでも､ そのファイルを探すことになる｡
そうでない場合は､ 絶対パスを指定する必要があります｡
リネームと同じように削除しようとすると､ ファイルを開くことができません｡
ファイルを削除するような操作では､ 必ずダブルチェックをする必要があります｡
このままではシステムを壊してしまうかもしれません｡
削除は非常に高価で､ 非常に危険な作業です｡
ファイルを削除すると､ 問題が発生することがあります｡
だから､ 気をつけよう｡
この講義のすべての情報は､ ファイルへのアクセス､
読み書きの前に必要なファイルを開く方法､ またファイルの削除や名前の変更､
そして使い終わったら閉じる方法に関係しています｡
全てはそのファイルポインタを元に行われます｡
だから､ そのファイルポインタとそれが含む構造を理解してください｡
かなり便利なものです｡
標準のioヘッダには､ すべての素晴らしい情報が含まれています｡
次の数回の講義では､ テキストファイルへの読み書き､
実際にデータを追加したり､ 追加したり読んだりすることについてお話します｡
ありがとうございます｡ 参考になったでしょうか｡