C,C++ & Linux

C/C++ read 함수 - 파일을 읽는 함수

KyooDong 2020. 4. 22. 01:28
728x90

read(2) 함수 기능

파일을 읽는 함수입니다.

함수 원형

#include <unistd.h>

ssize_t read(int fd, void *buf, size_t nbytes);

매개변수

int fd

읽을 파일의 파일 디스크립터

 

void *buf

읽어들인 데이터를 저장할 버퍼(배열)

 

size_t nbytes

읽어들일 데이터의 최대 길이 (buf의 길이보다 길어선 안됨)

반환값

읽어들인 데이터의 길이

무조건 nbytes 가 리턴되는 것은 아님. 중간에 파일의 끝을 만난다면 거기까지만 읽기 때문

예제

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "ssu_employee.h"


int main(int argc, char *argv[]) {
	struct ssu_employee record;
	int fd;
	int record_num;

	if (argc < 2) {
		fprintf(stderr, "Usage : %s file\n", argv[0]);
		exit(1);
	}
	
    // 입력받은 파일을 읽기모드로 열기
	if ((fd = open(argv[1], O_RDONLY)) < 0) {
		fprintf(stderr, "open error for %s\n", argv[1]);
		exit(1);
	}

	while (1) {
		printf("Enter record number : ");
		scanf("%d", &record_num);

		// 음수 레코드 번호 입력 시 종료
		if (record_num < 0)
			break;

		// record_num 번째 레코드에 접근
		if (lseek(fd, (long) record_num * sizeof(record), 0) < 0) {
			fprintf(stderr, "lseek error\n");
			exit(1);
		}

		// record_num 번째 레코드의 시작부분에서부터 record 사이즈만큼 읽음
        // 이는 곧 record_num 번째 레코드를 읽어들여 record 변수에 저장함을 의미
		if (read(fd, (char *) &record, sizeof(record)) > 0)
			printf("Employee : %s Salary : %d\n", record.name, record.salary);
		else
		printf("Record %d not found\n", record_num);
	}
	close(fd);
	exit(0);
}

레코드 생성하는 코드는 write 에 있습니다.

 

 

<ssu_test.txt>
Linux System Programming!
Unix System Programming!
Linux Mania
Unix Mania

<main.c>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

#define BUFFER_SIZE 1024

int main(int argc, char *argv[]) {
	char buf[BUFFER_SIZE];
	char *fname = "ssu_test.txt";
	int count;
	int fd1, fd2;
	
	fd1 = open(fname, O_RDONLY, 0644);
	fd2 = open(fname, O_RDONLY, 0644);

	if (fd1 < 0 || fd2 < 0) {
		fprintf(stderr, "open error for %s\n", fname);
		exit(1);
	}

	// Linux System Programming! 읽어들여서 buf에 저장
    // 이 때 널문자'\0' 는 buf에 없음
	count = read(fd1, buf, 25);
    
    // 따라서 이 구문이 없으면 뒷 쪽의 쓰레기 값들이 %s 를 통해 출력됨
	buf[count] = 0;
	printf("fd1's first printf : %s\n", buf);
    
    // 줄바꿈을 읽지 않기 위해 seek position 1칸 이동
	lseek(fd1, 1, SEEK_CUR);

	// Unix System Programming! 읽어서 buf에 저장
	count = read(fd1, buf, 24);
	buf[count] = 0;
	printf("fd1's second printf : %s\n", buf);

	// 여기서부터는 fd2 를 읽는데
    // fd1 을 아무리 읽고 써도 fd2의 seek position 에는 변화가 없으므로
    // fd2 의 seek position 은 파일의 맨 앞에 있음
	count = read(fd2, buf, 25);
	buf[count] = 0;
	printf("fd2's first printf : %s\n", buf);
	lseek(fd2, 1, SEEK_CUR);

	count = read(fd2, buf, 24);
	buf[count] = 0;
	printf("fd2's second printf : %s\n", buf);

	exit(0);
}

 

 

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

int main(int argc, char *argv[]) {
    int fd;
    char c;

    if ((fd = open("ssu_test.txt", O_RDONLY)) < 0) {
        fprintf(stderr, "open error for %s\n", "ssu_test.txt");
        exit(1);
    }

    while (1) {
    	// 모든 글자를 한 글자씩 읽어들임
        // 파일에 끝에 도달하여 읽지 못하는 순간 -1 리턴되어 끝남
        if (read(fd, &c, 1) > 0)
            putchar(c);
        else
            break;
    }

	exit(0);
}

 

 

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

#define TABLE_SIZE 128
#define BUFFER_SIZE 1024

int main(int argc, char *argv[]) {
    static struct {
        long offset;  // 데이터가 시작하는 위치
        int length;   // 데이터의 총 길이
    } table[TABLE_SIZE];

    char buf[BUFFER_SIZE];
    long offset;
    int entry;
    int i;
    int length;
    int fd;

    if (argc < 2) {
        fprintf(stderr, "usage: %s <file>\n", argv[0]);
        exit(1);
    }

    if ((fd = open(argv[1], O_RDONLY)) < 0) {
        fprintf(stderr, "open error for %s\n", argv[1]);
        exit(1);
    }

    entry = 0;
    offset = 0;
    // 파일을 끝까지 읽음
    while ((length = read(fd, buf, BUFFER_SIZE)) > 0) {
    	// 매 글자 체크
        for (int i = 0; i < length; i++) {
            table[entry].length++;
            offset++;

			// 개행문자가 발견되면 table 의 다음번(entry에 offset을 저장)
            if (buf[i] == '\n')
                table[++entry].offset = offset;
        }
    }

    //for (i = 0; i < entry; i++)
    //    printf("%d : %ld, %d\n", i + 1, table[i].offset, table[i].length);

    while (1) {
        printf("Enter line number : ");
        scanf("%d", &length);

        if (--length < 0)
            break;

		// table[length].offset 에는 length 번째 줄이 파일의 몇 바이트 부분에서 시작되는지 저장되어 있으므로
        // 해당 위치로 찾아가서
        lseek(fd, table[length].offset, 0);

		// table[length].length 만큼 읽으면 length 번째 줄을 다 읽게됨
        if (read(fd, buf, table[length].length) <= 0) 
            continue;

        buf[table[length].length] = '\0';
        printf("%s", buf);
    }

    close(fd);
	exit(0);
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

리눅스시스템프로그래밍 저자 : 홍지만
https://book.naver.com/bookdb/book_detail.nhn?bid=14623672

책에 기술된 예제 프로그램입니다. 책 내부에는 훨씬 더 많은 자료가 있습니다. (개인적으로 좋았습니다.)