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

削除された内容 追加された内容
Ef3 (トーク | 投稿記録)
→‎ファイルのオープン: エラーハンドリングを統一
タグ: 2017年版ソースエディター
Ef3 (トーク | 投稿記録)
scanf系の戻値チェック漏れ多数。文字列に読み込んで字句解析する安全なコードを示すべきでは?そうするにしても、Cではバッファ長の管理が煩雑になりがちでバッファオーバーランの温床。
タグ: 2017年版ソースエディター
140 行
さて、たとえばファイルに「test」とだけ書き込みたいなら、
<code>
fprintf(fp1fp, "test \n");
</code>
というふうに入力すればいい。
157 行
そのあと、プログラムがコード内でのファイル書き込み実行場所にて
<syntaxhighlight lang="C">
fprintf(fp1fp, "%d \n", var);
</syntaxhighlight>
のようなコードを実行するように、ソースコードを記述すればいい。
179 行
int main()
{
FILE *fp1fp = fopen("test1.txt", "w");
if (fp1fp == NULL) {
perror("ファイルtest1.txt を開けませんでした。\n");
return 1;
}
printf("ファイルtest1.txt をオープンしました。\n");
else {
printf("ファイルをオープンしました。\n");
}
 
char string[50];
printf("キーボードから文字列を入力してください。\n");
if (scanf("%s", &string); == EOF) {
perror("");
return 1;
}
printf("入力された文字列は %s です。 \n", string);
 
printf("これをファイルに書き込みます。 \n");
 
fprintf(fp1fp, "%s \n", string);
 
fclose(fp1fp);
printf("ファイルをクローズしました。\n");
}
247 ⟶ 248行目:
int main()
{
FILE *fp1fp = fopen("test1.txt", "r");
if (fp1fp == NULL) { // ここを読み取りモード"r"にするのを忘れないように
perror("ファイルを開けませんでした。\n");
return 1;
260 ⟶ 261行目:
printf("文字列を読み取っています。\n");
if (fscanf(fp1fp, "%s", str1); == EOF) {
perror("");
 
return 1;
}
printf("ファイルに書いてある文字列\n");
printf("%s\n", str1);
 
fclose(fp1fp);
printf("ファイルをクローズしました。\n");
}
296 ⟶ 299行目:
int main()
{
FILE *fp1fp = fopen("test1.txt", "r"); // ここを読み取りモード"r"にするのを忘れないように
if (fp1fp == NULL) {
perror("ファイルを開けませんでした。\n");
return 1;
308 ⟶ 311行目:
printf("文字列を読み取っています。\n");
 
if (fscanf(fp1fp, "%s", str1); == EOF) {
perror("");
return 1;
}
printf("ファイル1行目に書いてある文字列\n");
printf("%s\n", str1);
 
 
if (fscanf(fp1fp, "%s", str1); == EOF) {
perror("");
return 1;
}
printf("ファイル2行目に書いてある文字列\n");
printf("%s\n", str1);
 
fclose(fp1fp);
printf("ファイルをクローズしました。\n");
}
363 ⟶ 372行目:
int main()
{
FILE *fp1fp = fopen("test1.txt", "r"); // ここを読み取りモード"r"にするのを忘れないように
if (fp1fp == NULL) {
perror("ファイルを開けませんでした。\n");
return 1;
375 ⟶ 384行目:
printf("文字列を読み取っています。\n");
fgets(buffer1,150,fp1fp);
 
printf("1回目に読み取った文字列\n");
printf("%s", buffer1);
 
fgets(buffer1,150,fp1fp);
printf("2回目に読み取った文字列\n");
printf("%s", buffer1);
 
fclose(fp1fp);
printf("ファイルをクローズしました。\n");
}
420 ⟶ 429行目:
int main()
{
FILE *fp1fp = fopen("test1.txt", "r"); // ここを読み取りモード"r"にするのを忘れないように
if (fp1fp == NULL) {
perror("ファイルを開けませんでした。\n");
return 1;
}
printf("ファイルをオープンしました。\n");
else {
printf("ファイルをオープンしました。\n");
}
 
char buffer1[150];
printf("文字列を読み取っています。\n");
if (fscanf(fp1fp, "%s", buffer1); == EOF) {
perror("");
return 1;
}
 
printf("1回目に読み取った文字列\n");
printf("%s", buffer1);
 
if (fscanf(fp1fp, "%s", buffer1); == EOF) {
printfperror("2回目に読み取った文字列\n");
return 1;
}
printf("2回目に読み取った文字列\n");
printf("%s", buffer1);
 
fclose(fp1fp);
printf("ファイルをクローズしました。\n");
}
509 ⟶ 522行目:
int main()
{
FILE *fp1fp = fopen("sample.csv", "r");
if (fp1fp == NULL) { // ここを読み取りモード"r"にするのを忘れないように
perror("ファイルを開けませんでした。\n");
return 1;
}
printf("ファイルをオープンしました。\n");
else {
printf("ファイルをオープンしました。\n");
}
 
char str1[150];
523 ⟶ 534行目:
printf("文字列を読み取っています。\n");
if (fscanf(fp1fp, "%[^,],%s,%s", str1,str2); == EOF) {
perror("");
return 1;
}
 
printf("str1として読み取った文字列\n");
531 ⟶ 545行目:
printf("%s\n", str2);
 
fclose(fp1fp);
printf("ファイルをクローズしました。\n");
}
598 ⟶ 612行目:
int main()
{
FILE *fp1fp = fopen("sample.csv", "r"); // ここを読み取りモード"r"にするのを忘れないように
if (fp1fp == NULL) {
perror("ファイルを開けませんでした。\n");
return 1;
}
printf("ファイルをオープンしました。\n");
else {
printf("ファイルをオープンしました。\n");
}
 
char buffer1[150];
printf("文字列を読み取っています。\n");
fgets(buffer1,150,fp1fp);
 
printf("1行目の文字列\n");
printf("%s", buffer1);
 
 
char str1[150];
623 ⟶ 633行目:
strncpy(str2, strtok(NULL,",") ,150);
 
printf("str1として読み取った文字列\n");
printf("%s", str1);
printf("\n");
 
printf("str2として読み取った文字列\n");
printf("%s", str2);
 
fgets(buffer1,150,fp1fp);
printf("2行目の文字列\n");
printf("%s", buffer1);
 
638 ⟶ 648行目:
strncpy(str2, strtok(NULL,",") ,150);
 
printf("str1として読み取った文字列\n");
printf("%s", str1);
printf("\n");
 
printf("str2として読み取った文字列\n");
printf("%s", str2);
 
fclose(fp1fp);
printf("ファイルをクローズしました。\n");
}
698 ⟶ 708行目:
int main()
{
FILE* fp1fp = fopen("sample.csv", "r");
if (fp1fp == NULL) { // ここを読み取りモード"r"にするのを忘れないように
perror("ファイルを開けませんでした。\n");
return 1;
720 ⟶ 730行目:
// 下記のline は読み取りたい行数
for (int line = 1; line <= 2; line = line + 1) {
fgets(buffer1, 150, fp1fp);
 
printf("%d行目の文字列\n",line);
743 ⟶ 753行目:
 
 
fclose(fp1fp);
 
printf("ファイルをクローズしました。\n");
807 ⟶ 817行目:
== 文字コード ==
{{Main|[[w:Microsoftコードページ932]]}}
Windowsの場合、システム内部の文字コードには原則的にUnicodeを使っているのだが、しかし例外的にコマンドプロンプトではマイクロソフト独自規格の文字コードを使っている。
 
マイクロソフト社は、これをアメリカ標準規格のANSIと呼んでいるが<ref>マイクロソフトは、CP932を「ANSI」とは自称しておらず、[https://docs.microsoft.com/ja-jp/host-integration-server/core/ansi-oem-code-page-support-snanls-1 ANSI/OEM Code Page Support (SNANLS)]の一環として、'''ANSI/OEM - Japanese Shift-JIS'''の名称でサポートしている。この節は、この誤解に基づいて編集されていることに注意する必要がある。</ref>、実は、中身は米国の行政府の定める本物の1バイト文字のANSIでなく、マイクロソフト独自規格の自称「ANSI」である。おそらく、マイクロソフト独自規格の自称「ANSI」は、日本語などの2バイト文字の表示機能を含むので、自称「ANSI」も2バイト以上の文字であろうと考えられている。
 
1980年代くらいの古い、マイクロソフト日本法人などの開発したShift-JISという比較的に低バイト文字(2バイト以上の文字)の独自規格を、マイクロソフト米国法人の古い低バイト文字(1バイト以上の文字)の文字コードとすりあわせた独自規格のことをマイクロソフト社は「ANSI」と称しているようだ。
 
いちおう、現在ではShift-JISは日本工業規格になっているが、実際のWindowsでの文字コードの実装では、Windows用に独自にアレンジされたものを使っており、厳密には区別のためCP932という文字コード名で、技術者は呼ぶ。
 
 
 
アクセサリ「メモ帳」などのテキストエディタの文字コードでも、標準設定では、マイクロソフト独自規格の自称「ANSI」を使っている。
 
 
 
 
さて、上述のプログラム例で紹介したソースコードのように、特に文字コードの指定をする必要なく、日本語も表示できる。
 
マイクロソフト社が、そのように、コマンドプロンプトの機能を調整しているからである。
 
 
コマンドプロンプトで表示する場合、読み取るテキストファイルの文字コードは自称「ANSI」形式にしておけばいい。アクセサリ「メモ帳」の標準コードは「ANSI」(マイクロソフト自称)になっているので、特に変更する必要は無い。
 
 
もし、単に、あるテキストファイルを読み取ってコマンドプロンプトで表示するだけの場合なら、むしろUnicodeは、使ってはならない(少なくとも初心者は)。
読み取り対象のテキストファイルをUnicodeなどに変換すると、コンソール表示の際には、文字化けをしてしまう。
 
 
 
ただし、コマンドプロンプト以外のGUIアプリケーションの作成では(Windows API というのを使うと、GUIアプリを作れる)、文字表示の関数がANSI形式に対応しておらず Unicode 対応になっている場合もある。最終的に現代のプログラマが作るアプリケーションのほとんどはGUIアプリであるので、Windowsシステム内部の文字コードがANSIとUnicodeに不統一になっているのは、これは深刻な問題である。
 
 
ソースコード中にある文字については、コンパイラがコンパイル時に調節してくれるのが、しかしソースコード外部のテキストファイルについては、コンパイラが調整してくれないので、テキストファイルの読み取って表示などをした際に文字化けが起きることがある。
 
 
つまり、結論から言うと、GUIアプリとコンソールアプリで共通のテキストファイルを使うことは、あきらめるべきである。
 
 
ANSIコード(マイクロソフト自称)でも日本語は表示できるのだが、よそのパソコンなどに移動した場合に文字化けをする可能性がある。
 
 
 
なお、コンソール表示では不要だが、本来なら、自称「ANSI」コードや2バイト文字では、英語以外の文字を扱う際、
 
<code>setlocale(LC_ALL, "japanese");</code>
 
のように、英語以外の文字コードとして、どこの言語を使用するのかを指定しないといけない。2バイト文字の2バイトだけでは、65536文字までしか区別できないので、文字情報だけでは世界中の文字を網羅することは不可能であり、そのため、対象の文字を限定するために、言語を指定する必要があるからである。
 
(なお、日本語の常用漢字は、約2000個である。なので、2バイト文字なら、言語指定があれば、十分に常用漢字を表現できる。)
 
 
もっとも、Windowsのコマンドプロンプトに表示する場合、そのような言語指定なく、表示できる。
 
 
 
== Linux の場合 ==
871 ⟶ 828行目:
int main()
{
FILE *fp1fp = fopen("test1.txt", "r"); // ここを読み取りモード"r"にするのを忘れないように
if (fp1fp == NULL) {
perror("ファイルを開けませんでした。\n");
return 1;
884 ⟶ 841行目:
printf("文字列を読み取っています。\n");
 
fscanf(fp1fp, "%s", str1);
printf("ファイル1行目に書いてある文字列\n");
printf("%s\n", str1);
 
 
fscanf(fp1fp, "%s", str1);
printf("ファイル2行目に書いてある文字列\n");
printf("%s\n", str1);
 
fclose(fp1fp);
printf("ファイルをクローズしました。\n");
 
946 ⟶ 903行目:
setlocale(LC_ALL, "ja_JP.UTF-8"); //ロケール(地域)を設定する。
 
FILE* fp1fp = fopen( "test1.txt", "r, ccs = UTF-8"); // ここを読み取りモード"r"にするのを忘れないように
if (fp1fp == NULL) {
wprintf(L"ファイルを開けませんでした。\n");
return 1;
959 ⟶ 916行目:
wprintf(L"文字列を読み取っています。\n");
 
fwscanf(fp1fp, L"%s", str1);
 
wprintf(L"ファイルに書いてある文字列\n");
966 ⟶ 923行目:
wprintf(L"\n");
 
fclose(fp1fp);
wprintf(L"ファイルをクローズしました。\n");
1,020 ⟶ 977行目:
_wsetlocale(LC_ALL, L""); //ロケール(地域)を設定する。
 
FILE* fp1fp = _wfopen( L"test1.txt", L"r, ccs = UNICODE");
if (fp1fp == NULL) { // ここを読み取りモード"r"にするのを忘れないように
wprintf(L"ファイルを開けませんでした。\n");
perror(0);
1,034 ⟶ 991行目:
wprintf(L"文字列を読み取っています。\n");
 
fwscanf(fp1fp, L"%s", str1);
 
wprintf(L"ファイルに書いてある文字列\n");
1,041 ⟶ 998行目:
wprintf(L"\n");
 
fclose(fp1fp);
wprintf(L"ファイルをクローズしました。\n");
}
1,072 ⟶ 1,029行目:
int main()
{
FILE *fp1fp = fopen("test1.bin", "wb");
if (fp1fp == NULL) {
perror("ファイルを開けませんでした。\n");
return 1;
1,085 ⟶ 1,042行目:
char buf[5] = {0x42,0x4d,3,4,5};
fwrite(buf, 1, 5, fp1fp);
fclose(fp1fp);
printf("ファイルをクローズしました。\n");
}
1,124 ⟶ 1,081行目:
int main()
{
FILE *fp1fp = fopen("test.txt", "r");
if (fp1fp == NULL) {
perror("ファイルを開けませんでした。\n");
return 1;
1,138 ⟶ 1,095行目:
printf("文字列を読み取っています。\n");
fread(str1, sizeof(unsigned char), sizeof(str1) / sizeof(str1[0]), fp1fp);
printf("ファイルに書いてある文字列\n");
printf("%s\n", str1);
 
fclose(fp1fp);
printf("ファイルをクローズしました。\n");
}
1,173 ⟶ 1,130行目:
int main()
{
FILE *fp1fp = fopen("test1.txt", "rb");
if (fp1fp == NULL) {
perror("ファイルを開けませんでした。\n");
return 1;
1,186 ⟶ 1,143行目:
printf("バイナリーデーターを読み取っています。\n"); // 「文字列」ではなくバイナリーデーター
fread(str1, sizeof(char), 50, fp1fp);
printf("ファイルに書いてあるバイナリーデーター\n");
1,195 ⟶ 1,152行目:
}
fclose(fp1fp);
printf("\nファイルをクローズしました。\n");