내장형 하드웨어/C언어

저수준 입출력, HEXAVIEW

동화다아아 2011. 6. 28. 15:43

- 시스템 레벨 입출력(저수준)

 → 시스템 레벨 입출력 또는 저수준 입출력은 운영체제가 디스크에 데이터를 읽거나 쓰기 위해서 접근하는 방법과 유사한 방법으로 데이터 입출력을 실행하며, 표준 입출력 함수들을 작성하기 위해서 사용되기도 한다.

 → 표준 입출력에서는 버퍼가 시스템에 의해서 마련되어 프로그래머에게 보이지 않지만, 저수준 입출력에서는 프로그램 내에서 버퍼를 명시해 주어야 한다. 디스크로의 데이터 입출력은 이 버퍼 단위로 이루어진다.

 → 저수준 입출력은 표준 입출력 함수에 비해 프로그램 코드가 짧으며 실행속도가 빠르다. 저수준 입출력에서 파일의 열기와 닫기에 사용되는 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;
}