저수준 입출력, HEXAVIEW
- 시스템 레벨 입출력(저수준)
→ 시스템 레벨 입출력 또는 저수준 입출력은 운영체제가 디스크에 데이터를 읽거나 쓰기 위해서 접근하는 방법과 유사한 방법으로 데이터 입출력을 실행하며, 표준 입출력 함수들을 작성하기 위해서 사용되기도 한다.
→ 표준 입출력에서는 버퍼가 시스템에 의해서 마련되어 프로그래머에게 보이지 않지만, 저수준 입출력에서는 프로그램 내에서 버퍼를 명시해 주어야 한다. 디스크로의 데이터 입출력은 이 버퍼 단위로 이루어진다.
→ 저수준 입출력은 표준 입출력 함수에 비해 프로그램 코드가 짧으며 실행속도가 빠르다. 저수준 입출력에서 파일의 열기와 닫기에 사용되는 open() 함수와 close() 함수의 원형은 다음과 같다.
int open(char *filename, int oflag, int pmode);
int close(int fd);
⇒ oflag
→ open() 함수의 두 번째 인수인 oflag는 파일의 접근 목적이나 접근방법 등을 명시하는 것으로 <fcntl.h> 파일에 정의되어 있다.
oflag |
값 |
의미 |
O_APPEND |
0x0001 |
쓰기용으로 파일을 열어, 파일의 끝을 현재위치로 설정한다. |
O_CREAT |
0x0002 |
쓰기 용으로 파일을 생성한다. 파일이 이미 존재하면 효과가 없다. |
O_EXCEL |
0x0004 |
O_CREAT와 함께 사용되어 파일이 이미 존재할 경우 오류값을 반환. |
O_RDONLY |
0x0100 |
읽기 전용으로 파일을 연다. |
O_RDWR |
0x0200 |
읽고 쓰기용으로 파일을 연다. |
O_TRUNC |
0x0400 |
파일을 열고 내용을 삭제하여 파일의 길이를 0으로 만든다. |
O_WRONLY |
0x0800 |
쓰기 전용으로 파일을 연다. |
O_BINARY |
0x4000 |
이진 모드로 파일을 연다. |
O_TEXT |
0x8000 |
텍스트 모드로 파일을 연다. |
→ oflag의 값들은 상호 배타적이기 때문에 경우에 따라서는 여러개의 값을 주어야 한다.
→ 이때는 비트 OR 연산자(|)fmf 사용한다. 예로, 읽기 전용의 이진모드로 파일을 열 때는 다음과 같이 표현한다.
O_RDONLY | O_BINARY
→ 단, 읽기 전용과 쓰기 전용을 동시에 표시할 수는 없다.
- 파일 핸들(리눅스에선 파일 디스크립터(descriptor))
⇒ 고수준 입출력시에는 파일을 열면 파일포인터(파일을 읽거나 쓸수 있게 해준다.)를 프로그램에서 연결받아 이후 파일에 대한 연산이 파일 포인터를 통해서 이루어 진다.
⇒ 반면, 저수준 입출력에서는 파일 포인터를 사용하지 않고 핸들(handle)이라고 부르는 파일기술자를 사용하여 파일에 대한 연산이 이루어진다. 이 값은 open() 함수의 반환값으로 양의 정수 갑이다. open() 함수는 오류가 발생할 경우 -1을 반환한다.
장치 |
파일핸들 |
stdin |
0 |
stdout |
1 |
stderr |
2 |
stdaux |
3 |
stdprn |
4 |
⇒ 고수준일 때는 주소 FILE* fp, 저수준일 때는 번호
- read() / write() 함수
⇒ 저수준 파일 입출력에서는 파일에 데이터를 읽고 쓰기 위해서 read() 함수와 write() 함수를 사용하며, 원형은 다음과 같다.
int read (int fd, char *buffer, int size);
int write (int fd, char *buffer, int size);
→ 첫 번째 인자(read라면 읽을 대상, write라면 쓰는 대상.)
→ 두 번째 인자(메모리 주소.)
→ 세 번째 인자(한번에 읽어올 최대 양)
⇒ read() 함수는 파일핸들(linux는 description) fd가 가리키는 파일에서 size 크기 만큼의 바이트를 buffer로 읽어 온다. 실행이 성공하면 읽은 바이트 수를 반환하고, EOF(End Of File)이면 0을, 오류가 발생하면 -1dmf 반환한다.
⇒ write() 함수에서 buffer는 파일에 기록할 데이터를 가지고 있다. 버퍼의 크기는 디스크의 입출력 속도를 향상시키는 데 매우 중요하며 운영체제에 따라 다르다. 보통 512부터 배수인 2048 또는 4096 바이트를 많이 사용한다.
⇒ 버퍼의 크기가 커지면 스택 오버플로우가 일어날 수 있으므로 전역변수로 선언해 주어야만 한다.
- pmode
⇒ 마지막 인수인 pmode는 보통의 경우 생략되며, 새로운 파일은 만들기 위해서 O_CREAT을 사용했을 때 새로운 파일에 대한 접근 허가를 명시할 때 사용한다.
pmode |
의미 |
S_IWRITE |
쓰기 허용 |
S_IREAD |
읽기 허용 |
S_IREAD | S_IWRITE |
읽기와 쓰기 허용 |
⇒ pmode를 사용하기 위해선s #include를 사용하여 <sys/types.h> 파일과 <sys/stat.h> 파일을 포함시켜야 한다. oflag은 파일을 열 때 가지는 속성이므로 프로그램 내에서만 유요하다.
⇒ pmode는 새로운 파일 자체가 가지는 속성이다. 파일을 새로 만들었을 경우에는 시스템에 따라서 파일이 예상대로 작동하지 않는 경우가 있으므로 파일의 속성을 시스템에게 알리기 위해 한번 닫았다 다시 열어서 사용하는 것이 낫다.
⇒ open()함수로 연 파일은 close 함수로 닫아주면 된다. close() 함수의 실행시 파일 기술자(description)만을 인수로 넘겨주면 된다.
⇒ 새로운 파일을 작성할 때는 open() 함수 대신 creat() 함수를 사용할 수 있으며 그 원형은 다음과 같다.
int creat (char *filename, int pmode);
⇒ creat() 함수는 실패시 -1을 반환한다. pmode는 위의 open() 함수의 경우와 같다.
// 입력 데이터 파일의 내용을 새로운 출력파일을 생성하여 복사하는 프로그램(linux)
#include<stdio.h>
#include<string.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#define BUFFERSIZE 512
//#define file "d1009.in"
int main()
{
int infd;
int bytes;
int i;
int outfd;
char buffer[BUFFERSIZE];
//char는 문자열을 저장하려는게 아니라 정확하게 byte를 선언하려고 사용한다.
//const char *file = "d1009.in";
if((infd = open(file, O_RDONLY)) <0)
//if((infd = open("d1009.in", O_RDONLY)) <0)
{
perror("Can't open file d11-9.in");
}
if((outfd = open("d1009.out", O_CREAT|O_WRONLY, S_IWRITE))<0)
// 인자 3개면 세세한 지정이 가능하나 두 개로도 동작한다.
{
printf("Can\t open file d11-9.out");
}
while((bytes = read (infd, buffer, BUFFERSIZE))>0)
{
for(i=0;i<bytes; ++i)
{
putchar(buffer[i]);
}
write(outfd, buffer, bytes);
}
close(infd);
close(outfd);
return 0;
}
⇒ 출력결과
⇒ #include<fcntl.h>
→ o_flag를 사용하기 위해서 <fcntl.h>파일을 #include 시킨다.
⇒ perror("Can't open file d11-9.in");
→ 데이터 파일이 없을 경우 다음과 같이 오류메세지를 출력한다.
Can't open file d1009.in : No such file or directory
⇒ open("d1009.out", O_CREAT | O_WRONLY, SIWRITE)
→ 새로운 파일을 만들기 위해 O_CREAT를 명시하고, 쓰기전용의 이진 모드로 파일을 연다는 의미이다. O_CREAT가 명시되므로 pmode가 S_IWRITE로 명시되었다. open() 함수 대신 다음과 같이 creat() 함수를 사용하여 파일을 생성할 수 있다.
create ("d11-9.out", S_IWRITE);
⇒ #include<sys/types.h>
⇒ #include<sys/stat.h>
→ pmode를 사용하기 위해서 포함 시킨다.
- HEXAVIEW로 파일 읽기
#include<stdio.h>
#include<fcntl.h>
#include "hexaview.h"
#define BUFFERSIZE 256
int main()
{
int bytes;
int readfd;
char buffer[BUFFERSIZE];
readfd = open("test2.c",O_RDONLY);
// test2.c, test2, test2.exe 파일을 각각 읽어 본다.
bytes = read(readfd, buffer, 256);
hexaview(buffer, bytes);
close(readfd);
return 0;
}
⇒ linux로 실행
→ test2라는 파일을 읽어들여 hexaview 형태로 뿌린다.
→ 처음은 test2.c 파일을 읽어들여 출력한 형태
→ 두 번째는 test2 파일(실행파일)을 읽어들여 출력한 형태
⇒ cl로 실행
→ test2.c를 cl로 컴파일하여 생성된 test2.exe 파일을 읽어들여 출력한 화면
#include "MSDFunction.h"
#include <stdlib.h>
#include <fcntl.h>
int main(int iParam, char *cpParam[])
{
int iExeFile;
unsigned char ucBuf[16*16]={0,}; //속도면에서는 초기화 하지 않는 것이 낫다.
if(2 != iParam) //인자가 2개일때만 불러온다.
{
fprintf(stdout, "파일 이름을 쓰세요\n");
return 0;
}
iExeFile = open(cpParam[1], O_RDONLY); //두번째, 세번째 인자파일
if(0 > iExeFile)
{
fprintf(stdout, "[%s]파일을 찾을 수 없습니다\n", cpParam[1]);
return 0;
}
read(iExeFile, ucBuf, 16*16); //256이라고 적어도 되지만
MSDFunction(ucBuf, 16); // ucBUF
close(iExeFile);
return 0;
}
'내장형 하드웨어 > C언어' 카테고리의 다른 글
C언어 - text mode, binary mode, fprintf, freed, 배열과 포인터 (0) | 2011.06.30 |
---|---|
C언어 - 저수준 입출력, 리다이렉션 (0) | 2011.06.30 |
tcp/ip 기초, 저수준 입출력 (0) | 2011.06.28 |
C언어 - 고수준, 저수준 함수, write, read, open, close (0) | 2011.06.24 |
C언어 복습 5(token, strncpy, strtok, 디버깅) (0) | 2011.06.17 |