2016-02-14 7 views
2

Я работаю над назначением в программировании сокетов, в котором я должен отправить файл между sparc и linux машиной. Перед отправкой файла в поток char я должен получить размер файла и сообщить клиенту. Вот некоторые из способов, которыми я пытался получить размер, но я не уверен, какой из них правильный.Правильный способ получить размер файла в C

Для целей тестирования я создал файл с содержанием "тестом" (пробел + (строка) тесты)

Метод 1 - Используя fseeko() и ftello()

Это метод Я нашел на https://www.securecoding.cert.org/confluence/display/c/FIO19-C.+Do+not+use+fseek()+and+ftell()+to+compute+the+size+of+a+regular+file В то время как fssek() имеет проблему «Установка индикатора положения файла в конец файла, как и в файле fseek (файл, 0, SEEK_END), имеет неопределенное поведение для двоичного потока», fseeko() как говорят, решает эту проблему, но он работает только в системе POSIX (это нормально, потому что среда, которую я использую, является sparc и linux)

fd = open(file_path, O_RDONLY); 
fp = fopen(file_path, "rb"); 
/* Ensure that the file is a regular file */ 
if ((fstat(fd, &st) != 0) || (!S_ISREG(st.st_mode))) { 
    /* Handle error */ 
} 
if (fseeko(fp, 0 , SEEK_END) != 0) { 
    /* Handle error */ 
} 
file_size = ftello(fp); 
fseeko(fp, 0, SEEK_SET); 
printf("file size %zu\n", file_size); 

Этот метод работает нормально и получает размер правильно. Однако он ограничен только обычными файлами. Я попытался использовать термин «обычный файл», но я до сих пор не совсем понимаю его. И я не знаю, надежна ли эта функция для моего проекта.

Метод 2 - Использование StrLen()

С макс. размер файла в моем проекте составляет 4 МБ, поэтому я могу просто вызывать 4 МБ буфер. После этого файл считывается в буфер, и я попытался использовать strlen, чтобы получить размер файла (или, вернее, длину содержимого). Поскольку strlen() переносима, могу ли я использовать этот метод вместо этого? Фрагмент кода, как этот

fp = fopen(file_path, "rb"); 
fread(file_buffer, 1024*1024*4, 1, fp); 
printf("strlen %zu\n", strlen(file_buffer)); 

Этот метод работает также и возвращает

strlen 8 

Однако, я не мог видеть любой подобный подход в Интернете с помощью этого метода. Поэтому я думаю, может быть, я что-то упустил или есть некоторые ограничения такого подхода, которые я не понял.

+4

Почему вы используете 'strlen()', когда 'fread()' уже сообщает, сколько он читает, а 'strlen()' останавливается при первом nul-байте? –

+1

Возможный дубликат [Использование fseek и ftell для определения размера файла имеет уязвимость?] (Http://stackoverflow.com/questions/5957845/using-fseek-and-ftell-to-determine-the-size- из-a-file-has-a-уязвимость) – anatolyg

+0

Также связано: http://stackoverflow.com/a/21050963/509868 – anatolyg

ответ

3

Обычный файл означает, что это ничего особенного, как устройство, сокет, труба и т. Д., Но «обычный» файл. Кажется, что по вашему описанию задачи перед отправкой вы должны получить размер обычного файла. Так что ваш путь правильно:

FILE* fp = fopen(...); 
if(fp) { 
    fseek(fp, 0 , SEEK_END); 
    long fileSize = ftell(fp); 
    fseek(fp, 0 , SEEK_SET);// needed for next read from beginning of file 
    ... 
    fclose(fp); 
} 

, но вы можете сделать это без открытия файла:

#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 

struct stat buffer; 
int   status; 

status = stat("path to file", &buffer); 
if(status == 0) { 
    // size of file is in member buffer.st_size; 
} 
+0

1) 'ftell (fp)' возвращает тип 'long', а не' size_t'. 2) Если 'fopen' был в текстовом режиме,« ... разница между двумя такими возвращаемыми значениями не обязательно является значимой мерой количества написанных или прочитанных символов ». C11 §7.21.9.4 2. 3) Размер файла может превышать LONG_MAX. – chux

+0

Thx Chux для уведомления, я исправил его. – StackPeter

1

OP может сделать это легко путь, как «Максимальный размер файла в моем проекте. 4MB ".

Вместо использования strlen() используйте возвращаемое значение от fread(). stlen() останавливается на первом нулевом символе, поэтому может сообщать слишком малое значение. @Sami Kuhmonen Также мы не знаем, что чтение данных содержит нулевой символ, поэтому это может быть не строка. Добавьте нулевой символ (и выделите +1), если код должен использовать данные в виде строки. Но в этом случае я ожидаю, что файл должен быть открыт в текстовом режиме.

Обратите внимание, что многие ОС не используют выделенную память до ее записи.
Why is malloc not "using up" the memory on my computer?

fp = fopen(file_path, "rb"); 
if (fp) { 

    #define MAX_FILE_SIZE 4194304 
    char *buf = malloc(MAX_FILE_SIZE); 
    if (buf) { 
    size_t numread = fread(buf, sizeof *buf, MAX_FILE_SIZE, fp); 

    // shrink if desired 
    char *tmp = realloc(buf, numread); 
    if (tmp) { 
     buf = tmp; 

     // Use buf with numread char 

    } 
    free(buf); 
    } 
    fclose(fp); 
} 

Примечание: Чтение всего файла в память не может быть лучшей идеей, чтобы начать с.