• 検索結果がありません。

02: 変数と標準入出力

N/A
N/A
Protected

Academic year: 2021

シェア "02: 変数と標準入出力"

Copied!
21
0
0

読み込み中.... (全文を見る)

全文

(1)

10: ファイル入出力

Linux にログインし、以下の講義ページ

を開いておくこと

http://www-it.sci.waseda.ac.jp/

teachers/w483692/CPR1/

1

2016-06-15

C プログラミング入門

基幹7 (水5)

(2)

標準ライブラリ関数によりファイルの出力を

行う

画像ファイルの生成を例題として

配列の作成を復習する

関数を作ってプログラムを構造化する

2

今日の内容

(3)

文字コードの羅列でできているもの

3

テキストファイルの中を覗いてみる

Dear all,

I hope you and your family are fine. ...

Linux のコンソールで,

od -ctx1 ファイル名

とすると、文字コードを表示できる。

コマンドの詳細は man od で見れる。

(4)

Portable gray map image

他に、PPM (カラー), PBM (2値) がある

単純なフォーマット

テキスト形式とバイナリ形式がある

4

PGM 画像ファイル

P2 4 4 255 0 127 255 255 127 255 127 0 127 255 127 0 0 127 255 255 PGM 画像ファイルの例 (テキスト形式) PGM 画像 (4×4 pixel) header 画素値 横幅 高さ [pixels] フォーマットを識別する マジックナンバー 画素値の最大値 (=白)

(5)

1.

テキストエディタで、前頁のテキストファイ

ルを作り、 mini.pgm というファイル名で

保存する

2.

ダブルクリックして画像ビューアで開く

4x4 ピクセルなので、拡大しないと見えない

手で作ると大変なので、プログラムで作りだ

そうというのが、今日の本題です。

5

実演: PGM 画像ファイルを手で作る

(6)

1.

ファイルを開く

プログラムから指定してた名前のファイルに読み

書きできるように準備すること

2.

ファイルを読む・ファイルに書き込む

I/O (input/output) と呼ばれる

通常は、ファイルの内容を順番にアクセスする

(シーケンシャルアクセス

; sequential access)

⇄ランダムアクセス

(random access)

3.

ファイルを閉じる

ファイルの処理を完了し、バッファに残っている

ものを全て出力する

6

ファイル入出力の流れ

(7)

7

例題: PGM ファイルの出力

#include <stdio.h> int main(void) { FILE *fp; fp = fopen("mini.pgm", "w"); fprintf(fp, "P2¥n"); fprintf(fp, "4 4¥n"); fprintf(fp, "255¥n"); fprintf(fp, " 0 127 255 255¥n"); ... fclose(fp); ... 開いたファイルを識別するため情報を指すポインタ ファイルポインタと呼ばれる。変数名は何でもよい ファイルを mini.pgm という名前で、 書きこみモードで開く

fopen(), fprintf(), fclose() などは stdio.h で 宣言されている

ファイル閉じる

(8)

fopen() にファイル名と

モードを指定

FILE 型へのポインタが返

ファイルを操作するために

必要な情報が入っている

変数に入れて使う

8

ファイルを開く

#include <stdio.h>

FILE *fopen(const char *filename, const char *mode );

fopen() のプロトタイプ モー 意味 "r" 読み込み (read)。ファ イルがなければエラーと なる。 "w" 書き込み (write)。既存 のファイルは削除される "a" 追記 (append)。既存の ファイルがあればその末 尾に追記され、なければ 新規作成される。 構造体(今後の講義で解説)であるが、 内容を理解する必要は通常ない

(9)

ファイルが開けない場合がある

読み込みモードで、ファイルが存在しない場合

書き込みモードで、書き込み禁止の場所の場合

etc...

失敗した場合 NULL ポインタが返る

9

ファイルオープンの失敗

{ FILE *fp; fp = fopen("some.file", "w"); if(fp == NULL) { // エラー処理を行う

(10)

ファイルに書き込むための関数を利用

fprintf() は printf() と同じ使い方だが、第1

引数にファイルポインタを与える

10

ファイルに文字列を書きだす

#include <stdio.h>

int fprintf(FILE *stream, const char *format, ...);

fprintf() のプロトタイプ 関数 内容 fwrite ポインタで指すメモリ領域を指定したサイズだけ読み取って、 ファイルに書き込む fputc (putc) 1バイトだけファイルに書き込む fputs 文字列をファイルに書き込む fflush バッファの中身をすべて書きだす その他のファイル書き込み関数

(11)

ファイルポインタを引数に fclose() を呼ぶ

ファイルの書き込みは、効率のためにバッ

ファリングがされるが、 fclose() は自動的に

fflush() を呼び出す

11

ファイルを閉じる

#include <stdio.h> int fclose(FILE *fp); fclose() のプロトタイプ

(12)

特定のパターンならループを使ってファイル

を書きだせば書けそう

複雑な場合は?

12

大きい画像を作る

{ FILE *fp; int i; fp = fopen("grad.pgm", "w"); ... for(i = 0; i < 4; ++i) {

fprintf(fp, "%d %d %d %d¥n", i*50, i*50, i*50, i*50); }

画素値 0, 50, 100, 150 の グラデーション

(13)

配列の各要素を画素値だと思って、そこに絵

を書く

ループを使ってファイルに書き出す

13

配列をキャンバスに使う

0 0 255 0 0 0 0 255 0 0 0 0 0 0 0 0 0 21 0 0

unsigned char image[32][32]

画素値の配列を作って、 絵を書く

(14)

14

コード例

{

FILE *fp; int x, y;

unsigned char image[32][32] = {{0}};

// image に絵を書く... // ファイル出力 fp = fopen("image.pgm", "w"); // エラーチェックをしてヘッダを書きだす ... for(y = 0: y < 32; ++y) for(x = 0; x < 32; ++x) { fprintf(fp, "%d ", image[y][x]); } fclose(fp); ... 32×32ピクセルの配列をつ くり、ゼロで初期化する。 配列 image に画素値をい ろいろ入れる 空白でそれぞれの画素値が 区切られるようにする 行、列の順番で考えている

(15)

1 バイト (unsigned char) の配列をそのまま

ファイルに書いた形式。ヘッダは P5

fwrite() を使って書きだす

15

PGM のバイナリ形式の場合

0 0 255 0 0 0 0 255 0 0 0 0 0 0 0 0 0 21 0 0

unsigned char image[32][32]

#include <stdio.h>

size_t fwrite(const void *buf, size_t size, size_t count, FILE *fp);

fwrite() のプロトタイプ

buf の指す場所から、 size [bytes] * count [個]の領域の値を fp の指すファ イルに書き出す

(16)

配列に様々な絵を書きこむ関数を実現するに

は、配列へのポインタとサイズを渡す

配列のサイズを関数は直接知ることができない

16

配列に絵を書く関数

// width x height の画像 img を color で塗りつぶす

void fill(unsigned char *img, int width, int height, int color) {

int x, y;

for(y = 0; y < height; ++y) {

for(x = 0; x < width; ++x) {

// NG: img[y][x] = color;

img[x + y*width] = color;

} } } ポインタ引数で配列の先頭 位置を知っただけなので、 2次元配列としてアクセス できない。代わりに、座標 からメモリ上の位置を計算 する width x height の領域の先 頭へのポインタ

(17)

ファイル名などをプログラムで生成

自動的に日付を付ける

連番にする

etc...

文字配列に出力するには、 sprintf() を使う

c.f. printf() →標準出力 (画面)

c.f. fprintf() →ファイル

17

配列に文字列を書きこむ

#include <stdio.h>

int sprintf(char *buffer, const char *format, ...);

(18)

sprintf() が書きだすのに十分大きい配列を

用意しておく

はみ出してもエラーは出ない

他の使われている領域を破壊する可能性がある

18

sprintf() の使い方

char filename[10] '¥0' '¥0' '¥0' '¥0' '¥0' '¥0' '¥0' '¥0' '¥0' '¥0' { char filename[10] = "";

sprintf(filename, "img-%d.pgm", 5);

'i' 'm' 'g' '-' '5' '.' 'p' 'g' 'm' '¥0' この例ではぎりぎりの文字 数となる。 5 の代わりに 10 としたら、はみ出してメ モリ破壊をしてしまう。 たとえば、ここが変数とな り、ループなどで変化する 実用上は 256 など、大きい 値を指定する

(19)

printf は

fprintf(

stdout

, "format string", …);

と同じ。

ファイルポインタ stdout は標準出力といい、

<stdio.h> で定義されている。

画面を一種のファイルとして扱っている

19

printf と stdout

(20)

printf => 標準出力 (画面)

fprintf => ファイル

sprintf => メモリ (配列)

(実は、 printf は stdout ファイルを指定した

fprintf と同じ)

20

まとめ

(21)

手順

fopen() のモードを "r" で開く

fgetc(), fgets() で文字列を読み込み、メモリに書

きこむ

fscanf() によって文字列を数値などに変換してメ

モリに書きこむ

• その後、 sscanf() によって処理をしてもよい

読み込みの処理は、書きこむよりも難しいこ

とが多い

ファイルに「正しい」情報があるとは限らない

EOFの処理については省略

21

テキストファイルの読み込み

参照

関連したドキュメント

90年代に入ってから,クラブをめぐって新たな動きがみられるようになっている。それは,従来の

このような背景のもと,我々は,平成 24 年度の 新入生のスマートフォン所有率が過半数を超えると

WAV/AIFF ファイルから BR シリーズのデータへの変換(Import)において、サンプリング周波 数が 44.1kHz 以外の WAV ファイルが選択されました。.

前章 / 節からの流れで、計算可能な関数のもつ性質を抽象的に捉えることから始めよう。話を 単純にするために、以下では次のような型のプログラム を考える。 は部分関数 (

BC107 は、電源を入れて自動的に GPS 信号を受信します。GPS

画像の参照時に ACDSee Pro によってファイルがカタログ化され、ファイル プロパティと メタデータが自動的に ACDSee

(注)本報告書に掲載している数値は端数を四捨五入しているため、表中の数値の合計が表に示されている合計

・カメラには、日付 / 時刻などの設定を保持するためのリチ ウム充電池が内蔵されています。カメラにバッテリーを入