ASCII파일의 삭제 및 수정에 관해서....
C 프로그램을 하다보면,
설정 파일 등과 같이 ASCII형태의 파일들에 어떤 문자열을 삽입하고, 삭제, 수정등을 해야 하는 경우가 있습니다.
binary 형식의 파일 이라면, 삽입할 때 record형식으로 삽입하고, 수정 이나 삭제 시에도, 해당 레코드에 접근해서 삭제나 접근을 하면됩니다.
하지만 위와 같은 파일의 경우에는 record형식의 접근이 어렵습니다.
이럴 때 파일의 어느 부분을 삭제하고 수정할 때 어떻게 하시는지요?
제 경우에는 삽입할 때는 추가 모드로 연후에 파일의 제일 마지막에 추가 시킵니다.
삭제 할 때는 원본 파일과 임시 파일 두개를 열어서
원본 파일에서 fgets로 한줄씩 받아서 제가 원하는 문자열과 비교해 나가면서 같은 문자열이 아닌경우에는 임시파일에 저장합니다. 그러다가 같은 문자열을(삭제할 문자열) 만난 경우 임시 파일에 저장하지 않고, 다음 문자열을 받습니다.
파일의 끝까지 받은 후에는 원본 파일을 삭제하고, 임시파일을 원본 파일로 교체합니다.
수정할 때는 삭제할 때와 비슷하고, 같은 문자열을 만난 경우에만 임시 파일에 바꿀 문자열을 삽입합니다.
이 방법 말고 다른 방법이 있나요?
lex , yacc 등을 이용하면, 파싱등이 쉽게 이루어진다고 하던데...
아직 컴파일러와 파일처리에 대해서 공부를 못해서 방법 등이 생각 나지 않는군요.
아래는 아파치 서버의 가상 호스트 부분만을 프로그램에서 삽입하고, 삭제하는 함수 입니다.
이곳에서는 삽입할 때 "#+++id+++", "#---id---" 이런식으로 구분해서 집어 넣고 삭제 할 때 이것을 이용해서 삭제를 하는데요. 이 것 보다 편하거나, 효율적으로 프로그램을 할 수 있는 방법이 있을까요?
int append_virtual_host(char *user_name, char *domain, char *ip, char *user_dir) { FILE *fp; fp = fopen("virtual_host.txt", "a"); fprintf(fp, "#+++%s+++ <VirtualHost %s> ServerAdmin %s@%s DocumentRoot /%s/%s/public_html ServerName %s.%s ErrorLog /usr/local/apache/logs/%s.%s-error_log CustomLog /usr/local/apache/logs/%s.%s-access_log common </VirtualHost> #---%s---\n", user_name, ip, user_name, domain, user_dir, user_name, user_name, domain, user_name, domain, user_name, domain, user_name); fclose(fp); return 1; } int delete_virtual_host(char *user_name) { char *buf, *str1, *str2; FILE *fr, *fw; buf = (char *)memset((char *)malloc(1024+1), 0x00, 1024+1); str1 = (char *)memset((char *)malloc(32), 0x00, 32); str2 = (char *)memset((char *)malloc(32), 0x00, 32); fr = fopen(VHOST_FNAME, "r"); fw = fopen(VHOST_TMPNAME, "w"); sprintf(str1, "#+++%s+++\n", user_name); sprintf(str2, "#---%s---\n", user_name); while(fgets(buf,1024,fr)!=NULL) { if(strcmp(str1,buf)==0) { while(fgets(buf,1024,fr)!=NULL) { if(strcmp(str2, buf)==0) break; memset(buf, 0x00, 1024+1); } /* 상위 while문 빠져나감 */ if(buf==NULL) break; } else { fputs(buf, fw); memset(buf, 0x00, 1024+1); } } fclose(fr); fclose(fw); unlink(VHOST_FNAME); rename(VHOST_TMPNAME, VHOST_FNAME); return 1; }
:roll:
존재하는 프로그램을 이용하겠습니다.
C에서 일일히 구현하는건, 일단 시간도 많이 걸리고, 실수하기 쉬울것 같군요.
저라면, awk, sed 같은 유닉스 기본 유틸리티를 system으로 끌어쓰겠습니다.
KeepItSimple~
--
Life is short. damn short...
댓글 달기