「C言語/ファイル入出力」の版間の差分

削除された内容 追加された内容
編集の要約なし
117 行
読者は、ソースファイルのあるフォルダを確認してみて、"test1.txt"というファイルが作られている事を確認しよう。
 
 
また、マウスでクリックして、このtest1.txtをみても、まだ何も文章は書き込まれていない事を確認しよう。
 
ソースファイルのあるフォルダの場所は、Windowsの場合、標準設定では
 
:\ユーザー名\source\repos\プロジェクト名\プロジェクト名
のアドレスのフォルダにある。
 
VisualStudio 2019 をインストールしたとき、既に source というフォルダのある場合を除けば、普通は インストール時に source という visual studio のプログラミング用のフォルダが自動作成されているので、そこのフォルダを探せばいい。
 
 
さて、このtest1.txtをマウスでクリックして、中身を見ても、まだ何も文章は書き込まれていない事を確認しよう。
 
 
749 ⟶ 759行目:
 
== 応用例 ==
=== 読み取りでオープンできなかったファイルは、クローズしてはいけない ===
Windows(Visual Studio)でもLinux(gcc)でも、
 
<code>fp1 = fopen("test1.txt", "r");</code> のような命令で読み込みに失敗した場合、つまり、普通なら読み込み対象のファイルが無い場合は、
 
そもそも、命令<code>fp1 = fopen("test1.txt", "r");</code>の実行直後は、
 
まだファイル"test1.txt"は、まったくオープンされて無い状態です。
 
なので、もしも、読み込み対象の失敗時のときの操作を、If文などの記述ブロックのなかに <code> fclose(fp1);</code> を記述しても、オープンしてないファイルをクローズしようとしており、そのため、エラーになります。
 
==== Windowsの場合 ====
いくつか前に示したコード、
 
;コード例(まだ改造してない)
<source lang=c>
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h> // 「続行するには何かキーを押してください . . .」を表示するのに必要。
 
#pragma warning(disable:4996)
 
 
 
int main()
{
FILE *fp1;
 
fp1 = fopen("test1.txt", "r");
if ( (fp1 = fopen("test1.txt", "r") ) == NULL) { // ここを読み取りモード"r"にするのを忘れないように
printf("ファイルを開けませんでした。\n");
system("pause");// 「続行するには何かキーを押してください . . .」の待機命令
return 1;
}
else{
printf("ファイルをオープンしました。\n");
}
 
char str1[150];
printf("文字列を読み取っています。\n");
fscanf(fp1, "%s", str1);
 
printf("ファイルに書いてある文字列\n");
printf("%s\n", str1);
 
fclose(fp1);
printf("ファイルをクローズしました。\n");
system("pause");// 「続行するには何かキーを押してください . . .」の待機命令
return 0;
}
</source>
 
 
は、次のようにも書き換えできる。
 
 
次のコードではelse文ブロックの中に、ファイルが存在していた時の処理をまとめている。
 
;改造したコード例 (Visual Studio 2019 および Windows 7 で確認ずみ)
<source lang=c>
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h> // 「続行するには何かキーを押してください . . .」を表示するのに必要。
 
#pragma warning(disable:4996)
 
int main()
{
FILE* fp1;
 
fp1 = fopen("test1.txt", "r");
if ((fp1 = fopen("test1.txt", "r")) == NULL) { // ここを読み取りモード"r"にするのを忘れないように
printf("ファイルを開けませんでした。\n");
//fclose(fp1); // ここでクローズするとエラー
system("pause");// 「続行するには何かキーを押してください . . .」の待機命令
return 1;
}
else {
printf("ファイルをオープンしました。\n");
 
char str1[150];
printf("文字列を読み取っています。\n");
 
fscanf(fp1, "%s", str1);
 
printf("ファイルに書いてある文字列\n");
printf("%s\n", str1);
 
fclose(fp1);
printf("ファイルをクローズしました。\n");
 
}
 
system("pause");// 「続行するには何かキーを押してください . . .」の待機命令
return 0;
}
</source>
 
------------
 
いっぽう、タイトルのとおり、下のようなコードがあると、エラーになります。
 
このエラーの起きるコードでは、if文の条件節にファイルポインタを使ったif文の中で、むりやりクローズしようとしています。
 
<source lang=c>
fp1 = fopen("test1.txt", "r");
if ((fp1 = fopen("test1.txt", "r")) == NULL) {
printf("ファイルを開けませんでした。\n");
fclose(fp1); // コメントアウトしないとエラーになる
system("pause");
return 1;
}
</source>
 
 
ついつい、ファイルを開けなかった場合などには、「この命令は用済みだから、すぐファイルを閉じよう(×)」って発想で、むりやりブロック中でクローズしようと思いたくなります。
 
しかし、上記のように、読み取りに失敗しあたとに、むりやりクローズしようとしても、実行時にエラーになります。
 
 
これはどういうことかというと、ファイルのオープンに失敗した場合、そもそも、そのファイルはオープンされてないのでクローズの必要もないです。
 
また、もしもオープンに失敗したファイルをクローズしようとした場合、実行時にエラーになります。
 
 
==== Linuxの場合 ====
Linuxでも同様です。もしもファイルのオープンに失敗した場合、Linuxでも、そのファイルはオープンされてないのでクローズの必要もないです。
 
また、もしもオープンに失敗したファイルをクローズしようとした場合、Linuxでも実行時にエラーになります。
 
Linuxの場合、コンパイルできてしまうかもしれ無い場合もありますが、しかしビルドされた実行ファイルの実行時にエラーになり、「コアダンプ」などのメッセージが表示されます。
 
 
たとえば、次のコードは、読み取り対象のファイル"SettingFile.txt"の無い場合には、実行時にエラーになります
<source lang=c>
// Linuxでエラーになる例
#include <stdio.h>
#include <stdlib.h> // Windowsでは「続行するには何かキーを押してください . . .」を表示するのに必要だった。
 
// #pragma warning(disable:4996) // Linux なので不要だし、あるとエラーの原因になる
 
int main()
{
FILE* fp1;
{
fp1 = fopen("SettingFile.txt", "r"); // まず、読み込みモードで開く。
 
if ( (fp1 = fopen("SettingFile.txt", "r") ) == NULL) { // 読み込みが失敗(NULL)の場合のブロック
printf("ファイルを開けませんでした。\n");
fclose(fp1);
}
else {
printf("ファイルを開けました。 \n");
fclose(fp1);
}
//fclose(fp1);
 
printf("ファイルを閉じました。 \n");
printf("終了しています。 \n");
//system("pause");// 「続行するには何かキーを押してください . . .」の待機命令
return 0;
}
}
</source>
 
 
いっぽう、次のように改善して、読み込み失敗後のクローズ命令を除去すれば、エラーにならず、実行できます。
 
(Fedora 31 で確認ずみ)
<source lang=c>
// Linuxでエラーにならない例
#include <stdio.h>
#include <stdlib.h> // Windowsでは「続行するには何かキーを押してください . . .」を表示するのに必要だった。
 
// #pragma warning(disable:4996) // Linux なので不要だし、あるとエラーの原因になる
 
int main()
{
FILE* fp1;
{
fp1 = fopen("SettingFile.txt", "r"); // まず、読み込みモードで開く。
 
if ( (fp1 = fopen("SettingFile.txt", "r") ) == NULL) { // 読み込みが失敗(NULL)の場合のブロック
printf("ファイルを開けませんでした。\n");
 
}
else {
printf("ファイルを開けました。 \n");
fclose(fp1); // elseが実行される場合、このブロックの始めではファイルがオープン状態なので、すぐ閉じたいなら、ここで。
printf("ファイルを閉じました。 \n");
}
//fclose(fp1); // ここではない。
 
printf("終了しています。 \n");
//system("pause");// 「続行するには何かキーを押してください . . .」の待機命令
return 0;
}
}
</source>
 
もし、読み取り対象のファイルの無い場合に、
 
上のコードの
// ここではない
の場所で<code> fclose(fp1);</code> でクローズすると、ファイルの存在しない場合にエラーになります。なぜなら、オープンしてないファイルをクローズしようとしているからです。そのような動作は、エラーになり、認められません。
 
 
同様に、elseブロック内でクローズした場合でも、さらに「ここではない」の場所でもう一度クローズしてしまうと、これもエラーになります。
 
 
 
=== 読み込もうとしたファイルが無い場合に、同名のファイルを作成したい場合 ===
 
883 ⟶ 1,112行目:
</pre>
 
=== if文の条件節にファイルポインタを使った場合にはブロック内でクローズできない ===
==== Windowsの場合 ====
タイトルのとおり、下のようなコードがあると、エラーになります。
 
このエラーの起きるコードでは、if文の条件節にファイルポインタを使ったif文の中で、むりやりクローズしようとしています。
 
<source lang=c>
if ( (fp1 = fopen("sanpuru1.txt", "r") ) == NULL) { // ここを読み取りモード"r"にするのを忘れないように
printf("ファイルを開けませんでした。\n");
system("pause");// 「続行するには何かキーを押してください . . .」の待機命令
 
fclose(fp1); // ここでクローズするとエラーになる。
return 1;
}
</source>
 
 
ついつい、ファイルを開けなかった場合などには、「この命令は用済みだから、すぐファイルを閉じよう(×)」って発想で、むりやりブロック中でクローズしようと思いたくなります。
しかし、上記のように、if文の条件節にファイルポインタを使ったif文の中で、むりやりクローズしようとしても、実行時にエラーになります。
 
 
 
ただし、所属しているブロックの条件判定文で'''使ってない''' ファイルポインタおよび別ファイルなら(たとえば ファイルポインタ fp20 と 対象ファイル名"sanpuru20" とする)、それは条件節のファイルとはまったくの別物ですので、fp1のif文のブロック内でも別物のfp20と"sanpuru20"はオープンすることもクローズも可能です。
 
 
==== Linuxの場合 ====
Linuxではファイルのオープンに失敗した場合、そもそもそのファイルはオープンされてないのでクローズの必要もないです。
 
また、もしもオープンに失敗したファイルをクローズしようとした場合、実行時にエラーになります。
 
コンパイルできてしまうかもしれませんが、しかしビルドされた実行ファイルの実行時にエラーになり、「コアダンプ」などのメッセージが表示されます。
 
 
たとえば、次のコードは、読み取り対象のファイル"SettingFile.txt"の無い場合には、実行時にエラーになります
<source lang=c>
// Linuxでエラーになる例
#include <stdio.h>
#include <stdlib.h> // Windowsでは「続行するには何かキーを押してください . . .」を表示するのに必要だった。
 
// #pragma warning(disable:4996) // Linux なので不要だし、あるとエラーの原因になる
 
int main()
{
FILE* fp1;
{
fp1 = fopen("SettingFile.txt", "r"); // まず、読み込みモードで開く。
 
if ( (fp1 = fopen("SettingFile.txt", "r") ) == NULL) { // 読み込みが失敗(NULL)の場合のブロック
printf("ファイルを開けませんでした。\n");
fclose(fp1);
}
else {
printf("ファイルを開けました。 \n");
fclose(fp1);
}
//fclose(fp1);
 
printf("ファイルを閉じました。 \n");
printf("終了しています。 \n");
//system("pause");// 「続行するには何かキーを押してください . . .」の待機命令
return 0;
}
}
</source>
 
 
いっぽう、次のように改善すれば、エラーにならず、実行できます。
 
(Fedora 31 で確認ずみ)
<source lang=c>
// Linuxでエラーにならない例
#include <stdio.h>
#include <stdlib.h> // Windowsでは「続行するには何かキーを押してください . . .」を表示するのに必要だった。
 
// #pragma warning(disable:4996) // Linux なので不要だし、あるとエラーの原因になる
 
int main()
{
FILE* fp1;
{
fp1 = fopen("SettingFile.txt", "r"); // まず、読み込みモードで開く。
 
if ( (fp1 = fopen("SettingFile.txt", "r") ) == NULL) { // 読み込みが失敗(NULL)の場合のブロック
printf("ファイルを開けませんでした。\n");
 
}
else {
printf("ファイルを開けました。 \n");
fclose(fp1); // elseが実行される場合、このブロックの始めではファイルがオープン状態なので、すぐ閉じたいなら、ここで。
printf("ファイルを閉じました。 \n");
}
//fclose(fp1); // ここではない。
 
printf("終了しています。 \n");
//system("pause");// 「続行するには何かキーを押してください . . .」の待機命令
return 0;
}
}
</source>
 
 
上のコード
// ここではない
の場所で<code> fclose(fp1);</code> でクローズすると、ファイルの存在しない場合にエラーになります。なぜなら、オープンしてないファイルをクローズしようとしているからです。そのような動作は、エラーになり、認められません。
 
 
同様に、elseブロック内でクローズした場合でも、さらに「ここではない」の場所でもう一度クローズしてしまうと、これもエラーになります。
 
=== メモのあるファイルの数値の読取 ===