C / C++」カテゴリーアーカイブ

ファイルの所有者・グループの設定

UNIXにおいてファイルの所有者や所属グループを変更するには chown 関数を呼び出します.
 
使い方: chown(ファイルのパス, ユーザID, グループID)
 
例えば,対象ファイルのパス名を格納する記憶へのポインタを char *p, ユーザIDが uid_t u に,グループIDが gid_t g に格納されているとき chown( p, u, g ) として実行します.
 
処理が正常に終了した場合,戻り値は0となります.
 
サンプルプログラム ファイル a の所有者・グループを設定する

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include	<stdio.h>
#include	<sys/types.h>
#include	<unistd.h>
 
int main()
{
	char	p[] = "a";
//	uid_t	uid = 501;
	uid_t	uid = 503;
	gid_t	gid = 20;
 
	if ( chown(p,uid,gid) != 0 ) {
		fprintf(stderr,"chown failed.\n");
	}
}

シンボリックリンクの作成と削除

 「シンボリックリンク」はUNIX独特のものです.
 
大抵のOSでは,ファイルの別名を意味するアイコンを作ることができます.
Microsoft Windowsでは「ショートカット」,
Apple OS Xでは「エイリアス」というものを作って,
ファイル本体とは別のものとして別名のアイコンを作ることがあります.
 
UNIX独自のファイルの別名として「シンボリックリンク」を理解してください.
 
シンボリックリンクを作成するための関数に symlink というものがあります.
使い方は簡単です.
 
元のファイルのパス名を文字列として格納した記憶へのポインタを char *p1,
リンク(別名)のパス名を文字列として格納した記憶へのポインタを char *p2,
として symlink(p1,p2) として関数を呼び出すことでシンボリックリンクが作成されます.
正常に実行が終了した場合の戻り値は 0 です.
 
サンプルプログラム1: ファイル s_symlink.c のリンク(別名)を s_symlink_l として作成する

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include	<stdio.h>
#include	<unistd.h>
 
int main()
{
	int	r;
	char	p1[] = "s_symlink.c", p2[] = "s_symlink_l", lnk[256];
 
	r = symlink(p1,p2);
	if ( r == 0 ) {
		r = readlink(p2,lnk,256);
		fprintf(stderr,"symlnk success!: %s -> %s\n",p2,lnk);
 
	} else {
		fprintf(stderr,"symlnk failure.\n");
	}
}

 
サンプルプログラム2: リンク s_symlink_l を解除する

1
2
3
4
5
6
7
8
9
10
11
12
13
#include	<stdio.h>
#include	<unistd.h>
 
int main()
{
	int	r;
	char	p[] = "s_symlink_l";
 
	r = unlink(p);
	if ( r != 0 ) {
		fprintf(stderr,"unlnk failure: %d\n",r);
	}
}

ディレクトリの作成/削除/移動

【ディレクトリの作成】
 ディレクトリを作成するための関数 mkdir の使い方について説明します.
 
使い方: mkdir( 作成するディレクトリのパス名 , アクセス権 )
 
ディレクトリを作成する際には,誰に対して読み書き・実行を許可するかという「アクセス権」を設定します.
 
アクセス権は
 1) ユーザに対する読み書き・実行
 2) グループに対する読み書き・実行
 3) 他人に対する読み書き・実行
の3種類を設定します.
 
アクセス権を意味する記号(定義)は下記の通りで,それらを論理和として組み合わせ,整数型の値にして mkdir の引数にします.

S_IRWXU	00700	ファイル所有者のアクセス許可用のビットマスク
S_IRUSR	00400	所有者の読み込み許可
S_IWUSR	00200	所有者の書き込み許可
S_IXUSR	00100	所有者の実行許可
 
S_IRWXG	00070	グループのアクセス許可用のビットマスク
S_IRGRP	00040	グループの読み込み許可
S_IWGRP	00020	グループの書き込み許可
S_IXGRP	00010	グループの実行許可
 
S_IRWXO	00007	他人 (others) のアクセス許可用のビットマスク
S_IROTH	00004	他人の読み込み許可
S_IWOTH	00002	他人の書き込み許可
S_IXOTH	00001	他人の実行許可

 
サンプルプログラム: アクセス権を設定してディレクトリ s_mkdir_d をつくる

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include	<stdio.h>
#include	<sys/stat.h>
 
int main()
{
	const char	dname[] = "s_mkdir_d";
	int		r;
	mode_t		mode;
 
	/*--- mode ---- read -- write - execute --------*
	 |   user	  1	  1	  1		|
	 |   group	  1	  0	  1		|
	 |   other	  1	  0	  1		|
	 *----------------------------------------------*/
	mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
 
	r = mkdir(dname,mode);
	printf("result: %d\n",r);
}

 
【ディレクトリの削除】
 ディレクトリを削除するための関数 rmdir の使い方について説明します.
 
使い方: rmdir( 削除するディレクトリのパス名 )
 
サンプルプログラム ディレクトリ s_mkdir_d を削除する

1
2
3
4
5
6
7
8
9
10
11
#include	<stdio.h>
#include	<unistd.h>
 
int main()
{
	const char	dname[] = "s_mkdir_d";
	int		r;
 
	r = rmdir(dname);
	printf("result: %d\n",r);
}

 
【ディレクトリの移動】
 ディレクトリを移動(カレントディレクトリを変更)するための関数 cd の使い方について説明します.
 
使い方: chdir( ディレクトリのパス名 )
 これを実行することで,カレントディレクトリを「ディレクトリのパス名」にすることができます.
 
サンプルプログラム ディレクトリ s_mkdir_d2 を作成した後そこに移動し,更に同じ名前のディレクトリ s_mkdir_d2 を作成する

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include	<stdio.h>
#include	<unistd.h>
#include	<sys/stat.h>
 
int main()
{
	const char	dname[] = "s_mkdir_d2";
	int		r;
	mode_t		mode;
 
	/*--- mode ---- read -- write - execute --------*
	 |   user	  1	  1	  1		|
	 |   group	  1	  0	  1		|
	 |   other	  1	  0	  1		|
	 *----------------------------------------------*/
	mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
 
	r = mkdir(dname,mode);
	printf("result: %d\n",r);
 
	if ( r == 0 ) {
		r = chdir(dname);
		if ( r == 0 ) {
			r = mkdir(dname,mode);
			printf("result: %d\n",r);
		} else {
			fprintf(stderr,"chdir failure: %s\n",dname);
		}
	} else {
		fprintf(stderr,"mkdir failure(1): %s[%d]\n",dname,r);
	}
}

ファイルのタイムスタンプの変更

指定したファイルのタイムスタンプを変更する方法について説明します.
 
UNIX ではファイルの時間に関する情報には次の3つのものがあります.
1) 最終アクセス時刻: atime
2) 最終更新時刻  : mtime
3) 最終属性変更時刻: ctime
 
この内 atime と mtime を,関数 utime を使って変更することができます.
 
utime を実行するに先立って,atime, mtime の値を utimbuf 構造体に格納しておく必要があります.
この構造体の内容に従って,指定したファイルのタイムスタンプを変更します.
 
utimbuf 構造体の定義

struct utimbuf {
	time_t actime;	/* atime : access time */
	time_t modtime;	/* mtime : modification time */
};

 
char *fname で示されるパスのファイルのタイムスタンプを struct utimbuf utb の内容にする

utime(fname,&utb)

処理が正常に終了すると戻り値は0となる.
 
サンプルプログラム s_utime.c:ファイル s_utime.out のタイムスタンプを1年後に設定する

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include	<stdio.h>
#include	<time.h>
#include	<sys/types.h>
#include	<utime.h>
 
int main()
{
	FILE	*f;
	time_t	t;
	char	ftime[128], fname[128];;
	struct	tm	*tstamp;
	struct	utimbuf	utb;
 
	/* file generation */
	sprintf(fname,"s_utime.out");
	f = fopen(fname,"w");
	fclose(f);
 
	/* setting 1 year later */
	t = time(NULL) + 86400 * 365;
	tstamp = gmtime(&t);
 
	strftime(ftime,sizeof(ftime),"%Y/%m/%d(%a) %H:%M:%S",tstamp);
	printf("%s\n",ftime);
 
	utb.actime = t;
	utb.modtime = t;
 
	/* changing time stamp */
	if ( utime(fname,&utb) != 0 ) {
		fprintf(stderr,"utime failure!\n");
	}
}

実行例

$ date			← 現在の日付を調べる
2015年 3月28日 土曜日 18時11分16秒 JST
$ s_utime		← 1年後の日付にする
2016/03/27(Sun) 09:11:24

この後 “ls -la” コマンドで s_utime.out のタイムスタンプを調べる

-rwxr-xr-x    1 user1  staff    9056  3 28 17:57 s_utime
-rw-r--r--    1 user1  staff     585  3 28 17:57 s_utime.c
-rw-r--r--    1 user1  staff       0  3 27  2016 s_utime.out

ディレクトリを開く

ディレクトリの配下には,いくつかのファイルやサブディレクトリが配置されています.
 
ここでは,ディレクトリに登録されているそれらの項目の名前を取得する方法について説明します.
 
1. ディレクトリを開く
 指定した名前のディレクトリを開くには opendir 関数を呼び出します.
この関数はディレクトリに関する情報を収めた DIR 構造体へのポインタを戻り値として返します.
処理が失敗すると NULL を返します.
 
ディレクトリを開いた後は,そのポインタが指し示す構造体のメンバにアクセスすることでディレクトリに関する情報を取得することができます.
 
例 char *path に与えられたディレクトリを開く

DIR	*dr;
dr = opendir(path);

 
2. ディレクトリ配下の項目を取得する
 readdir 関数を呼び出すことで開いたディレクトリの配下の項目を1つづつ取得することができます.
この関数は,項目の情報を格納する dirent 構造体へのポインタを戻り値として返します.
(項目を全部取得してしまった後は戻り値は NULL となります)
 
例 dr として開いたディレクトリから項目を取得する

struct	dirent	*de;
de=readdir(dr)

 
dirent 構造体の定義

struct dirent {
    ino_t          d_ino;       /* inode 番号 */
    off_t          d_off;
    unsigned short d_reclen;    /* このレコードの長さ */
    unsigned char  d_type;      /* ファイル種別 */
    char           d_name[256]; /* ファイル名 */
};

de->d_name を参照することで項目のファイル名を取得できる.
 
3. ディレクトリを閉じる
 ディレクトリへのアクセスが終われば,閉じる必要があります.
開いたディレクトリを閉じるには関数 closedir を呼び出します.
 
例 dr として開いたディレクトリを閉じる

closedir(dr);

 
サンプルプログラム: 指定したディレクトリ配下の項目を全てリストアップする

#include	<stdio.h>
#include	<sys/types.h>
#include	<dirent.h>
 
int main(ac,av)
int  ac;
char **av;
{
	char	*path;
	DIR	*dr;
	struct	dirent	*de;
	int	i = 0;
 
	path = av[1];
	dr = opendir(path);
	if ( dr == NULL ) {
		fprintf(stderr,"Can not open directory: %s\n",path);
		return(-1);
	}
 
	while ( -1 ) {
		if ( (de=readdir(dr)) == NULL ) {
			break;
		}
		i++;
		printf("item %03d: %s\n",i,de->d_name);
	}
 
	closedir(dr);
}

 
実行例: 上のサンプルを s_opendir.c として作って実行する.
プログラム本体が次のようなディレクトリにあるものとする.

$ ls -la
total 1200
drwxr-xr-x   16 user1  staff     544  3 27 19:47 .
drwxr-xr-x+ 166 user1  staff    5644  2 28 15:04 ..
-rw-------    1 user1  staff   12288  3 27 19:47 .s_opendir.c.swp
-rwxr-xr-x    1 user1  staff     369  6  1  2014 cmd1
-rw-r--r--    1 user1  staff     360  6  1  2014 inp
-rwxr-xr-x    1 user1  staff    8936  3 15 16:55 s_fstat
-rw-r-----    1 user1  staff    1488  3 15 16:55 s_fstat.c
-rwxr-xr-x    1 user1  staff    8780  3 27 19:47 s_opendir
-rw-r--r--    1 user1  staff     423  3 27 19:47 s_opendir.c
-rwxr-xr-x    1 user1  staff    8688  3 16 19:29 s_time
-rw-r--r--    1 user1  staff     450  3 16 19:29 s_time.c
-rwxr-xr-x    1 user1  staff    8568  3 15 21:49 s_timeb
-rw-r--r--    1 user1  staff     333  3 16 20:08 s_timeb.c
lrwxr-xr-x    1 user1  staff       9  3 15 16:22 sl -> s_fstat.c
-rw-r--r--@   1 user1  staff  258640  3 15 16:26 sl2
-rw-r--r--@   1 user1  staff  258640  3 15 20:57 sl3

ここでプログラムを実行して,このディレクトリ自身 “.” の中身をリストアップする.

$ s_opendir .
item 001: .
item 002: ..
item 003: .s_opendir.c.swp
item 004: cmd1
item 005: inp
item 006: s_fstat
item 007: s_fstat.c
item 008: s_opendir
item 009: s_opendir.c
item 010: s_time
item 011: s_time.c
item 012: s_timeb
item 013: s_timeb.c
item 014: sl
item 015: sl2
item 016: sl3

ファイルの属性の取得

ファイルシステムにはファイルディレクトリリンクといった異なる種類の実体があります.また,それらにはアクセスされた時刻の情報も属性として記録されています.
 
ここでは,指定したパスの実体の属性を調べる方法について説明します.
 
指定したパスの属性を取得するには stat という関数を呼び出します.
また,stat の呼び出しで得られた属性の情報は stat 構造体に格納されます.
 
例.ポインタ cahr *path によって示されるパス名の文字列があるとき,そのパスの属性を得る方法

struct	stat	buf;
r = stat(path,&buf);

(int r は戻り値で,stat の処理が正常に終了した場合は 0 となる)
これにより,構造体 buf にパスの各種の属性が格納される.
 
指定したパスがシンボリックリンクである場合,そのリンク先の実体の属性を求めるのか,あるいはリンクそのものの属性を求めるかは全く意味が異なります.
「リンクであるかどうか」の情報が必要な場合は stat ではなく lstat を用います.
 
構造体 stat の定義

struct stat {
	dev_t     st_dev;     /* ファイルがあるデバイスの ID */
	ino_t     st_ino;     /* inode 番号 */
	mode_t    st_mode;    /* アクセス保護 */
	nlink_t   st_nlink;   /* ハードリンクの数 */
	uid_t     st_uid;     /* 所有者のユーザー ID */
	gid_t     st_gid;     /* 所有者のグループ ID */
	dev_t     st_rdev;    /* デバイス ID (特殊ファイルの場合) */
	off_t     st_size;    /* 全体のサイズ (バイト単位) */
	blksize_t st_blksize; /* ファイルシステム I/O での
					ブロックサイズ */
	blkcnt_t  st_blocks;  /* 割り当てられた 512B のブロック数 */
	struct timespec st_atim;  /* 最終アクセス時刻 */
	struct timespec st_mtim;  /* 最終修正時刻 */
	struct timespec st_ctim;  /* 最終状態変更時刻 */
};
#define st_atime st_atim.tv_sec
#define st_mtime st_mtim.tv_sec
#define st_ctime st_ctim.tv_sec

 
この構造体のメンバにファイルに関する各種の情報が格納されています.
特に st_mode には,それがファイルなのかディレクトリなのか,
あるいはシンボリックリンクなのかという情報が格納されており,
実体の種別を識別するのに使うことができます.
 
ファイル/ディレクトリ/シンボリックリンクの判別
 st_mode から種別を判定する下記のような関数があります.
S_ISREG : 通常のファイルであることを判定
S_ISDIR : ディレクトリであることを判定
S_ISLNK : シンボリックリンクであることを判定
 
サンプルプログラム : 指定したパスの情報を表示するプログラム

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include	<stdio.h>
#include	<unistd.h>
#include	<time.h>
#include	<sys/types.h>
#include	<sys/stat.h>
 
struct	stat	buf;
struct	tm	*ts;
 
int main(ac,av)
int	ac;
char	**av;
{
	int	r, size, mode;
	char	*path, tf[128];
 
	if ( ac < 2 ) {
		fprintf(stderr,"No arguments.\n");
		return(-1);
	}
 
	path = av[1];	// パス名を取得
	fprintf(stderr,"path: %s\n",path);
 
//	r = stat(path,&buf);	// パスの属性を取得
	r = lstat(path,&buf);	// パスの属性を取得
	if ( r != 0 ) {		// エラー処理
		fprintf(stderr,"error: stat = %d\n",r);
		return(-1);
	}
 
//	ts = localtime(&(buf.st_atime));	// 最終アクセス時刻を取得
	ts = gmtime(&(buf.st_atime));		// 最終アクセス時刻を取得
//	strftime(tf,sizeof(tf),"%Y/%m/%d(%a) %H:%M:%S(%z)",ts);
	strftime(tf,sizeof(tf),"%Y/%m/%d(%a) %H:%M:%S",ts);
	printf("Last access(st_atime)       = %s\n",tf);	// 表示
 
//	ts = localtime(&(buf.st_mtime));	// 最終修正時刻を取得
	ts = gmtime(&(buf.st_mtime));		// 最終修正時刻を取得
//	strftime(tf,sizeof(tf),"%Y/%m/%d(%a) %H:%M:%S(%z)",ts);
	strftime(tf,sizeof(tf),"%Y/%m/%d(%a) %H:%M:%S",ts);
	printf("Last modified(st_mtime)     = %s\n",tf);	// 表示
 
//	ts = localtime(&(buf.st_ctime));	// 最終状態変更時刻を取得
	ts = gmtime(&(buf.st_ctime));		// 最終状態変更時刻を取得
//	strftime(tf,sizeof(tf),"%Y/%m/%d(%a) %H:%M:%S(%z)",ts);
	strftime(tf,sizeof(tf),"%Y/%m/%d(%a) %H:%M:%S",ts);
	printf("Last state change(st_ctime) = %s\n",tf);	// 表示
 
	size = (int)(buf.st_size);	// サイズを取得
	printf("size: %d (bytes)\n",size);	// 表示
 
	mode = (int)(buf.st_mode);	// アクセス属性の取得
	printf("mode: %o\n",mode);	// 表示
 
	// ファイル/ディレクトリ/シンボリックリンクの判定
	printf("type: /");
	if ( S_ISREG(buf.st_mode) ) {
		printf("regular file/");
	}
	if ( S_ISDIR(buf.st_mode) ) {
		printf("directory/");
	}
	if ( S_ISLNK(buf.st_mode) ) {
		printf("simlink/");
	}
	printf("\n");
}

このプログラムを s_fstat という名前で作成して実行した例を次に示します.
 
実行例1 ディクレイトリ “.” の属性を調べる例

$ s_fstat .
path: .
Last access(st_atime)       = 2015/03/27(Fri) 10:28:37
Last modified(st_mtime)     = 2015/03/16(Mon) 11:08:31
Last state change(st_ctime) = 2015/03/16(Mon) 11:08:31
size: 442 (bytes)
mode: 40755
type: /directory/
$

 
実行例2 ソースファイル “s_fstat.c” の属性を調べる例

$ s_fstat s_fstat.c
path: s_fstat.c
Last access(st_atime)       = 2015/03/23(Mon) 10:15:09
Last modified(st_mtime)     = 2015/03/15(Sun) 07:55:09
Last state change(st_ctime) = 2015/03/15(Sun) 07:55:09
size: 1488 (bytes)
mode: 100640
type: /regular file/
$

 
実行例3 シンボリックリンク “sl” の属性を調べる例

$ s_fstat sl
path: sl
Last access(st_atime)       = 2015/03/15(Sun) 07:22:56
Last modified(st_mtime)     = 2015/03/15(Sun) 07:22:56
Last state change(st_ctime) = 2015/03/15(Sun) 07:22:56
size: 9 (bytes)
mode: 120755
type: /simlink/
$

時刻の扱い(1)

 UNIX系システムの時刻情報の考え方はとても単純です.
それはどのようなものかというと,
 
「”西暦1970年1月1日0時0分0秒”を基準として,その後の秒数で時刻を表現する」
 
というものです.そして各種の関数を呼び出すことで,
秒数で表現された時刻情報から,
年,月,日,曜日,時,分,秒などの情報を取得することになります.
 
また,日付や時,分,秒の値を保持するための各種の構造体も
提供されています.
 
■ システムの現在時刻の取得(秒単位)
 OSの現在時刻(秒単位)を取得するには time 関数を使います.
 
例.

time_t    t;
t = time(NULL);

上の例のようにすると,t の中に現在時刻が秒数として得られます.
 
日付や時分秒の情報を格納する構造体として tm があり,
localtime 関数や gmtime 関数を使用することで
time_t 型のデータから tm の各メンバに情報を与えることができます.
 
例.

time_t    t;
struct tm *jst;
t = time(NULL);
jst = localtime(&t);

上の例のようにすることで,t の値から日付や時分秒の数値を算出して
それを jst の各メンバに格納します.
localtime 関数はOSのタイムゾーンに合った形で日付と時刻を取得します.
また類似の関数に gmtime というものがあり,これを用いると
グリニッジ標準時の形式で日付と時刻を取得することができます.
 
ちなみに,構造体 tm の中身(定義)は下記のようなものです.

struct tm {
	int tm_sec;        /* 秒 (0-60) */
	int tm_min;        /* 分 (0-59) */
	int tm_hour;       /* 時間 (0-23) */
	int tm_mday;       /* 月内の日付 (1-31) */
	int tm_mon;        /* 月 (0-11) */
	int tm_year;       /* 年 - 1900 */
	int tm_wday;       /* 曜日 (0-6, 日曜 = 0) */
	int tm_yday;       /* 年内通算日 (0-365, 1 月 1 日 = 0) */
	int tm_isdst;      /* 夏時間 */
};

この後,jst->tm_year を参照することで,西暦年(下2桁)の数値を得ることができます.
 
便利な関数として strftime というものがあり,これを使用することで,
日付や時刻を表現する文字列を得ることができます.
例.現在の日付と時刻を1秒感覚で表示するプログラム

#include	<stdio.h>
#include	<time.h>
 
int main()
{
	time_t	t;
	struct	tm	*gmt, *jst;
	int	s1, s2;
	char	fgmt[128], fjst[128];
 
	s2 = 0;
	while ( -1 ) {
//		t = time(NULL);
		time(&t);
		gmt = gmtime( &t );
		jst = localtime( &t );
		s1 = gmt->tm_sec;
		if ( s1 != s2 ) {
			strftime(fgmt,sizeof(fgmt),"%Y/%m/%d(%a) %H:%M:%S",gmt);
			strftime(fjst,sizeof(fjst),"%Y/%m/%d(%a) %H:%M:%S(%a)",jst);
			printf("%s [%s]\n",fgmt,fjst);
			s2 = s1;
		}
	}
}

実行結果の例.

$ s_time
2015/03/16(Mon) 10:56:34 [2015/03/16(Mon) 19:56:34(Mon)]
2015/03/16(Mon) 10:56:35 [2015/03/16(Mon) 19:56:35(Mon)]
2015/03/16(Mon) 10:56:36 [2015/03/16(Mon) 19:56:36(Mon)]
2015/03/16(Mon) 10:56:37 [2015/03/16(Mon) 19:56:37(Mon)]
2015/03/16(Mon) 10:56:38 [2015/03/16(Mon) 19:56:38(Mon)]
2015/03/16(Mon) 10:56:39 [2015/03/16(Mon) 19:56:39(Mon)]
^C
$

 
■ システムの現在時刻の取得(ミリ秒単位)
 OSの現在時刻(ミリ秒単位)を取得するには ftime 関数を使います.
この関数を使用すると,秒とミリ秒の情報が構造体 timeb のメンバに格納されます.
 
例.10分の1秒毎に時刻の秒数を表示するプログラム

#include	<stdio.h>
#include	<sys/timeb.h>
 
struct	timeb	tb;
 
int main()
{
	int	sec,sec2, msec,msec2;
 
	ftime( &tb );
	sec2 = tb.time;
	msec2 = tb.millitm / 100;
	while ( -1 ) {
		ftime( &tb );
		sec = tb.time;
		msec = tb.millitm / 100;
		if ( msec != msec2 ) {
			printf("%d.%d\n",sec,msec);
			sec2 = sec;
			msec2 = msec;
		}
	}
}

 
localtime の逆関数
 tm 構造体の内容から,その時刻に対応する time_t の値を求めるには mktime 関数を使います.
 
例1.localtime で変換した tm 構造体の内容を time_t に逆変換する

#include	<stdio.h>
#include	<time.h>
 
int main()
{
	time_t	t;
	struct	tm	*jst;
	char	fjst[128];
 
//	t = time(NULL);
	time(&t);
	printf("Now, time_t is %ld\n",t);
 
	jst = localtime( &t );
	strftime(fjst,sizeof(fjst),"%Y/%m/%d(%a) %H:%M:%S(%a)",jst);
	printf("%s\n",fjst);
 
	t = mktime( jst );
	printf("mktime is      %ld\n",t);
}

実行例

$ s_mktime
Now, time_t is 1427529755
2015/03/28(Sat) 17:02:35(Sat)
mktime is      1427529755

 
例2.コマンドラインから入力した日付と時刻から time_t を求める

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include	<stdio.h>
#include	<time.h>
 
int main(ac,av)
int	ac;
char	**av;
{
	int	year, month, day, hour, min, sec;
	time_t	t;
	struct	tm	jst, *jst2;
	char	fjst[128];
 
	sscanf(av[1],"%d",&year);
	sscanf(av[2],"%d",&month);
	sscanf(av[3],"%d",&day);
	sscanf(av[4],"%d",&hour);
	sscanf(av[5],"%d",&min);
	sscanf(av[6],"%d",&sec);
	year  -= 1900;
	month -= 1;
 
	jst.tm_year   = year;
	jst.tm_mon    = month;
	jst.tm_mday   = day;
	jst.tm_hour   = hour;
	jst.tm_min    = min;
	jst.tm_sec    = sec;
	jst.tm_isdst  = -1;
 
	t = mktime(&jst);
	printf("%04d/%02d/%02d %02d:%02d:%02d\n",
			year+1900,month+1,day,hour,min,sec);
	printf("time_t is %ld\n",t);
 
	jst2 = localtime( &t );
	strftime(fjst,sizeof(fjst),"%Y/%m/%d(%a) %H:%M:%S",jst2);
	printf("%s\n",fjst);
 
	t = mktime( jst2 );
	printf("mktime is %ld\n",t);
}

実行結果の例

$ s_mktime2 2015 3 29 13 16 00
2015/03/29 13:16:00
time_t is 1427602560
2015/03/29(Sun) 13:16:00
mktime is 1427602560

ファイル入出力 (1)

ファイルからデータを読み込んだり,ファイルに対してデータを書き出したりする方法です.
今回は1バイトづつ入出力する方法です.
 
基本的なこととして理解しておくことがあります.
それは,「ファイルに格納されているデータは1バイトづつのデータが直線的に並んでいる」
ということです.

つまりファイルからデータを読み込む際,ファイルの先頭から末尾にかけて
1バイトづつデータを取り出すという作業になります.

同様に,ファイルに対してデータを出力する際,ファイルの先頭から末尾にかけて
1バイトづつデータを書き込むことになります.

ストリームという概念
 順番にデータを入出力する対象をストリームと呼びます.
 順番にデータがもたらされる入力を「入力ストリーム」,順番にデータを書き込む形の出力を
「出力ストリーム」と呼ぶことがあります.

【ファイルから入力する例】
 ファイルから1バイトづつデータを読み込んで,それを次々と標準出力(コマンド画面)に表示するプログラムの例です.
 まず次のような内容のテキストファイル “InputFile” があると仮定します.

This is a sample text data.

このファイルから1バイトづつデータを読み込んで,それを標準出力に表示するプログラム “FileTest01.c” を次に示します.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include	<stdio.h>
 
#define		TRUE		-1
#define		FALSE		0
 
int main()
{
	FILE	*fi;
	int	c;
 
	fi = fopen( "InputFile", "r" );
	if ( fi == NULL ) {
		printf("InputFile can not be opened!\n");
		return(FALSE);
	}
 
	printf("Start---\n");
	while ( TRUE ) {
		c = getc(fi);
		if ( feof(fi) ) {
			break;
		}
		putchar(c);
	}
	printf("End---\n");
 
	fclose(fi);
	return(TRUE);
}

 
【ファイルにデータを書き込む例】
 ファイルにデータを書き込む方法について紹介します.
1バイトづつデータを出力する例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include	<stdio.h>
 
#define		TRUE		-1
#define		FALSE		0
 
int main()
{
	FILE	*fo;
	int	c;
 
	fo = fopen( "OutputFile", "w" );
	if ( fo == NULL ) {
		printf("OutputFile can not be created!\n");
		return(FALSE);
	}
 
	printf("Start---\n");
	for ( c = 97; c < 123; c++ ) {
		putc(c,fo);
	}
	printf("End---\n");
 
	fclose(fo);
	return(TRUE);
}

 この例では,アルファベット小文字の ‘a’〜’z’ をファイル “OutputFile” に書き込んでいます.
 
コマンド画面に出力するようなスタイルで出力する例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include	<stdio.h>
 
#define		TRUE		-1
#define		FALSE		0
 
int main()
{
	FILE	*fo;
	int	c;
 
	fo = fopen( "OutputFile", "w" );
	if ( fo == NULL ) {
		printf("OutputFile can not be created!\n");
		return(FALSE);
	}
 
	printf("Start---\n");
	fprintf(fo,"This file is created by the program \'FileTest03.c\'.\n");
	fprintf(fo,"This is one easy way of output.\n");
	printf("End---\n");
 
	fclose(fo);
	return(TRUE);
}

このプログラムを実行すると “OutputFile” というファイルが作成され,内容は

This file is created by the program 'FileTest03.c'.
This is one easy way of output.

となります.