Вопрос по posix, c, file-io, unix – Чтение большого файла с использованием C (более 4 ГБ) с использованием функции чтения, что вызывает проблемы

5

Я должен написать код C для чтения больших файлов. Код ниже:

int read_from_file_open(char *filename,long size)
{
    long read1=0;
    int result=1;
    int fd;
    int check=0;
    long *buffer=(long*) malloc(size * sizeof(int));
    fd = open(filename, O_RDONLY|O_LARGEFILE);
    if (fd == -1)
    {
       printf("\nFile Open Unsuccessful\n");
       exit (0);;
    }
    long chunk=0;
    lseek(fd,0,SEEK_SET);
    printf("\nCurrent Position%d\n",lseek(fd,size,SEEK_SET));
    while ( chunk < size )
    {
        printf ("the size of chunk read is  %d\n",chunk);
        if ( read(fd,buffer,1048576) == -1 )
        {
            result=0;
        }
        if (result == 0)
        {
            printf("\nRead Unsuccessful\n");
            close(fd);
            return(result);
        }

        chunk=chunk+1048576;
        lseek(fd,chunk,SEEK_SET);
        free(buffer);
    }

    printf("\nRead Successful\n");

    close(fd);
    return(result);
}

Проблема, с которой я здесь сталкиваюсь, заключается в том, что пока переданный аргумент (параметр размера) меньше 264000000 байт, он может читать. Я получаю увеличивающиеся размеры переменной чанка с каждым циклом.

Когда я передаю 264000000 байт или более, чтение завершается неудачно, то есть в соответствии с используемой проверкой чтение возвращает -1.

Кто-нибудь может указать мне, почему это происходит? Я компилирую с помощью cc в обычном режиме, не используя DD64.

И, наконец, вы не должны использоватьread при чтении из большого файла. Используя, например,mmap Это, вероятно, более эффективное решение, особенно если вы читаете файл последовательно. Some programmer dude
возможно дублирование дляstackoverflow.com/questions/3825896/… CyberDem0n
Есть некоторые серьезные проблемы с вашим кодом, которые я вижу. Прежде всего вы выделяете буфер для чтения, используяsize как размер. Затем вы читаете информацию о буфере, используя фиксированный размер, независимо от выделенного размера буфера, в который вы читаете. Подумай, что будет, еслиsize являетсяless чем 250к. Во-вторых, поскольку файл недавно открыт, вам не нужно искать в начале. В-третьих, вы затем стремитесьsize, но этоsize количество записей в файле или количество байтов? Ты используешьsize иначе при выделении буфера. Some programmer dude
Какая операционная система? Dietrich Epp
В-четвертых, вы освобождаете буфер внутри цикла, но не выделяете новый. Это означает, что на второй итерации он будет считывать в нераспределенную память. В-пятых, зоветread автоматически продвинет позицию в файле, вам не нужно искать каждый раз. В-шестых, когда вы читаете, вы проверяете на наличие ошибок, но не на конец файла.read возвращается0 в конце файла. Some programmer dude

Ваш Ответ

3   ответа
7

Во-первых, зачем вамlseek() в вашем цикле?read() переместит курсор в файл на количество прочитанных байтов.

И, к теме: long и, соответственно, chunk, имеют максимальное значение2147483647любое число, большее этого, станет отрицательным.

Вы хотите использоватьoff_t объявить чанк:off_t chunkи размер какsize_t. That's the main reason why lseek() выходит из строя.

И, опять же, как уже заметили другие люди, вы не хотитеfree() ваш буфер внутри цикла.

Обратите внимание, что вы перезапишете данные, которые вы уже прочитали. Дополнительно,read() не обязательно будет читать столько, сколько вы просили, поэтому лучше увеличивать порцию по количеству фактически прочитанных байтов, а не по количеству байтов, которые вы хотите прочитать.

Принимая все во внимание, правильный код, вероятно, должен выглядеть примерно так:

// Edited: note comments after the code
#ifndef O_LARGEFILE
#define O_LARGEFILE 0
#endif

int read_from_file_open(char *filename,size_t size)
{
int fd;
long *buffer=(long*) malloc(size * sizeof(long));
fd = open(filename, O_RDONLY|O_LARGEFILE);
   if (fd == -1)
    {
       printf("\nFile Open Unsuccessful\n");
       exit (0);;
    }
off_t chunk=0;
lseek(fd,0,SEEK_SET);
printf("\nCurrent Position%d\n",lseek(fd,size,SEEK_SET));
while ( chunk < size )
  {
   printf ("the size of chunk read is  %d\n",chunk);
   size_t readnow;
   readnow=read(fd,((char *)buffer)+chunk,1048576);
   if (readnow < 0 )
     {
        printf("\nRead Unsuccessful\n");
        free (buffer);
        close (fd);
        return 0;
     }

   chunk=chunk+readnow;
  }

printf("\nRead Successful\n");

free(buffer);
close(fd);
return 1;

}

Я также взял на себя смелость удалить переменную результата и всю связанную логику, поскольку, как мне кажется, ее можно упростить.

Изменить: я отметил, что некоторые системы (в частности, BSD) не имеютO_LARGEFILE, так как там это не нужно. Итак, я добавил в начале #ifdef, что сделало бы код более переносимым.

0

У функции lseek могут быть трудности с поддержкой больших размеров файлов. Попробуйте использоватьlseek64

Пожалуйста, проверьте ссылку, чтобы увидеть связанные макросы, которые необходимо определить при использовании функции lseek64.

0

Если его 32-битный компьютер, это вызовет некоторые проблемы при чтении файла размером более 4 ГБ. Так что если вы используете компилятор gcc, попробуйте использовать макрос-D_LARGEFILE_SOURCE=1 а также-D_FILE_OFFSET_BITS=64.

Пожалуйста, проверьте этоссылка на сайт также

Если вы используете какой-либо другой компилятор, проверьте аналогичные типы параметров компилятора.

Похожие вопросы