実践Linux                 TOPへ  Cプログラミング目次へ

ファイル操作  2010年3月更新

●Makefile
プログラムソースをtest.cで保存して、Makefileを以下の内容で準備し、makeを実行する。
字下げはTabキーで行うこと。

# Makefile for test

CC = gcc
TARGETS = test.cgi
OBJ = ${SRC:.c=.o}
SRC = test.c

$(TARGETS):${OBJ}
  ${CC} ${OBJ} -o ${TARGETS}

${OBJ}:${SRC}
  ${CC} ${SRC} -c -o ${OBJ}

clean:
  rm -f *.o $(TARGETS)


●プラグラム概要
public_htmlディレクトリ内のすべてのhtmlファイルをindex.txtファイルを使って統一的に書き換えます。
htmlファイルのある部分を同じ内容で統一記述している場合(例えばインデックス部分等)、その部分を一挙に書き換えるのに便利。
public_htmlディレクトリ内のhtmlファイルに"<!-- ここから -->"、"<!-- ここまで -->を書き込んでおけば、その区間をindex.txtファイルの内容ですべて一挙に書き換えます。
注意 index.txtの最後は改行してpublic_htmlディレクトリに保存しておいてください。
(もちろんphpが使用できる環境であればinclude機能を使ったほうが便利ですが、そうでない場合利用してみてください。)

【htmlファイル例】
<HTML>
<HEAD>
<TITLE>*********</TITLE>
</HEAD>

<BODY>
<!-- ここから -->
 …………………………
 …………………………
 …………………………
<!-- ここまで -->
</BODY>
</HTML>

【index.txtファイル例】
 aaaaaaaa
 bbbbb
 cccccccccccc
 dddddddd  ←この最後を必ず改行しておく。


【書き換え例】
<!-- ここから -->
 aaaaaaaa
 bbbbb
 cccccccccccc
 dddddddd
<!-- ここまで -->  上で改行してないと「 dddddddd <!-- ここまで --> 」のようになってしまう。



●プログラム(単純なもの)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>

#define BUFSIZE 4096

char File_dir[]="../public_html/";
char Index_file[]="index.txt";
char Tmp_file[]="tmp.html";
char Start_str[]="<!-- ここから -->";
char End_str[]="<!-- ここまで -->";


void kakikae(char *htmlf)
{
FILE *fp,*ft,*ftmp;
char buf[BUFSIZE + 1];
char buf2[BUFSIZE + 1];
char fname1[128];
char fname2[128];
int flag=0;

/* tmp.htmlファイルの作成 */
sprintf(fname1,"%s%s",File_dir,Tmp_file);
if ((ftmp = fopen(fname1, "w")) == NULL)
{
printf("could not open %s!\n",Tmp_file);
exit(1);
}

/* index.txtファイルのオープン */
//strcpy(buf,File_dir);
//strcat(buf,Index_file);
sprintf(fname1,"%s%s",File_dir,Index_file);
if ((ft = fopen(fname1, "r")) == NULL)
{
fprintf(stderr,"could not open %s!\n",Index_file);
exit(1);
}

/* htmlファイルの書き換え処理 */
sprintf(fname1,"%s%s",File_dir,htmlf);
if ((fp = fopen(fname1, "r")) == NULL)
{
fprintf(stderr,"could not open %s-file!\n",htmlf);
exit(1);
}
while (fgets(buf, BUFSIZE, fp) != NULL)
{
if(strstr(buf,Start_str) != NULL && flag == 0)
{
flag=1;
fputs(buf,ftmp);
/* index.txtファイルの読み込み */
while (fgets(buf2, BUFSIZE, ft) != NULL)
{
fputs(buf2,ftmp);
}
}
else if(strstr(buf,End_str) != NULL && flag == 1)
{
flag=0;
fputs(buf,ftmp);
}
else if(flag == 0)
{
fputs(buf,ftmp);
}
}
if(fclose(fp))
{
fprintf(stderr,"could not close %s-file!\n",htmlf);
}

/* index.txtファイルのクローズ */
if(fclose(ft))
{
fprintf(stderr,"could not close %s!\n",Index_file);
}

/* tmp.htmlファイルのクローズ */
if(fclose(ftmp))
{
fprintf(stderr,"could not close %s!\n",Tmp_file);
}

/* html元ファイルの削除 */
sprintf(fname1,"%s%s",File_dir,htmlf);
if(remove(fname1))
{
fprintf(stderr,"could not remove %s!\n",htmlf);
}

/* tmp.htmlファイルの名称変更 */
sprintf(fname1,"%s%s",File_dir,Tmp_file);
sprintf(fname2,"%s%s",File_dir,htmlf);
if(rename(fname1,fname2))
{
fprintf(stderr,"could not rename %s!\n",Tmp_file);
}
}

/////////////////////////////////////////////////////////////////////////////
/* public_htmlディレクトリ内のすべてのhtmlファイルを探し出し、kakikaeサブルーチンを呼び出す */

int main()
{
DIR *dir;
struct dirent *dp;
char buf[BUFSIZE + 1];

if((dir=opendir(File_dir)) == NULL)
{
fprintf(stderr,"can not open %s\n",File_dir);
exit(1);
}
while((dp=readdir(dir)) != NULL)
{
if(strstr(dp->d_name,".htm") != 0)
{
kakikae(dp->d_name);
sprintf(buf,"chown ユーザー:グループ %s%s",File_dir,dp->d_name);  所有者の変更。ユーザー:グルーフには適切な名前を代入しておいてください。下の例では自動化しました。
system(buf);
}
}

closedir(dir);

/* 終了 */
fprintf(stderr,"program end\n");
return 0;
}


●ディレクトリ以下を再帰的に書き換える(発展させたもの)

使用例 # ./test -R ../public_html ../public_html/chocolat

../public_htmlディレクトリ以下のすべてのhtmlファイルを再帰的に../public_html/menu1.txt、menu2.txtファイルを使って統一的に書き換え、さらに../public_html/chocolatのhtmlファイルを../public_html/chocolat/menu1.txt、menu2.txtファイルを使って書き換える(非再帰的に)。
htmlファイルには<!-- ここから1 -->、<!-- ここまで1 -->、<!-- ここから2 -->、<!-- ここまで2 -->を書き込んでおく。そのあいだの区間をmenu1.txt、menu2.txtファイルの内容で書き換えることになる。
注意 menu1.txt、menu2.txtの最後は改行して保存しておくこと。(上と同じ)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

#define BUFSIZE 4096

char File_dir[FILENAME_MAX];
char Menu1[]="menu1.txt";
char Menu2[]="menu2.txt";
char Tmp_file[]="tmp.txt";
char Start_str1[]="<!-- ここから1 -->";
char End_str1[]="<!-- ここまで1 -->";
char Start_str2[]="<!-- ここから2 -->";
char End_str2[]="<!-- ここまで2 -->";

void kakikae(char *htmlf, char *dir, char *txtfile, char *start_str, char *end_str)
{
FILE *fp,*ft,*ftmp;
char buf[BUFSIZE + 1];
char buf2[BUFSIZE + 1];
char fname1[FILENAME_MAX];
char fname2[FILENAME_MAX];
int flag=0;

/* tmpファイルの作成 */
sprintf(fname1,"%s/%s",dir,Tmp_file);
//printf("%s\n", fname1);
if ((ftmp = fopen(fname1, "w")) == NULL)
{
printf("could not open 1:%s/%s!\n",dir,Tmp_file);
exit(1);
}

/* txtファイルのオープン */
sprintf(fname1,"%s/%s",File_dir,txtfile);
//printf("%s\n", fname1);
if ((ft = fopen(fname1, "r")) == NULL)
{
fprintf(stderr,"could not open 2:%s/%s!\n",File_dir,txtfile);
exit(1);
}

/* htmlファイルの書き換え処理 */
sprintf(fname1,"%s/%s",dir,htmlf);
//printf("%s\n", fname1);
if ((fp = fopen(fname1, "r")) == NULL)
{
fprintf(stderr,"could not open 3:%s/%s.!\n",dir,htmlf);
exit(1);
}
while (fgets(buf, BUFSIZE, fp) != NULL)
{
if(strstr(buf,start_str) != NULL && flag == 0)
{
flag=1;
fputs(buf,ftmp);
/* txtファイルの読み込み */
while (fgets(buf2, BUFSIZE, ft) != NULL)
{
fputs(buf2,ftmp);
}
}
else if(strstr(buf,end_str) != NULL && flag == 1)
{
flag=0;
fputs(buf,ftmp);
}
else if(flag == 0)
{
fputs(buf,ftmp);
}
}
if(fclose(fp))
{
fprintf(stderr,"could not close %s-file!\n",htmlf);
}

/* txtファイルのクローズ */
if(fclose(ft))
{
fprintf(stderr,"could not close %s!\n",txtfile);
}

/* tmp.htmlファイルのクローズ */
if(fclose(ftmp))
{
fprintf(stderr,"could not close %s!\n",Tmp_file);
}

/* html元ファイルの削除 */
sprintf(fname1,"%s/%s",dir,htmlf);
if(remove(fname1))
{
fprintf(stderr,"could not remove %s!\n",htmlf);
}

/* tmp.htmlファイルの名称変更 */
sprintf(fname1,"%s/%s",dir,Tmp_file);
sprintf(fname2,"%s/%s",dir,htmlf);
if(rename(fname1,fname2))
{
fprintf(stderr,"could not rename %s!\n",Tmp_file);
}
}

void dirlist(char *dir)
{
struct dirent *entry;
struct stat statbuf;
int len;
char buf[BUFSIZE + 1];
char dirbuf[FILENAME_MAX];

DIR *dp = opendir(dir);
if (dp == NULL) perror("opendir"), exit(1);

len = strlen(dir);

while ((entry = readdir(dp)) != NULL)
if (strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..")) {
sprintf(dir + len, "/%s", entry->d_name); //ディレクトリ名のあとにentry->d_nameをつなげる
stat(dir, &statbuf);
if (S_ISDIR(statbuf.st_mode)){ //ディレクトリかどうか
//printf("\ndir: %s\n", dir);
dirlist(dir); //再帰的に自分を呼び出す
} else {
if (strlen(entry->d_name) > 4 && strstr(entry->d_name, ".htm") != 0)
{
dirbuf[strlen(dir)-strlen(entry->d_name)-1] = '\0'; //切りとりたい長さの次にNULLを入れておかないと前の文字が残る
strncpy(dirbuf, dir, strlen(dir)-strlen(entry->d_name)-1); //strncpy(dest, source+n, m); n文字目からm文字を切り取りdestにコピー。ただし'\0'の自動付加は行わないので注意。mが大きすぎた場合は残りは'\0'で埋めてコピー。
printf("-----------------\n");
printf("%s\n", dir);
kakikae(entry->d_name, dirbuf, Menu1, Start_str1, End_str1);
kakikae(entry->d_name, dirbuf, Menu2, Start_str2, End_str2);
sprintf(buf,"chown %d:%d %s", statbuf.st_uid, statbuf.st_gid, dir);
system(buf);
}
}
}
closedir(dp);
}

void filelist()
{
DIR *dp;
struct dirent *entry;
char buf[BUFSIZE + 1];
struct stat statbuf;

if((dp=opendir(File_dir)) == NULL)
{
fprintf(stderr,"can not open %s\n",File_dir);
exit(1);
}
while((entry=readdir(dp)) != NULL)
{
if(strstr(entry->d_name,".htm") != 0)
{
sprintf(buf,"%s/%s",File_dir,entry->d_name);
stat(buf, &statbuf);
printf("-----------------\n");
printf("%s\n", buf);
kakikae(entry->d_name, File_dir, Menu1, Start_str1, End_str1);
kakikae(entry->d_name, File_dir, Menu2, Start_str2, End_str2);
sprintf(buf,"chown %d:%d %s/%s", statbuf.st_uid, statbuf.st_gid, File_dir, entry->d_name);
system(buf);
}
}

closedir(dp);
}

int main(int argc, char *argv[])
{
int c;
char dir[FILENAME_MAX];

while((c = getopt(argc, argv, "R:")) != -1){
switch(c)
{
case 'R':
strcpy(File_dir, argc < 2 ? "." : optarg);

strcpy(dir, File_dir); //File_dirが書き換えられないようにコピーして使う
dirlist(dir);
break;
case '?':
fprintf(stderr,"usage: %s -R\n", argv[0]);
}
while(optind < argc){
strcpy(File_dir, argc < 2 ? "." : argv[optind++]);

filelist();
}
}

/* 終了 */
fprintf(stderr,"program end\n");
return 0;
}






TOPへ  Cプログラミング目次へ