programing

C의 버퍼에 텍스트 파일을 읽는 올바른 방법은?

closeapi 2023. 10. 18. 22:08
반응형

C의 버퍼에 텍스트 파일을 읽는 올바른 방법은?

처리하는 동안 버퍼에 읽고 싶은 작은 텍스트 파일을 다루고 있으므로 다음 코드를 생각해 냈습니다.

...
char source[1000000];

FILE *fp = fopen("TheFile.txt", "r");
if(fp != NULL)
{
    while((symbol = getc(fp)) != EOF)
    {
        strcat(source, &symbol);
    }
    fclose(fp);
}
...

이것이 파일의 내용을 버퍼에 넣는 올바른 방법인가요 아니면 제가 남용하고 있는 것인가요?strcat()?

그런 다음 버퍼를 통해 반복합니다.

for(int x = 0; (c = source[x]) != '\0'; x++)
{
    //Process chars
}
char source[1000000];

FILE *fp = fopen("TheFile.txt", "r");
if(fp != NULL)
{
    while((symbol = getc(fp)) != EOF)
    {
        strcat(source, &symbol);
    }
    fclose(fp);
}

이 코드에는 몇 가지 문제가 있습니다.

  1. 매우 느립니다(버퍼를 한 번에 한 문자씩 추출합니다).
  2. 파일 크기가 끝나면sizeof(source), 버퍼 오버플로가 발생하기 쉽습니다.
  3. 정말로, 좀 더 자세히 보면 이 코드가 전혀 작동하지 않을 겁니다.맨 페이지에 명시된 바와 같이:

strcat()function은 null-terminated 문자열 s1의 끝에 null-terminated 문자열 s2의 복사본을 추가한 다음 '\0'을 종료합니다.

NUL이 종료되거나 종료되지 않을 수 있는 문자열에 NUL이 종료된 문자열이 아닌 문자를 추가하는 것입니다.man-page 설명에 따라 이것이 작동하는 것을 상상할 수 있는 유일한 경우는 파일의 모든 문자가 NUL이 종료되는 경우입니다. 이 경우에는 오히려 무의미할 것입니다.그래요, 이건 정말 끔찍한 학대입니다.strcat().

대신 사용을 고려해야 할 두 가지 대안은 다음과 같습니다.

최대 버퍼 크기를 미리 알고 있는 경우:

#include <stdio.h>
#define MAXBUFLEN 1000000

char source[MAXBUFLEN + 1];
FILE *fp = fopen("foo.txt", "r");
if (fp != NULL) {
    size_t newLen = fread(source, sizeof(char), MAXBUFLEN, fp);
    if ( ferror( fp ) != 0 ) {
        fputs("Error reading file", stderr);
    } else {
        source[newLen++] = '\0'; /* Just to be safe. */
    }

    fclose(fp);
}

또는 그렇지 않은 경우:

#include <stdio.h>
#include <stdlib.h>

char *source = NULL;
FILE *fp = fopen("foo.txt", "r");
if (fp != NULL) {
    /* Go to the end of the file. */
    if (fseek(fp, 0L, SEEK_END) == 0) {
        /* Get the size of the file. */
        long bufsize = ftell(fp);
        if (bufsize == -1) { /* Error */ }

        /* Allocate our buffer to that size. */
        source = malloc(sizeof(char) * (bufsize + 1));

        /* Go back to the start of the file. */
        if (fseek(fp, 0L, SEEK_SET) != 0) { /* Error */ }

        /* Read the entire file into memory. */
        size_t newLen = fread(source, sizeof(char), bufsize, fp);
        if ( ferror( fp ) != 0 ) {
            fputs("Error reading file", stderr);
        } else {
            source[newLen++] = '\0'; /* Just to be safe. */
        }
    }
    fclose(fp);
}

free(source); /* Don't forget to call free() later! */

네, 아마 스트랫을 끔찍한 학대로 체포될 겁니다!

getline()을 살펴보세요. 한 번에 한 줄씩 데이터를 읽지만 중요한 것은 읽는 문자의 수를 제한할 수 있기 때문에 버퍼가 오버플로되지 않습니다.

Strcat은 모든 문자 삽입 시 문자열 전체에서 끝을 검색해야 하기 때문에 상대적으로 느립니다.일반적으로 문자열 저장소의 현재 끝에 포인터를 두고 다음 줄을 읽을 위치로 줄을 가져오도록 전달합니다.

리눅스 시스템의 경우 파일 설명자를 가지고 있으면 fstat()을 사용하여 파일에 대한 많은 정보를 얻을 수 있습니다.

http://linux.die.net/man/2/stat

그래서 당신은 아마

#include  <unistd.h> 
void main()
{
    struct stat stat;
    int fd;
    //get file descriptor
    fstat(fd, &stat);
    //the size of the file is now in stat.st_size
}

이렇게 하면 파일의 처음과 끝을 찾을 수 없습니다.

사용하지 않으려는 이유에 대해서는 JoelOn Software의 이 기사를 참조하십시오.strcat.

다른 대안을 찾기 위해 빵을 보세요.바이트나 문자를 읽을 때 크기는 1과 함께 사용합니다.

그냥 당신이 가지고 있는 차들의 배열을 사용하는게 어때요?이렇게 해야 합니다.

   source[i] = getc(fp); 
   i++;

테스트되지 않았지만 작동해야 합니다.그리고 네, 빵으로 더 잘 구현될 수 있습니다. 독자들에게 연습문제로 맡기겠습니다.

#define DEFAULT_SIZE 100
#define STEP_SIZE 100

char *buffer[DEFAULT_SIZE];
size_t buffer_sz=DEFAULT_SIZE;
size_t i=0;
while(!feof(fp)){
  buffer[i]=fgetc(fp);
  i++;
  if(i>=buffer_sz){
    buffer_sz+=STEP_SIZE;
    void *tmp=buffer;
    buffer=realloc(buffer,buffer_sz);
    if(buffer==null){ free(tmp); exit(1);} //ensure we don't have a memory leak
  }
}
buffer[i]=0;

당신이 자유를 원한다고 생각합니다.

http://www.cplusplus.com/reference/clibrary/cstdio/fread/

mmap()을 고려해보셨습니까?파일을 마치 메모리에 저장된 것처럼 바로 읽을 수 있습니다.

http://beej.us/guide/bgipc/output/html/multipage/mmap.html

언급URL : https://stackoverflow.com/questions/2029103/correct-way-to-read-a-text-file-into-a-buffer-in-c

반응형