2022. 4. 28. 22:54ㆍ컴퓨터 공학/운영체제
본 티스토리 블로그는 PC 환경에 최적화되어 있습니다.
모바일 유저분들은 아래 네이버 블로그를 이용해 주세요.
운영체제 기능 중 하나인 reverse 명령어를 구현해 보도록 하겠습니다.
명령어의 기능은 입력된 파일을 열어서 역순으로 출력해 주는 것입니다.
단, 개행문자 기준으로 역순 출력해야 하며, 모든 내응을 반전시켜서는 안됩니다.
input file
|
output file
|
asdf0
asdf1 asdf2 asdf3 |
asdf3
asdf2 asdf1 asdf0 |
이 기능을 구현하는 방식은 제가 생각하기론 스택, 파일 포인터, 전체 동적할당을 진행하는 방법이 존재하는 것 같습니다.
대부분 원리는 같으나 부연 설명을 진행하자면 아래와 같습니다.
1) 스택
파일을 읽다가 '\n'을 확인하면 해당 위치를 스택에 집어넣습니다.
이 과정을 반복하다가 EOF를 만나면 스택에서 하나씩 주소 정보를 pop 하고, 문자열을 출력해 주면 역순으로 한 줄씩 출력이 가능합니다.
다만, 문자열 출력과 포인터를 관리하기 위한 별도의 코드를 작성해야 하며, C언어는 직접 자료구조를 만들어야 하기 때문에 조금 귀찮을 수 있습니다.
2) 파일 포인터 이용
파일을 역순으로 읽어 드리고 '\n'을 확인하면 getline 함수를 호출하여 한 줄 출력하고, 파일 포인터를 개행문자 이전으로 옮기는 방식입니다.
포인터와 인덱스 관리도 쉽고, 메모리 사용량도 상당히 적지만 파일 포인터를 움직여야 하는 경우가 많기 때문에 경우에 따라서는 상당히 느려질 수 있습니다.
아래는 해당 아이디어 기반으로 작성된 코드입니다.
물론, ostep 테스트를 통과했다는 것이지 일반 파일에도 정상 동작하지 않을 수 있습니다.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void reversContents(FILE* input, FILE* output);
int main(int argc, char* argv[]){
FILE *fp, *fp2;
char c,d;
if (argc > 3){ //인자 개수가 3을 초과한 경우
fprintf(stderr,"usage: reverse <input> <output>\n");
exit(1);
}
else if(argc == 1){
fp = stdin;
fp2 = stdout;
}
else{
fp = fopen(argv[1],"r");
if(fp == NULL){
fprintf(stderr, "reverse: cannot open file '%s'\n",argv[1]);
exit(1);
}
fp2 = fopen(argv[2],"w");
if(fp2 == NULL){
fprintf(stderr, "reverse: cannot open file '%s'\n",argv[2]);
exit(1);
}
while(1){
if (feof(fp) == 0 && feof(fp2) == 0){
c = fgetc(fp);
d = fgetc(fp2);
if (c != d) // 읽어드린 정보가 하나라도 다르면 다른 파일이다.
break;
}
else{
fprintf(stderr, "reverse: input and output file must differ\n");
exit(1);
}
}
}
reversContents(fp, fp2);
return 0;
}
void reversContents(FILE* input, FILE* output){
int head, tail;
char *buffer;
size_t size=0;
char c;
FILE *fp = input;
FILE *fp2 = output;
fseek(fp,0,SEEK_END);
while(ftell(fp)>0){
head = ftell(fp);
c =fgetc(fp);
if(c == '\n'){
getline(&buffer, &size, fp);
fprintf(fp2, "%s", buffer);
tail = ftell(fp);
fseek(fp, (tail - head)*(-1), SEEK_CUR);
}
fseek(fp, -2, SEEK_CUR);
}
fseek(fp, 0, SEEK_SET);
getline(&buffer, &size, fp);
fprintf(fp2, "%s", buffer);
free(buffer);
}
3) 파일 전체를 동적할당하기
가장 쉬운 방법이며, 파일 전체를 힙 영역에 받아와서 읽고 strtok를 통해서 '\n'을 분리, 역순으로 배열을 순회하면 풀립니다.
이 방식은 경우에 따라서 작동이 불가능할 수 있습니다.
예를 들어 파일 크기가 20GB 정도 되는 걸 힙 영역에 넣는 건 무리겠죠?
아래는 해당 아이디어 기반으로 작성된 코드입니다.
실제 파일 크기가 커지거나 할 경우 코드가 정상 동작하지 않을 가능성이 매우 높으므로 주의 바랍니다!!!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char* argv[]){
FILE *FD, *FD2;
int sizeFile;
char* tmp;
char checker_FD,checker_FD2;
if (argc > 3){ //인자 개수가 3을 초과한 경우
fprintf(stderr,"usage: reverse <input> <output>\n");
exit(1);
}
if(argc == 1 ){
FD = stdin;
FD2 = stdout;
}
else{
FD = fopen(argv[1],"r");
if(FD == NULL){
fprintf(stderr, "reverse: cannot open file '%s'\n",argv[1]);
exit(1);
}
FD2 = fopen(argv[2],"w");
if(FD2 == NULL){
fprintf(stderr, "reverse: cannot open file '%s'\n",argv[2]);
exit(1);
}
if(!strcmp(argv[1], argv[2])){ // 입력된 경로가 일치하면, 동일 파일로 간주함.
fprintf(stderr,"reverse: input and output file must differ\n");
exit(1);
}
while(1){
if (feof(FD) == 0 && feof(FD2) == 0){
checker_FD = fgetc(FD);
checker_FD2 = fgetc(FD2);
if (checker_FD != checker_FD2) // 읽어드린 정보가 하나라도 다르면 다른 파일이다.
break;
}
else{
fprintf(stderr, "reverse: input and output file must differ\n");
exit(1);
}
}
}
fseek(FD,0,SEEK_END); // 파일의 맨 끝으로 이동
sizeFile = ftell(FD); // 파일 포인터의 현재 위치를 얻는다.
char buffer[sizeFile+1]; // 확인된 파일 사이즈+1 만큼 버퍼를 할당. c언어 표준이 일부 바뀌면서 사이즈 고정이 아니여도 사용가능.
char *result[sizeFile+1]; // 반환 역순 데이터를 저장.
fseek(FD, 0, SEEK_SET);
fread(buffer, sizeFile , 1 , FD); // 실제 파일 데이터를 읽음
tmp = strtok(buffer, "\n");
int i;
for(i=0;; i++){
if(tmp == NULL) // 자를 문자열이 없을때까지 반복함
break;
result[i] = tmp;
tmp = strtok(NULL, "\n"); // 다음 문자열을 잘라서 포인터를 반환
}
for(int j=i-1; j>-1; j--){
if(result[j] != NULL)
fprintf(FD2,"%s\n",result[j]);
}
fclose(FD);
fclose(FD2);
return 0;
}
아래는 테스트 성공 화면입니다.
'컴퓨터 공학 > 운영체제' 카테고리의 다른 글
ostep initial-xv6 - Syscall 추가하기 (2) | 2022.05.13 |
---|---|
ostep project - process shell(쉘 구현) (0) | 2022.04.30 |
ostep-utility : wcat 명령어 구현 (0) | 2022.03.11 |
1. Operation System OT (0) | 2020.02.12 |