Copyright(C) 11Feb2003 coskx
このページではCプログラムでファイルを取り扱う。
ここで修得してほしい内容は以下の通りである。
1.printfを用いたコンソール画面への出力と同じように,fprintfを使用してファイルへの出力が出来る。
2.scanfを用いたキーボードからの入力と同じように,fscanfを使用してファイルからの入力が出来る。
3.fgetc,fputc,fgets,fputsを使ってテキストファイルの処理が出来る
4.コマンドラインの取り込みと,引数を取り出すことが出来る
5.fread,fwriteを用いてバイナリファイルの入出力が出来る
演習における注意 ここでのプログラムの実行においては,実行形式ファイルおよび書き出すファイル,読み込み用ファイルはすべて同一ディレクトリに存在するものとし,実行はコンソール画面から行なう。
コンソール画面に文字を表示する時にはprintfを使った。
ファイルに文字を出力するにはfprintfを使う。
テキストを画面に表示する場合とファイルに書き出す場合のプログラムを並べて書いて比較してみよう。
「(A)画面出力」ではコンソール画面に文字が書
き出される。
「(B)ファイル出力」ではコンソール画面にはなにも出力されないがファイルmyfile.txtが出来る。テキストエディタでファイル
myfile.txtを開いてみると「(A)画面出力」でコンソール画面に表示された内容と同じテキストが書いてあることが確認できる。
表示したいテキスト
Hello. How are you?
Fine, thanks. And You?
So so.
List7.1.1 文字出力プログラムの比較 | |
(A)画面出力 |
(B)ファイル出力(ファイル名はmyfile.txt) |
#include
<stdio.h> int main() { printf("Hello. How are you?\n"); printf("Fine, thanks. And You?\n"); printf("So so.\n"); return 0; } |
#include <stdio.h> |
項目 |
プログラムでの記述 |
1.プログラム中でファイルを表す変数を宣言する。 変数宣言部で FILE *fp; 宣言の時だけ「*」の付く「変な変数名!」ということ にしておこう。 FILEは型名 fpは変数名なので別の名前でもよい。 この後,ファイルはファイル名ではなく, fp(ストリームと呼ばれる)で扱われる |
FILE *fp; |
2.ファイルのオープンとオープン失敗時の対策 |
fp=fopen("myfile.txt","w"); if (fp==NULL) { /*ファイルのオープンに失敗した場合は*/ printf("can't open a file\n"); /*失敗したと画面に表示*/ exit(1); /*緊急停止*/ } |
3.書き出したいことはここでfprintfで書く。 いくらでも書ける。 |
fprintf(fp,"Hello. How are
you?\n"); fprintf(fp,"Fine, thanks. And You?\n"); fprintf(fp,"So so.\n"); |
4.書き終えたらファイルをクローズする。 クローズしてしまったらもう書きこめない。 |
fclose(fp); |
List7.1.2 素数表(1000まで)のファイル出力 |
#include <stdio.h> /*****************コンソール出力******************** |
書き出された「primenumber.txt」 |
1000 までの素数 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199 211 223 227 229 233 239 241 251 257 263 269 271 277 281 283 293 307 311 313 317 331 337 347 349 353 359 367 373 379 383 389 397 401 409 419 421 431 433 439 443 449 457 461 463 467 479 487 491 499 503 509 521 523 541 547 557 563 569 571 577 587 593 599 601 607 613 617 619 631 641 643 647 653 659 661 673 677 683 691 701 709 719 727 733 739 743 751 757 761 769 773 787 797 809 811 821 823 827 829 839 853 857 859 863 877 881 883 887 907 911 919 929 937 941 947 953 967 971 977 983 991 997 素数は168個見つかりました。 |
課題7 その1 |
---|
(1)x,x2,x3の表を1≦x≦100でファイル出力するプログラムを作りなさい。
(p07ex01.c)
出力されたファイルの内容を実行結果として提出ファイルに貼り付けなさい。
x x^2 x^3 |
7.2 ファイルからの読み出し |
---|
プログラムのファイルととテキストファイルmydata1.txtを次の(B)のように作り,実行してみよう。
List7.2.1 データの読み出し | |||
(A)キーボードからのデータ読み出しプログラム #include <stdio.h> |
(B)ファイルからのデータ読み出しプログラム #include <stdio.h> | ||
テキストファイルmydata1.txt (実行前に作っておく)
| |||
実行時のコンソール出力 | 実行時のコンソール出力 | ||
123
456 data1=123 data2=456 |
data1=123 data2=456 |
項目 |
プログラムでの記述 |
1.プログラム中でファイルを表す変数を宣言する。 変数宣言部で FILE *fp; 宣言の時だけ「*」の付く「変な変数名!」ということ にしておこう。 FILEは型名 fpは変数名なので別の名前でもよい。 この後,ファイルはファイル名ではなく, fp(ストリームと呼ばれる)で扱われる |
FILE *fp; |
2.ファイルのオープンとオープン失敗時の対策 |
fp=fopen("mydata1.txt","r"); |
3.読み込みをfscanfで行なう | fscanf(fp,"%d %d",&data1,&data2); |
4.読み込み作業が終わったらファイルをクローズする。 クローズしてしまったらもう読めない。 |
fclose(fp); |
List7.2.2 ファイル中の成績データの処理 |
#include <stdio.h> |
fscanfに関する追加説明 |
関数fscanf()は,関数の返す値があり,実際に読み込むことに成功した数値の個数が返される。 |
テキストファイルmydata2.txt (実行前に作っておく) |
86, 75, 60 75, 68, 81 84, 98,100 87, 76, 48 82, 58, 73 100, 87, 98 64, 72, 70 87, 68, 99 98, 87, 68 87, 72, 84 |
実行時のコンソール出力 |
学生番号 英語 数学 国語 合計 0 86 75 60 221 1 75 68 81 224 2 84 98 100 282 3 87 76 48 211 4 82 58 73 213 5 100 87 98 285 6 64 72 70 206 7 87 68 99 254 8 98 87 68 253 9 87 72 84 243 平均 85.0 76.1 78.1 239.2 |
課題7 その2 |
---|
(2)次の枠内は,あるクラスの英語,数学,理科,国語の試験の得点一覧である。ファイルmarks.txtの中身である。これをダウンロードしなさい。(ブラウザで右クリック→ファイルに保存)
次に,このファイルを読み込み,List7.2.2のように各科目の平均点,学生ごとの総点,総点の平均(小
数点以下1桁まで)を求め,新たに一覧表ファイルmarks1.txtを作成するプログラムを作成しなさい。(p07ex02.c)
出力されたファイルの内容を実行結果として提出ファイルに貼り付けなさい。
70, 59, 56,
66 100, 100, 100, 100 68, 90, 96, 94 79, 92, 85, 75 64, 66, 72, 50 100, 100, 100, 100 81, 92, 86, 97 95, 88, 88, 79 78, 74, 75, 74 75, 80, 92, 75 87, 76, 77, 63 90, 90, 99, 100 68, 68, 67, 75 66, 66, 69, 71 71, 69, 73, 80 98, 81, 98, 97 100, 100, 100, 100 91, 100, 94, 92 89, 87, 73, 68 89, 100, 100, 94 21, 27, 26, 25 100, 100, 100, 100 36, 53, 32, 31 97, 74, 72, 85 86, 85, 81, 79 75, 71, 63, 72 88, 94, 87, 84 62, 68, 72, 60 62, 68, 62, 70 92, 88, 86, 70 57, 64, 69, 64 55, 77, 51, 73 58, 74, 80, 71 97, 91, 79, 100 69, 58, 72, 69 38, 54, 35, 19 31, 23, 34, 37 94, 85, 71, 63 64, 90, 71, 73 55, 51, 50, 48 97, 100, 100, 100 87, 83, 100, 85 |
7.3 テキストファイルの処理 |
---|
7.3.1 テキストファイルの構成 |
![]() |
ABCD[改行]EDG[改行]HIJKLMN[改行] |
のように一列の文字列で構成されている。
( EOF は End Of File のことである。)
ファイルダンププログラムでファイルの中を見ると,次のように見える。
文字コードの説明は「A.変数 (A.4 文字コード)(APPENDIX 2 文字コードに関する補足)」を参照のこと
kskdump.exeで見たファイルの内容表示([改行]は0d 0aで保存されているのがわかる)
kskdump.exeのダウンロード先
+0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +a +b +c +d +e +f 0123456789abcdef 0000000 :
0000010 :41 42 43 44 0d 0a 45 44 47 0d 0a 48 49 4a 4b 4c
4d 4e 0d 0aABCD..EDG..HIJKL
MN..
同様に
![]() |
kskdump.exeで見たファイルの内容表示([改行]は0d 0aで保存されているのがわかる) kskdump.exeのダウンロード先 |
ABCD[改行]EDG[改行]HIJKLMN |
のように最後の改行がない場合もある。
ファイルダンププログラムでファイルの中を見ると,次のように末尾に0d 0aがないことがわかる。
kskdump.exeで見たファイルの内容表示([改行]は0d 0aで保存されているのがわかる)
kskdump.exeのダウンロード先
+0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +a +b +c +d +e +f 0123456789abcdef 0000000 :
0000010 :41 42 43 44 0d 0a 45 44 47 0d 0a 48 49 4a 4b 4c
4d 4eABCD..EDG..HIJKL
MN
また
![]() |
#include <stdio.h>[改行][改行]int
main()[改行]{[改行] printf("Hello. How are
you?\n");[改行] printf("Fine, thanks. And You?\n");[改行] printf("So so.\n");[改行] return 0;[改行]}[改行] |
のように一列の文字列で構成されている。
kskdump.exeで見たファイルの内容表示([改行]は0d 0aで保存されているのがわかる)
kskdump.exeのダウンロード先
+0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +a +b +c +d +e +f 0123456789abcdef 0000000 :
0000010 :
0000020 :
0000030 :
0000040 :
0000050 :
0000060 :
0000070 :
0000080 :
0000090 :23 69 6e 63 6c 75 64 65 20 3c 73 74 64 69 6f 2e
68 3e 0d 0a 0d 0a 69 6e 74 20 6d 61 69 6e 28 29
0d 0a 7b 0d 0a 20 20 20 20 70 72 69 6e 74 66 28
22 48 65 6c 6c 6f 2e 20 48 6f 77 20 61 72 65 20
79 6f 75 3f 5c 6e 22 29 3b 0d 0a 20 20 20 20 70
72 69 6e 74 66 28 22 46 69 6e 65 2c 20 74 68 61
6e 6b 73 2e 20 41 6e 64 20 59 6f 75 3f 5c 6e 22
29 3b 0d 0a 20 20 20 20 70 72 69 6e 74 66 28 22
53 6f 20 73 6f 2e 5c 6e 22 29 3b 0d 0a 20 20 20
20 72 65 74 75 72 6e 20 30 3b 0d 0a 7d 0d 0a#include <stdio.
h>....int main()
..{.. printf(
"Hello. How are
you?\n");.. p
rintf("Fine, tha
nks. And You?\n"
);.. printf("
So so.\n");..
return 0;..}..
プログラム中でファイルから1文字読み込むには関数fgetc()を用い,ファイルへ1文字書き出すには関数fputc()を用いる。
OS
改行コード
Windows
0d + 0a
UNIX
0a のみ
7.3.2 テキストファイルの文字単位処理 |
テキストファイルを一文字ごとに処理する。
ここで大事な関数はfgetc()(ファイルからの1文字読み込み)とfputc()(ファイルへの1文字書き込み)である。
これらの関数については,「C.ライブラリ関数の説明」にまとめられている。
例1 |
テキストファイルから1文字読み込みで,ファイルの先頭の10文字を読み込み,画面に書き出すプログラム
読み込み対象ファイル「Peter.txt」 |
Peter ran straight away to Mr. McGregor's garden, and squeezed under the gate! First he ate some French beans; and then he ate some radishes. |
List 7.3.1 テキストファイルから1文字読み込みで,先頭10文字を読み込み,画面に書き出すプログラム |
#include <stdio.h> int main() |
実行結果(画面表示)「Peter ran 」までが読み込まれ表示されている。 |
0文字目 [P( 80 50H)] 1文字目 [e(101 65H)] 2文字目 [t(116 74H)] 3文字目 [e(101 65H)] 4文字目 [r(114 72H)] 5文字目 [ ( 32 20H)] 6文字目 [r(114 72H)] 7文字目 [a( 97 61H)] 8文字目 [n(110 6eH)] 9文字目 [ ( 32 20H)] |
例2 |
List 7.3.2
テキストファイルのコピー(1文字入力1文字出力) 関数fgetc()は,ファイル先頭から順にから1文字だけ読み取る関数である。ファイルの終わりに達してしまって,もう読み込むことが出来ない場合はEOFを返す。 | ||||
#include <stdio.h> int main()
|
式が値を持つことを利用するとwhileの部分をスマートに記述できる。 |
例3 |
List 7.3.3
テキストファイルの小文字大文字変換(1文字入力1文字出力) 関数fgetc()は,ファイルの終わりに達してしまって,もう読み込むことが出来ない場合はEOFを返す。 | ||||
#include <stdio.h>
toupperはASCIIコードのみに対応しているため,日本語の混じったテキストファイルに対してこの操作を行なうと,その結果は保証されません。 |
もし,ファイル内のアルファベットをすべて小文字にしたかったら |
例4 |
List 7.3.4 Cソースファイルの暗号化 | ||||
#include <stdio.h> | ||||
=====================暗号化の際のコンソール画面の様子=====================
| ||||
=====================復号化の際のコンソール画面の様子=====================
|
7.3.3 テキストファイルの行単位処理 |
テキストファイルから一行を文字列として読み込んで処理する。
ここで大事な関数はfgets()(ファイルからの1行読み込み)とfputs()(ファイルへの1行書き込み)である。
これらの関数については,「C.ライブラリ関数の説明」にまとめられている。
例5 |
読み込み対象ファイル「Peter.txt」 |
Peter ran straight away to Mr. McGregor's garden, and squeezed under the gate! First he ate some French beans; and then he ate some radishes. |
List 7.3.5 テキストファイルから1行ずつ読み込んで最初の3行を表示する |
#include <stdio.h> int main() |
実行結果(画面表示) |
0行目文字列 [Peter ran straight away to Mr. McGregor's
garden, ] 1行目文字列 [and squeezed under the gate! ] 2行目文字列 [First he ate some French beans; ] |
実行結果が3行にならず,「 ]
」が次の行に表示されているのは,関数fgetsが,改行コードも文字列の一部として取り込んでしまい,
文字列(char型配列)stringの行末に改行コードが入っているからである。(関数fgetsの説明を参照のこと)
テキストファイルのイメージ |
Peter ran straight away to Mr. McGregor's garden,[改行]and squeezed
under the gate![改行] First he ate some French beans;[改行]and then he ate some radishes. |
1行目を読み込んだイメージ |
Peter ran straight away to Mr. McGregor's garden,[改行] |
2行目を読み込んだイメージ |
and squeezed
under the gate![改行] |
3行目を読み込んだイメージ |
First he ate some French beans;[改行] |
もし改行コードが入っていなかったら,実行結果は次のようになるはずである。
1行読み込んだ時,末尾についている改行コードが邪魔な時がある。
仮想実行結果(現実にはこのようにはならない)
行末に改行コードが入っていなかったらこうなるはず0行目文字列 [Peter ran straight away to Mr. McGregor's garden,]
1行目文字列 [and squeezed under the gate!]
2行目文字列 [First he ate some French beans;]
例6 |
例5で使ったプログラムを変更し,各行の文字コードを表示し,改行コード(16進で0A)が入っているのを確認しよう。
ファイル中では改行コードは0d
0aの2バイトだったが,windowsでは,ファイルから読み出した後には0aのみ1バイトである。
表示はされないが,0aの後ろには文字列の終わりを示す00が入っている。
テキストファイルは「Peter.txt」を使用する。
List 7.3.6 テキストファイルから1行ずつ読み込んで最初の3行の文字コード表示を行なう |
#include <stdio.h> void printString(char
txt[]) int main() |
実行結果(画面表示) |
0行目文字列 [Peter ran straight away to Mr. McGregor's
garden, 1行目文字列 [and squeezed under the gate! 2行目文字列 [First he ate some French beans; |
行末に改行コード(16進で0A)が入っているのがわかる。その他は文字コード表で確認しておきなさい。
例7 |
List 7.3.7
プログラムソースファイルを読み込んで,行頭に行番号をつけて,テキストファイルに書き出す。 | ||||
#include <stdio.h> /*ファイル名のキーボード入力*/ /*ファイルのオープン*/ /*読み込み-書き出し作業*/ /*ファイルのクローズ*/
return 0;
|
課題7 その3 |
---|
提出実行結果は,出力されたファイルの内容を貼り付けることとします。 #include <stdio.h>
p05ex09.cで作った関数が使えるはずである。(正しく動作していれば)
#include
"stdio.h"
#include "stdlib.h"
#include "ctype.h"
:
が
"h.oidts"
edulcni#
"h.bildts" edulcni#
"h.epytc"
edulcni#
:
のようになる。プログラミングにおいて関数void reverseString(char
string[])を作り,用いなさい。
void reverseString(char
string[])は与えられた文字列stringを逆順にする関数である。
なお,ファイルから一行文字列を読み込むときにはfgets()を用いると思うが,これは行末に'\n'をつけたままで
読み込むので,これを取り除いてからreverseString()を使って反転し,ファイル書き出しの際に,'\n'を
付け加えるのが良い。
なお,実行の検査には次のファイルを用いなさい。(ダウンロード可能)
test.c.zip
int
main()
{
printf("Hello. How are
you?\n");
printf("Fine, thanks. And
You?\n");
printf("So so.\n");
return 0;
}
(5)入力ファイル中の単語を抜き出し出力ファイルへ書き出すプログラムを作成しなさい。単語とはアル
ファベットで始まり,アルファベットと数字とアンダーバー(_)のみでできている文字列である。単語の書き出しにおいては,単語ごとにスペースで区切っ
て,8つごとに改行するものとする.例えば何かのプログラムを入力ファイルとした時,次のようなファイルができるでしょう。なお,ファイル名は,コマンド
ラインからか,または,getsで読み込むものとする。(p07ex05.c)
参考プログラム(単語を抜き出して画面に表示している。課題とは異なる)
include stdio
h include stdlib h include ctype
h void main int argc char argv FILE
f1 f2
short int ch if argc printf
次のファイル(ダウンロード可能)について検証しなさい。(12qwe は数字で始まるため単語ではないので抽出されてはならない)
test.txt.zip |
1234 ..wer
qwe123+wer456 |
発展問題(挑戦課題です。力をつけたい人は挑戦してください) |
(6)「(5)」で入力ファイル中の単語を抜き出し,出力ファイルへ書き出したが,下のようにそれぞれの単語の出現回数を数えてその結果を出力ファ
イルに書き出しなさい。(ここまでに習得した文法のみを使うなら,2次元配列とカウンタ変数の配列が必要です。また「5.5
文字列操作の関数」や「C.ライブラリ関数の説明」で紹介したstrで始まる関数を便利に使います。文字列コピー関数(strcpy)や文字列の一致を調
べる関数(strcmp)があります。 チャレンジ課題)
(p07ex06.c)
include 3
stdio 1
h
3
stdlib 1
ctype 1
main
1
:
参考プログラム ポインタ,構造体を使用している
7.4 コマンドラインの取り込み |
---|
UNIXのコンソール,Windowsのコマンドプロンプト,Windowsのファイルのドロップに対応した内容
これはC言語の文法とは関わりはないが,将来システムプログラミングなどでは必須になる内容である。
興味があったらここを読むこと
興味があったらここを読むこと |
7.5 バイナリファイルの処理 |
---|
テキストファイルは文字コードと改行などの制御コードで出来ている。そのためエディタと呼ばれる種類のアプリケーションで内容を見たり,変更することが容易である。
これに対して,画像やサウンドを保存するファイルは,データのコンピュータ内部表現をそのまま保存しているファイルである。
例えば音を表現する時は,1/8000秒ごとの8ビットの数値の連続で音の波形データを表わすことがある。
例えば,グラフで音の波形を表すと次のようになるが,
![]() |
これを数値であらわすと,
0,31,56,68,66,50,25,-2,-24,-36,-33,-16,11,41,68,86,89,77,53,23,-6,-27,-36,-31,-12,13,40,....
の
ようになる。データをこのままテキストファイルとして保存してもよいが,1ポイントあたり4文字程度(4バイト)必要となる。しかし,各データは8ビット
であることが約束されているため,コンピュータ内部表現では,1バイトである。これをそのまま保存すると1ポイントあたり1バイトとなり,テキストファイ
ルで保存するのに比べ1/4のサイズのファイルとなる。
(実際のサウンドファイルや画像ファイルではファイルサイズを小さくするための工夫がなされ,ファイルの先頭にはヘッダーブロックと呼ばれる必要な一連のデータが保存されている部分がある。)
バイナリファイルはテキストエディタでは見ることができず,バイナリエディタやバイナリビュワーで見ることができる。
kskdump.exeを使うと内容を見ることができる。
kskdump.exeのダウンロード先
テキストファイルとバイナリファイルの書き出しと読み込みを比較してみよう。
テキストファイルの書き出しと読み込み | バイナリファイルの書き出しと読み込み |
/*テキストファイル"sample.txt"の書き出し*/ |
/*バイナリファイル"sample.bin"の書き出し*/ |
説明 sizeof()は与えられた項目のバイト数を得る演算子 sizeof(short int)は2となる (short intは2バイトであるため) 配列dataの要素数は20個であるため,メモリ上では40バイトになっ ているはずである。 そのため,sizeof(data)は40バイトとなる。 要素数は,40バイトを1要素当たりのバイト数2で割ったものになる はずだから dataSize=sizeof(data)/sizeof(short int)は要素数になる。 |
説明 dataSize=sizeof(data)/sizeof(short int)に関しては左の説明 の通り,要素数である。 fwrite(data, sizeof(short int), dataSize, fp); は,配列dataを書き込むが,sizeof(short int)バイト (これはshort intは2バイトなので2を表す)ずつ dataSize個(20個),ストリームfpに書き込みなさい という関数,関数の返す値は書き込めた項目数なので 20が返された。 |
テキストエディタでsample.txtを表示すると次のようになる。 1 2 3 4 : 途中省略 18 19 20 | テキストエディタでsample.binを表示しようとしても, 表示できない。 |
/*テキストファイル"sample.txt"の読み込み*/ int main() |
/*バイナリファイル"sample.bin"の読み込み*/ int main() |
説明 fread(data, sizeof(short int), 100, fp); は,2バイト(short intは2バイト)ずつ 100個までのデータを,ストリームfpから,配列data中に読み出しなさい という関数,関数の返す値は読み込んだ項目数なので 20が返され,dataSizeに20が格納され10この値が得られた。 20個のデータしか読み込まないのに, short int data[100]; となっているのは,読み込み時には,データがあふれる実行時エラーが 起こる可能性があるため,配列の大きさを大きめに取ります。 また fread(data,sizeof(short int),100,fp); の100というのは読み出すデータの数ではなく,読み込み可能な最大デ ータ数です。 | |
Windows
PCでの テキストファイル"sample.txt"の内容 (後半の表示は,データを文字として表示したものである。 表示できないデータは,「.」で表している。) kskdump.exeで表示したもの |
Windows
PCでの バイナリファイル"sample.bin"の内容 (後半の表示は,データを文字として表示したものである。 表示できないデータは,「.」で表している。) kskdump.exeで表示したもの |
sample.txt +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +a +b +c +d +e +f 00 : 31 0d 0a 32 0d 0a 33 0d 0a 34 0d 0a 35 0d 0a 36 10 : 0d 0a 37 0d 0a 38 0d 0a 39 0d 0a 31 30 0d 0a 31 20 : 31 0d 0a 31 32 0d 0a 31 33 0d 0a 31 34 0d 0a 31 30 : 35 0d 0a 31 36 0d 0a 31 37 0d 0a 31 38 0d 0a 31 40 : 39 0d 0a 32 30 0d 0a 0123456789abcdef 00 : 1..2..3..4..5..6 10 : ..7..8..9..10..1 20 : 1..12..13..14..1 30 : 5..16..17..18..1 40 : 9..20.. |
sample.bin +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +a +b +c +d +e +f 00 : 01 00 02 00 03 00 04 00 05 00 06 00 07 00 08 00 10 : 09 00 0a 00 0b 00 0c 00 0d 00 0e 00 0f 00 10 00 20 : 11 00 12 00 13 00 14 00 0123456789abcdef 00 : ................ 10 : ................ 20 : ........ |
参考 1 WindowsOSとUNIXでのテキストファイルの改行の取扱の違い
テキストファイル"sample.txt"の書き出し | 出力されたsample.txt |
#include
<stdio.h> #include <stdlib.h> /*関数exitのために必要*/ int main() { FILE *fp; short int data[]={ 1,2,3,4,5,6,7,8,9,10, 11,12,13,14,15,16,17,18,19,20 }; int dataSize; int i; fp=fopen("sample.txt","w"); if (fp==NULL) { printf("can't open a file\n"); exit(1); } dataSize=sizeof(data)/sizeof(short int); /*要素数を求めた (dataのバイト数)÷(short intのバイト数)*/ for (i=0;i<dataSize;i++) { fprintf(fp,"%d\n",data[i]); } fclose(fp); return 0; } | ![]() |
同じプログラムを実行しても,OSによって作成されるファイルは異なっている。
WindowsOSでは改行コード \n (LF)を出力した場合, 0d 0a(\r\n)(CR+LF)に変換され出力されるが,
UNIXではそのまま 0a (\n) (LF)のみが出力される。
CR: Carriage Return (文字ポインタを先頭に戻す。かつてのテレタイプで活字をのせたキャレッジを左端に戻していた。)
LF: Line Feed (改行する。かつてのテレタイプで紙送り機構が1行分紙を送った。)
Windows
PCでの テキストファイル"sample.txt"の内容 kskdump.exeで表示したもの | UNIXでの テキストファイル"sample.txt"の内容 kskdump.exeで表示したもの |
sample.txt +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +a +b +c +d +e +f 00 : 31 0d 0a 32 0d 0a 33 0d 0a 34 0d 0a 35 0d 0a 36 10 : 0d 0a 37 0d 0a 38 0d 0a 39 0d 0a 31 30 0d 0a 31 20 : 31 0d 0a 31 32 0d 0a 31 33 0d 0a 31 34 0d 0a 31 30 : 35 0d 0a 31 36 0d 0a 31 37 0d 0a 31 38 0d 0a 31 40 : 39 0d 0a 32 30 0d 0a 0123456789abcdef 00 : 1..2..3..4..5..6 10 : ..7..8..9..10..1 20 : 1..12..13..14..1 30 : 5..16..17..18..1 40 : 9..20.. | sample.txt +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F 00 : 31 0a 32 0a 33 0a 34 0a 35 0a 36 0a 37 0a 38 0a 01 : 39 0a 31 30 0a 31 31 0a 31 32 0a 31 33 0a 31 34 02 : 0a 31 35 0a 31 36 0a 31 37 0a 31 38 0a 31 39 0a 03 : 32 30 0a 0123456789ABCDEF 00 : 1.2.3.4.5.6.7.8. 01 : 9.10.11.12.13.14 02 : .15.16.17.18.19. 03 : 20. |
WindowsOSのプログラムでUNIX形式のファイルを作成したい
WindowsOSのプログラムでUNIX形式のテキストファイルを作成したいことがある。
その場合は,ファイルの開き方を変えれば可能である。(変更は1箇所)
fp=fopen("sample.txt","w");
↓
fp=fopen("sample.txt","wb");
このようにするとfprintfやfputs,fputcなどで改行コード \n を出力した場合, 0d 0a(\r\n)に変換されず,
そのまま 0a (\n) のみが出力され,UNIX形式のテキストファイルになる。
バイナリ出力の1つの使い方である。
すでにあるWindowsOS形式のテキストファイルをUNIX形式に変換したい
参考 2 intel(インテル)系CPU,とMotrola(モトローラ)系CPUによる複数バイト変数のバイトの並び順
WindowsPCはIntel系のCPUなので2バイトの表現時,順番が逆になる
「01
00」の2バイトで0001(10進数でも1)を表す。
「02 00」の2バイトで0002(10進数でも2)を表す。
:
「0f
00」の2バイトで000f(10進数では15)を表す。
「10
00」の2バイトで0010(10進数では16)を表す。
:
このようなバイト順のことをリトルエンディアン(little-endian)と呼ぶ。
motrola系のCPUでは2バイトの表現時の順番は順である。
「00
01」の2バイトで0001(10進数でも1)を表す。
「00 02」の2バイトで0002(10進数でも2)を表す。
:
「00
0f」の2バイトで000f(10進数では15)を表す。
「00
10」の2バイトで0010(10進数では16)を表す。
:
このようなバイト順のことをビッグエンディアン(big-endian)と呼ぶ。
Windows
PC(intel系CPU使用)での バイナリファイル"sample.bin"の内容 | モトローラ系CPUでの バイナリファイル"sample.bin"の内容 |
sample.bin +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +a +b +c +d +e +f 00 : 01 00 02 00 03 00 04 00 05 00 06 00 07 00 08 00 10 : 09 00 0a 00 0b 00 0c 00 0d 00 0e 00 0f 00 10 00 20 : 11 00 12 00 13 00 14 00 0123456789abcdef 00 : ................ 10 : ................ 20 : ........ | sample.bin +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F 00 : 00 01 00 02 00 03 00 04 00 05 00 06 00 07 00 08 01 : 00 09 00 0a 00 0b 00 0c 00 0d 00 0e 00 0f 00 10 02 : 00 11 00 12 00 13 00 14 0123456789ABCDEF 00 : ................ 01 : ................ 02 : ........ |
課題7 その4 |
---|
(7)double型配列をバイナリファイルに格納し,もう一度読み出して,もとのデータが復元されることを確認しなさい。
1つのプログラム内の前半でファイルに書き出し,後半で読み込むようにする。
(p07ex07.c)
テストするデータと確認用作業は次のとおりとする。必要な変数は自分で増やすこと。
double ddata[10]={
1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0
};
double gdata[10];
:
printf("original data\n");
for (i=0;i<????;i++) printf("(%02d) %6.1f\n",i,ddata[i]);
:
ここでddataをfwriteでファイルに書き込む
:
ここでファイルからfreadでgdataに読み込む
:
printf("obtained data\n");
for (i=0;i<????;i++) printf("[%02d] %6.1f\n",i,gdata[i]);
(文章課題)ファイルに関するこのページの内容で重要なポイントをまとめてレポートにしなさい。ただし,初めの2行(ファイル名,ID,出席番号,氏名)は,これまでのプログラムと同様な書式で書くこと。 (p07.txt)
ただし,次のキーワードは必ず含むこと
ファイル,ファイルのオープン,ファイルのクローズ,テキストファイル,バイナリファイル