2009년 3월 2일 월요일

4Day Study

4Day Study
[[[[[파일(File) 작업]]]]]
아이노드(inode) => 파일 시스템의 데이터의 특정 블록이며, 파일의 길이와 파일이 디스크의 어디에 저장되어 있는가를 포함(ls -i)
디렉토리 => 아이노드 숫자와 파일의 이름을 저장하고 있는 파일이다. 각 디렉토리 항목은 파일의 아이노드에 대한 연결이다. 파일 이름을 삭제하면 연결이 삭제된다
사용자 디렉토리 => 틸트(tilde) ~를 가지고 있음
/bin => 시스템 바이너리 디렉토리
/etc => 시스템 구성 파일 디렉토리
/lib => 시스템 라이브러기 디렉토리
/dev => 장치 인터페이스 파일 디렉토리

CD-ROM 마운트
# mount -t iso9660 /dev/hdc /mnt/cdrom
# cd /mnt/cdrom

/dev/console => 시스템 콘솔을 표현
/dev/tty => 프로세스의 제어 터미널(키보드와 화면 혹은 윈도우)에 대한 별칭
/dev/zero => 0을 포함하는 파일을 생성하기 위해 null 바이트의 원본처럼 작동
/dev/null => 이 장치로 쓰여진 모든 출력은 버려짐

빈파일 만들기
cp /dev/null empty_file
touch .empty_file => 기존 파일이 있을 경우 파일의 수정시간 만 바뀜

장치 드라이버 액세스를 위한 저수준 함수인 시스템 호출(시스템 호출은 성능부하가 큼으로 한번에 큰 파일을 쓰기 위함)
open => 파일 혹은 장치 열기
read => 열린 파일 혹은 장치로 부터 읽기
write => 파일이나 장치에 쓰기
close => 파일이나 장치를 닫기
ioctl => 제어 정보를 장치 드라이버에 전달(각 드라이버 마다 고유한 ioctl 명령 집합이 있음)

리눅스 시스템
사용자 프로그램(라이브러리) => 사용자 공간

시스템 호출/커널(장치 드라이버) => 커널 공간

하드웨어 장치

write의 설명자
0 => 표준 입력
1 => 표준 출력
2 => 표준 에러

write 예시 => 반환값(0 데이터 안씀, -1 에러 발생, 1이상의 실제로 쓰여진 바이트 수)
size_t write(int fildes, const void *buf, size_t nbytes);

#include
#include
#include

int main()
{
if ((write(1, "Here is some data\n", 18)) != 18)
write(2, "A write error has occurred on file descriptor 1\n",46);

exit(0);
}

결과는
Here is some data

read 예시 => 반환값(0 데이터 안읽기, -1 에러 발생, 1이상의 실제로 읽어진 바이트 수)
size_t read(int fildes, const void *buf, size_t nbytes);

int main()
{
char buffer[128];
int nread;

nread = read(0, buffer, 128);
if (nread == -1)
write(2, "A read error has occurred\n", 26);

if ((write(1,buffer,nread__ != nread)
write(2, "A write error has occurred\n",27);

exit(0);
}

결과는
echo hello there | simple_read
hello there

open => 새로운 파일 설명자를 만들기 위해
int open(const char *path, int oflags);
int open(const char *path, int oflags, mode_t mode);

mode 맴버는
O_RDONLY => 읽기 전용
O_WRONLY => 쓰기 전용
O_RDWR => 읽고 쓰기용

oflags 맴버는
O_APPEND => 파일 끝에 붙이기
O_TRUNC => 파일의 길이를 0으로 설정하여 기존 내용을 삭제함
O_CREAT => 필요하다면 파일을 생성
O_EXCL => O_CREAT와 함께 사용하며 파일이 만들었음을 확실 할 수 있음

#include
#include

파일을 만들때(O_CREAT)는 플래그 필요 맴버는
S_IRUSR : 읽기 권한, 소유자
S_IWUSR : 쓰기 권한, 소유자
S_IXUSR : 실행 권한, 소유자
S_IRGRP : 읽기 권한, 그룹
S_IWGRP : 쓰기 권한, 그룹
S_IXGRP : 실행 권한, 그룹
S_IROTH : 읽기 권한, 다른 사용자
S_IWOTH : 쓰기 권한, 다른 사용자
S_IXOTH : 실행 권한, 다른 사용자

예: myfile 파일을 만들면서 소유자의 읽기 권한과 다른 사용자의 실행 권한을 부여
open ("myfile", O_CREAT, S_IRUSR|S_IXOTH);

umask => 파일을 만들 때 사용할 파일의 권한 마스크를 인코드 하는 시스템 변수
close => 파일 간의 연결을 종료(반환값 : 0 성공, -1 실패)
int close(int fildes);

limits.h => 실행중에 한번에 열수 있는 파일의 개수 제한(OPEN_MAX)

ioctl => 장치 제어
int ioctl(int fildes, int cmd, ...);

TIMEFORMAT="" time copy_system => 복사에 대해서 점유율 파악
Command exited with non-zero status 127
0.00user 0.00system 0:00.00elapsed 0%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+0outputs (0major+49minor)pagefaults 0swaps

저수준의 파일 복사하기 기능 예:
#include
#include
#include
#include

int main()
{
char block[1024];
int in, out;
int nread;

in = open("file.in", O_RDONLY);
out = open("file.out", O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);
while((nread = read(in,block,sizeof(block))) > 0)
write(out,block,nread);

exit(0);
}

lseek => 파일 설명자 filedes의 읽기/쓰기 포인터를 설정
off_t lseek(int fildes, off_t offset, int whence);

fstat => 열린 파일 설명자에 연결된 파일의 관한 상태 정보를 반환
stat => 명명된 파일의 상태 정보를 반환
lstat => 명명된 파일의 상태 정보를 기호화된 링크로 반환
int fstat(int fildes, struct stat *buf)
int stat(const char *path, struct stat *buf);
int lstat(const char *path, struct stat *buf);

stat의 맴버는
st_mode => 파일 권한과 파일 형식 정보
st_ino => 파일과 관련된 inode
st_dev => 파일이 존재하는 장치
st_uid => 파일 소유자의 사용자 ID
st_gid => 파일 소유자의 그룹 ID
st_atime => 마지막 액세스 시간
st_ctime => 권한, 소유자, 그룹 혹은 내용이 마지막으로 변한 시간
st_mtime => 내용이 마지막으로 변한 시간
st_nlink => 파일에 대한 하드 링크의 갯수

예: 파일이 디렉토리가 아니고 소유자에 대한 실행 권한을 가지고 있지만 다른 권한을 가지고 있지 않은지 테스트
struct stat statbuf;
mode_t modes;

stat("filename",&statbuf);
modes = statbuf.st_mode;
if(!S_ISDIR(modes && (modes & S_ISWXU) == S_IXUSR)
...

dup, dup2 => 파일 설명자를 복제하는 방법
int dup(int fildes);
int dup2(int fildes, int fildes2);

기본 라이브러리(stdio.h)를 이용한 파일 입출력
fopen => 저수준 open 시스템 호출과 유사하나 저수준 시스템 호출은 입출력 버퍼링과 같은 잠재적 버그로 원하지 않는 부작용을 없애줌
FILE *fopen(const char *filename, const char *mode);
반환값(null 실패, FILE * 성공)
r 또는 rb => 읽기 전용
w 또는 wb => 쓰기, 내용을 모두 지움
a 또는 ab => 쓰기, 내용을 추가
r+ 또는rb+ 또는 r+b => 갱신(읽기와 쓰기)
w 또는 wb+ 또는 w+b => 갱신, 내용을 모두 지움
a+ 또는 ab+ 또는 a+b => 갱신, 내용을 추가
b는 파일이 텍스트가 아니라 바이너리 파일임을 가르킴(유닉스와 리눅스는 텍스트 파일은 없음 모두 바이너리로 취급함)

fread => 파일 스트림으로 부터 데이터를 읽기
size_t fread(void *ptr, size_t size, size_t nitems, FILE *stream);

fwrite => 지정된 데이터 버퍼에 있는 데이터 레코드를 출력 스트림으로 쓴다
size_t fwrite (const void *ptr, size_t size, size_t nitems, FILE *stream);

!!중요!!
구조화된 데이터를 사용하는 목적으로 fread와 fwrite를 권장하지 않는다. fwrite로 쓰여진 파일들이 다른 컴퓨터에서 잠재적으로 이식되지 않을 수도 있어서 문제의 소지가 있다

fclose => 지정된 stream을 닫으며 쓰여지지 않은 모든 데이터를 쓴다
int fclose(FILE *stream);
stream의 제한은 stdio.h에 FOPEN_MAX로 정의되어있고 최소 8이다

fflush => 파일 스트림의 모든 데이터가 즉시 쓰여짐
int fflush(FILE *stream);
fclose전에 fflush는 자동으로 호출됨으로 fclose 전에 호출할 필요가 없다

fseek => 저수준의 lseek에 해당하는 stream 함수이나 lseek는 off_t를 반환하고
int fseek(FILE *stream, long int offset, int whence);
fseek는 정수를 반환한다(반환값 -1 실패, 0 성공)

fgetc => 파일 스트림으로부터 다음 바이트를 문자로 반환(반환값 EOF 파일 끝, EOF 에러)
int fgetc(FILE *stream);
fgetc의 반환값이 EOF가 2가지가 존재함으로 ferror 혹은 feof를 사용 해야함

getc => 매크로로 구현된 fgetc임(지역 변수가 아니거나 함수의 매개변수로 전달되지
앟은 변수에 영향을 끼치지 못하고 getc의 주소를 함수 포인터로 사용할 수 없다)
int getc(FILE *stream);

getchar => getc(stdin)과 동일하며 표준 입력으로부터 다음 문자를 읽는다
int getchar();

fputc => 문자를 출력 스트림에 쓴다(반환값 : 쓴값 성공, EOF 실패)
int fputc(int c, FILE *stream);
putc => getc의 경우와 같음
int putc(int c, FILE *stream);
putchar => putc(cm, stdout)와 동일하며, 하나의 문자를 표준 출력으로 쓴다(문자를 char가 아닌 int로 취하고 반환함)(반환값: -1 문자끝)
int putchar(int c);

fgets => stream으로부터 문자열을 읽는다(최대 n-1 문자까지 한번에 전송가능)(반환값: 문자열 s에 대한 포인터를 반환)(반환값: EOF 파일끝, NULL 읽기에러)
char *fgets(char *s, int n, FILE *stream);
gets => fgets와 동일하며 표준 입력으로부터 읽고 줄 바꿈 문자를 없앤다는 차이가 있다
char *gets(char *s)

!!중요!!
gets는 전송할 수 있는 문자의 개수에 제한을 두지 않기 때문에 버퍼오버플로우 공격에 취약함으로 fgets로 쓰길 권장함

printf => 다른 형식을 가진 인자들을 형식화해서 출력
int printf(const char *format, ...);
예:
printf("Some numbers: %d, %d, and %d\n", 1, 2, 3);

결과는
Some numbers: 1, 2, and 3

fprintf => 자신의 출력을 지정된 stream에 작성
int fprintf(FILE *stream, const char *format, ...);
sprintf => 자신의 출력과 종료 널 문자를 매개변수로 전달된 문자열 s에 쓴다
int sprintf(char *s, const char *format, ...);

%d, %i => 정수를 십진 형태로 출력
%o, %x => 8진, 16진으로 출력
%c => 문자를 출력
%s => 문자열을 출력
%f => 부동 소수점 단위로 출력
%e => 배정밀도(double) 숫자를 고정된 형식으로 출력
%g => 배정밀도 숫자를 일반적인 형식으로 출력

예:
char initial = 'A';
char *surname "Matthew";
double age = 14.5;
printf("Hello Miss %c %s, aged %g\n", initial, surname, age);

결과는
Hello Miss A Matthew, aged 14.5

예: 181페이지 참조
%10s의 인자값이 Hello일때 결과는 | Hello|

scanf => 스트림으로부터 항목을 읽고 변수에 값을 저장(반환값: 0 실패, EOF 항목이 일치하기 전에 끝에 도달하면, 읽어들인 변수의 갯수 성공)
int scanf(const char *format, ...);
예:
int num;
scanf("Hello %d", &num);

실행방법(밑에 2개 모두 num에 1234가 들어감, Hello와 일치할 경우 %d에 따라 숫자가 오면 들어감)
Hello 1234
Hello1234

!!중요!!
정수를 입력받기 위해 스캔하면서 입력에 숫자가 아닌 문자가 들어온다면 무한 반복문이 발생할 수 있다

%d => 십진 정수 스캔
%o, %x => 8진, 16진 정수를 스캔
$f, $e, $g => 부동 소수점 숫자를 스캔
$s => 문자열 스캔(첫번째 공백에서 멈춤으로 단어용으로 씀)
$[] => 문자들의 집합을 스캔
%% => %문자를 스캔
%c => 하나의 문자만 스캔

예:
Hello, 1234, 5.678, X, string to the of the line를 스캔할 경우

char s[256];
int n;
float f;
char c;

scanf("Hello, %d, %g, %c, %[^\n]", &n, &f, &c, s);

!!중요!!
한 줄을 입력 받고 스캔하기 위해서는 필드 지정자를 사용하거나 fgets와 sscanf를 혼용하는것이 좋다)

int fscanf(FILE *stream, const char *format, ...);
int sscanf(const char *s, const char *format, ...);

!!중요!!
scanf 계열은 사용을 자제(여러 줄의 입력을 읽기 이해서는 fread나 ggets와 같은 함수를 사용)
정통적으로 구현상에 버그가 있음
사용하기에 유연하지 않음
구문 분석된 항목에 대해 작업하기 어려운 방향의 코드가 됨

기타 스트림 함수
fgetpos : 파일 스트림의 현재 위치를 얻는다
fsetpos : 파일 스트림의 현재 위치를 설정한다
ftell : 스트림의 현재 파일 옵셋을 반환한다
rewind : 스트림이 파일 위치를 처음으로 설정한다
freopen : 파일 스트림을 다시 사용한다
setvvuf : 스트림을 위한 버퍼링 방법을 설정한다
remove : 파일이면 unlink와 동일하고 디렉토리면 rmdir과 동일

표준라이브러리를 이용한 파일 복사하기 기능(저수준 보다 느림) 예:
#include
#include

int main()
{
int c;
FILE *in, *out;

in = fopen("file.n", "r");
out = fopen("file.out","w");

while((c=fgetc(in)) != EOF)
fputc(c,out);

exit(0);
}

저수준의 파일 복사하기 기능 예(다시):
#include
#include
#include
#include

int main()
{
char block[1024];
int in, out;
int nread;

in = open("file.in", O_RDONLY);
out = open("file.out", O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);
while((nread = read(in,block,sizeof(block))) > 0)
write(out,block,nread);

exit(0);
}

스트림 에러 처리
errno => 저수준의 에러 값을 반환하는데 이때 에러는 외부 변수 errno에 명시됨
#include
extern int errno;

!!중요!!
여러 함수가 errno의 값을 변경시킬수 있으므로 함수 에러 발생시 즉시 검사를 시행하고 항상 이 변수의 값을 사용하기 전에 다른 변수에 복사하고 쓴다

ferror => 스트림에 대한 에러 표시(반환값: 0 설정안됨, 0이외 설정됨)
int ferror(FILE *stream);

feof => 스트림에서 파일 끝 표시(반환값: 0 설정안됨, 0이외 설정됨)
int feof(FILE *stream);

예:
if(feof(some_stream))
/* 끝에 도달 */

clearerr => 스트림이 가리키는 스트림에서 파일 끝 표시와 에러 표시를 초기화("디스크 공간 부족" 에러가 해결된 다음 스트림에 쓰기 작업을 계속 수행할 때 쓰임)
void clearerr(FILE *stream);

fileno => 어떤 저수준 파일 설명자를 파일 스트림에 대해서 사용할 때(반환값: -1 실패, 주어진 스트림의 파일 설명자 성공)(열린 스트림에 대해서 fstat를 호출하는 것과 같이 저수준 액세스가 필요한 경우 유용하게 쓰임)
int fileno(FILE *stream);
FILE *fdopen(int fildes, const char *mode); => 이미 열린 파일 설명자를 기반으로 새로운 파일 스트림을 생성할 수 잇다(이미 열린 파일 설명자 주변에 stdio 버퍼를 제공)(fopen 함수와 동일한 방식으로 작동하는데 파일 이름 대신 저수준 파일 설명자를 받음)(반환값: NULL 실패, 새로운 파일 스트림 성공)

chmod => 시스템 호출을 사용하여 파일이나 디렉토리에 대한 권한을 변경(쉘 기반)
#include
int chmod(const char *path, mode_t mode);

chown => 시스템 호출을 사용하여 파일의 소유자를 변경
#include
int chown(const char *path, uid_t owner, gid_t group);

unlink => 시스템 호출을 사용하여 파일에 대한 디렉토리 항목을 지우고 링크 개수를 감소시킴(반환값: 0 성공, -1 에러)(unlink를 사용하려면 파일의 디렉토리 항목에 포함된 모든 디렉토리에 대해 쓰기와 실행 권한이 필요함)(rm 프로그램은 이 호출을 사용)
#include
int unlink(const char *path)
link => 기존파일 path1에 대해서 새로운 링크를 만들고 새로운 디렉토리 항목을 path2로 지정
int link(const char *path1, const char *path2);
symlink => 기호화된 링크 만들기(일반(하드) 링크와는 달리 파일이 효과적으로 삭제되는 것을 방지해 주지 않음)
int symlink(const char *path1, const char *path2);

!!중요!!
프로그램이 종료하면 파일을 자동삭제 하기 위해서 임시 파일로 쓰겠다면 open으로 파일을 만들고 바로 unlink를 호출함

mkdir => 디렉토리 생성
#include
int mkdir(const char *path, mode_t mode);
rmdir => 디렉토리 삭제(디렉토리가 비어있을 때만 가능)
#include
int rmdir(const char *path);

chdir => 디렉토리 변경
#include
int chdir(const char *path);

getcwd => 현재 작업 디렉토리 변경(반환값: null 에러(size보다 클때, 디렉토리가 삭제되었을때), buf반환 성공)
#include
char *getcwd(char *buf, size_t size);

opendir => (저수준)디렉토리를 열고 디렉토리 스트림을 생성(저수준임으로 너무 많은 파일을 열면 실패할 수도 있다)(반환값: 널 실패)
#include
#include
DIR *opendir(const char *name);

readdir => 디렉토리 스트림 dirp 내부에 다음 디렉토리 항목에 관한 구조체의 포인터 반환하고 디렉토리 끝에서는 NULL을 반환한다
#include
#include
struct dirent *readdir(DIR *dirp);

dirent 구조체는(더 많은 사항을 결정하려면 stat를 호출한다)
ino_t d_ino: 파일의 inode
char d_name[] : 파일의 이름

telldir => 디렉토리 스트림의 현재 위치를 기록하는 값을 반환
#include
#include
long int telldir(DIR *dirp);

seekdir => telldir 후에 디렉토리 스캔을 현재 위치로 다시 설정
#include
#include
void seekdir(DIR *dirp, long int loc);

closedir => 디렉토리 스트림을 닫음(반환값: 0 성공, 1 에러)
#include
#include
int closedir(DIR *dirp);

간단한 디렉토리 목록을 생성 예: 193페이지 참조
결과는
디렉토리의 각 파일은 한줄에 나열되고 각 하위 디렉토리의 이름에는 마지막에 슬래시(/)가 붙어있고 하위 디렉토리 하의 파일들은 공백 4자로 들여쓴다

lstat(entry ->d_name, &statbuf); // entry에 저장된 디렉토리명을 상태 버퍼에 저장

errno <= 에러처리(errno.h 안에 나열되어 있음)
EPERM : 연산이 허용되지 않음
ENOENT : 그러한 파일이나 디렉토리가 없다

strerror => 에러 번호를 문자열에 대응 시킴
#include
char *strerror(int errnum);

perror => errno에 보고된 현재 에러를 문자열에 대응 시키고 표준 에러 스트림에 출력
#include
void perror(const char *s);

예:
perror("program");

결과
program: Too many open files

/proc => 파일 시스템에 하드웨어 장치에 대한 목록화(리눅스는 대부분의 사항을 파일로 다룸)(리눅스는 특수한 파일 시스템인 procfs를 제공)
/dev => 저수준 시스템 호출을 사용하는 특벽한 방법으로 하드웨어 액세스

cat /proc/net/sockstat => 소켓 사용량 보기
cat /proc/sys/fs/file-max => 한개의 프로세스에서 파일을 최대로 열수 있는 갯수

!!중요!!(튜닝)
echo 60000 > /proc/sys/fs/file-max => 60000으로 변경(DB 용)
부팅 후도 계속 => /etc/sysctl.conf에 fs.file-max = 60000 추가
/etc/security/limits.conf 끝에 * - nofile 60000 추가

ulimit -a 또는 -Sa => soft 한도
ulimit -Ha => Hard 한도
lsof => 프로세스에서 열어놓은 파일 보기

PID는 기본적으로 1~32,000 사이의 값

od -c /proc/"PID"/cmdline => vi에서 어떤 파일을 열었는지 확인
/proc/"PID"/fd/ => 이 프로세스가 사용하고 있는 열린 파일 설명자에 관한 정보가 있음(설명자 0,1,2는 표준 입력,출력,에러 설명자임)

fcntl => 저수준 파일 설명자를 조작(파일 설명자 복제, 파일 설명자 플래그 설정하고 구하기, 파일 상태 플래그 설정하고 구하기, 관고 파일 잠금 관리)
#include
int fcntl(int fildes, int cmd);
int fcntl(int fildes, int cmd, long arg);

mmap => 메모리 맵을 이용해서 두개 이상의 프로그램이 함께 쓰고 읽을 수 있는 메모리 세그먼트를 설정(공유메모리)(off 매개변수를 전달하여 공유 세그먼트에 의해 액세스되는 파일 데이터의 시작 위치를 변경할 수 있고 열린 파일 설명자는 filedes로 전달되고 액세스 할 수 잇는 데이터의 양은 len 매개변수로 설정된다)(addr 틀정 메모리 주소를 요청(보통 0을 넣어서 자동 할당으로 설정))
#include
void *mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off);

msync => 메모리 세그먼트 부분 혹은 전부에 가해진 변경 사항을 매핑된 파일로 쓰거나 매핑된 파일로 부터 읽는다
#include
int msync(void *addr, size_t len, int flags);

mnumap => 메모리 세그먼트를 해지함
#include
int munmap(void *addr, size_t len);

mmap 예: 205페이지 참조

댓글 없음:

댓글 쓰기