Как я могу определить размер файла в байтах?
#include <stdio.h>
unsigned int fsize(char* file){
//what goes here?
}
Почему char* file, а почему не FILE* file? -1
@ user12211554 так что ... просто strlen!
Обратите внимание: файл может увеличиваться между fsize и read. Будь осторожен.





Если вас устраивает библиотека std c:
#include <sys/stat.h>
off_t fsize(char *file) {
struct stat filestat;
if (stat(file, &filestat) == 0) {
return filestat.st_size;
}
return 0;
}
Это не стандартный C. Это часть стандарта POSIX, но не стандарта C.
Вы можете открыть файл, перейти к 0 смещению относительно нижней части файла с помощью
#define SEEKBOTTOM 2
fseek(handle, 0, SEEKBOTTOM)
значение, возвращаемое из fseek, - это размер файла.
Я долгое время не программировал на C, но думаю, это должно сработать.
Вам не нужно определять что-то вроде SEEKBOTTOM. #include
Решение Мэтта должно работать, за исключением того, что это C++ вместо C, и в начальном сообщении нет необходимости.
unsigned long fsize(char* file)
{
FILE * f = fopen(file, "r");
fseek(f, 0, SEEK_END);
unsigned long len = (unsigned long)ftell(f);
fclose(f);
return len;
}
Поправил скобу и для тебя. ;)
Обновление: это не лучшее решение. В Windows он ограничен файлами размером 4 ГБ и, вероятно, медленнее, чем просто использование вызова для конкретной платформы, такого как GetFileSizeEx или stat64.
Да, ты должен. Однако, если нет действительно веской причины не писать для конкретной платформы, вам, вероятно, следует просто использовать вызов, специфичный для платформы, а не шаблон open / seek-end / tell / close.
Извините за поздний ответ, но у меня серьезная проблема. Это приводит к зависанию приложения при доступе к файлам с ограниченным доступом (например, защищенным паролем или системным файлам). Есть ли способ при необходимости запросить у пользователя пароль?
@Justin, вам, вероятно, следует открыть новый вопрос конкретно о проблеме, с которой вы столкнулись, и предоставить подробную информацию о платформе, на которой вы находитесь, о том, как вы получаете доступ к файлам и каково поведение.
И C99, и C11 возвращают long int из ftell(). Литье (unsigned long) не улучшает диапазон, поскольку уже ограничен функцией. ftell() возвращает -1 при ошибке, и это запутывается с приведением типов. Предложите fsize() вернуть тот же тип, что и ftell().
Я согласен. Актерский состав должен был соответствовать оригинальному прототипу в вопросе. Я не могу вспомнить, почему я превратил его в unsigned long вместо unsigned int.
** Не делайте этого (Почему?):
Quoting the C99 standard doc that i found online: "Setting the file position indicator to end-of-file, as with
fseek(file, 0, SEEK_END), has undefined behavior for a binary stream (because of possible trailing null characters) or for any stream with state-dependent encoding that does not assuredly end in the initial shift state.**
Измените определение на int, чтобы можно было передавать сообщения об ошибках, а затем используйте fseek() и ftell() для определения размера файла.
int fsize(char* file) {
int size;
FILE* fh;
fh = fopen(file, "rb"); //binary mode
if (fh != NULL){
if ( fseek(fh, 0, SEEK_END) ){
fclose(fh);
return -1;
}
size = ftell(fh);
fclose(fh);
return size;
}
return -1; //error
}
@mezhaka: Этот отчет CERT просто неверен. fseeko и ftello (или fseek и ftell, если вы застряли без первого и довольны ограничениями на размеры файлов, с которыми вы можете работать) - правильный способ определения длины файла. Решения на основе statне работает для многих «файлов» (таких как блочные устройства) и не переносятся в системы, отличные от POSIX.
Это единственный способ получить размер файла во многих системах, несовместимых с posix (например, в моем очень минималистичном mbed)
Я нашел метод с использованием fseek и ftell и ветку с этим вопросом с ответами, что это невозможно сделать на одном языке C другим способом.
Вы можете использовать библиотеку переносимости, такую как NSPR (библиотека, на которой работает Firefox).
Не используйте int. Файлы размером более 2 гигабайт в наши дни стали обычным явлением
Не используйте unsigned int. Файлы размером более 4 гигабайт обычно встречаются в качестве немного менее распространенной грязи.
Стандартная библиотека IIRC определяет off_t как 64-битное целое число без знака, которое следует использовать всем. Мы можем переопределить это значение до 128 бит через несколько лет, когда у нас появится 16 эксабайтных файлов.
Если вы работаете в Windows, вам следует использовать GetFileSizeEx - он фактически использует подписанное 64-битное целое число, поэтому они начнут сталкиваться с проблемами с 8-ми эксабайтными файлами. Глупый Microsoft! :-)
Я использовал компиляторы, где off_t - 32 бита. Конечно, это во встроенных системах, где файлы размером 4 ГБ встречаются реже. В любом случае, POSIX также определяет off64_t и соответствующие методы, чтобы добавить путаницы.
Мне всегда нравятся ответы, которые предполагают наличие Windows и не делают ничего, кроме критики вопроса. Не могли бы вы добавить что-нибудь, совместимое с POSIX?
@ JL2210 принятый ответ от Теда Персиваля показывает решение, совместимое с posix, поэтому я не вижу смысла повторять очевидное. Я (и еще 70 человек) подумал, что добавление примечания об окнах и отказ от использования 32-битных целых чисел со знаком для представления размеров файлов было добавлением ценности к этому. Ваше здоровье
А если вы создаете приложение для Windows, используйте GetFileSizeEx API, поскольку ввод-вывод файла CRT беспорядочный, особенно для определения длины файла, из-за особенностей представления файлов в разных системах;)
На основе кода NilObject:
#include <sys/stat.h>
#include <sys/types.h>
off_t fsize(const char *filename) {
struct stat st;
if (stat(filename, &st) == 0)
return st.st_size;
return -1;
}
Изменения:
const char.struct stat, в котором отсутствовало имя переменной.-1 вместо 0, что было бы неоднозначно для пустого файла. off_t - это тип со знаком, поэтому это возможно.Если вы хотите, чтобы fsize() выводил сообщение об ошибке, вы можете использовать это:
#include <sys/stat.h>
#include <sys/types.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
off_t fsize(const char *filename) {
struct stat st;
if (stat(filename, &st) == 0)
return st.st_size;
fprintf(stderr, "Cannot determine size of %s: %s\n",
filename, strerror(errno));
return -1;
}
В 32-битных системах вы должны скомпилировать это с опцией -D_FILE_OFFSET_BITS=64, иначе off_t будет хранить только значения до 2 ГБ. См. Подробности в разделе «Использование LFS» в Поддержка больших файлов в Linux.
Это специфично для Linux / Unix - вероятно, стоит указать на это, поскольку в вопросе не указана ОС.
Вероятно, вы могли бы без проблем изменить тип возвращаемого значения на ssize_t и преобразовать размер из off_t. Казалось бы, имеет смысл использовать ssize_t :-) (не путать с size_t, которое не имеет знака и не может использоваться для обозначения ошибки.)
Для более переносимого кода используйте fseek + ftell, предложенный Дереком.
fseek + ftell, предложенный Дереком. No. The C Стандартный specifically states that fseek() to SEEK_END on a binary file is undefined behavior. 7.19.9.2 Функция fseek... Двоичный поток не обязательно должен поддерживать вызовы fseek со значением источника SEEK_END, and as noted below, which is from footnote 234 on p. 267 of the linked C Standard, and which specifically labels fseek to SEEK_END in a binary stream as undefined behavior. .
Из gnu libc руководство: ... [не-POSIX] системы проводят различие между файлами, содержащими текст, и файлами, содержащими двоичные данные, и средства ввода и вывода ISO C обеспечивают это различие. ... В библиотеке GNU C и во всех системах POSIX нет разницы между текстовыми потоками и двоичными потоками. Когда вы открываете поток, вы получаете тот же поток независимо от того, запрашиваете ли вы двоичный файл. Этот поток может обрабатывать любое содержимое файла и не имеет ограничений, которые иногда имеют текстовые потоки.
Я использовал этот набор кода, чтобы найти длину файла.
//opens a file with a file descriptor
FILE * i_file;
i_file = fopen(source, "r");
//gets a long from the file descriptor for fstat
long f_d = fileno(i_file);
struct stat buffer;
fstat(f_d, &buffer);
//stores file size
long file_length = buffer.st_size;
fclose(i_file);
Вот простая и понятная функция, которая возвращает размер файла.
long get_file_size(char *path)
{
FILE *fp;
long size = -1;
/* Open file for reading */
fp = fopen(path, "r");
fseek(fp, 0, SEEK_END);
size = ftell(fp);
fclose(fp);
return
}
Не нужно ли закрывать файл?
Нет, мне не нравятся функции, ожидающие пути. Вместо этого, пожалуйста, сделайте так, чтобы указатель на файл
ftell может не быть байтовым смещением для текстовых файлов (вы открываете файл в текстовом режиме)
fp.close() не компилируется
А что будет, если вы работаете в Windows и размер файла составляет 14 ГБ?
Попробуй это --
fseek(fp, 0, SEEK_END);
unsigned long int file_size = ftell(fp);
rewind(fp);
Сначала выполняется поиск до конца файла; затем сообщите, где находится указатель файла. Наконец (это необязательно) он перематывает назад к началу файла. Обратите внимание, что fp должен быть двоичным потоком.
file_size содержит количество байтов, содержащихся в файле. Обратите внимание: поскольку (согласно climits.h) тип unsigned long ограничен 4294967295 байтами (4 гигабайта), вам нужно будет найти другой тип переменной, если вы, вероятно, будете иметь дело с файлами большего размера.
Чем это отличается от Ответ Дерека 8-летней давности?
Это неопределенное поведение для двоичного потока, а для текстового потока ftell не возвращает значение, представляющее количество байтов, которые могут быть прочитаны из файла.
Стандарт POSIX имеет свой собственный метод получения размера файла.
Включите заголовок sys/stat.h, чтобы использовать функцию.
Примечание: ограничивает размер 4GB. Если файловая система не Fat32, используйте 64-битную версию!
#include <stdio.h>
#include <sys/stat.h>
int main(int argc, char** argv)
{
struct stat info;
stat(argv[1], &info);
// 'st' is an acronym of 'stat'
printf("%s: size=%ld\n", argv[1], info.st_size);
}
#include <stdio.h>
#include <sys/stat.h>
int main(int argc, char** argv)
{
struct stat64 info;
stat64(argv[1], &info);
// 'st' is an acronym of 'stat'
printf("%s: size=%ld\n", argv[1], info.st_size);
}
ANSI C не предоставляет напрямую способ определения длины файла.
Придется использовать свой разум. А пока воспользуемся методом поиска!
#include <stdio.h>
int main(int argc, char** argv)
{
FILE* fp = fopen(argv[1]);
int f_size;
fseek(fp, 0, SEEK_END);
f_size = ftell(fp);
rewind(fp); // to back to start again
printf("%s: size=%ld", (unsigned long)f_size);
}
If the file is
stdinor a pipe. POSIX, ANSI C won't work.
It will going return0if the file is a pipe orstdin.Opinion: You should use POSIX standard instead. Because, it has 64bit support.
struct _stat64 и __stat64() для _Windows.
Последний пример неверен, fopen принимает два аргумента
У меня есть функция, которая хорошо работает только с stdio.h. Мне он очень нравится, он очень хорошо работает и довольно лаконичен:
size_t fsize(FILE *File) {
size_t FSZ;
fseek(File, 0, 2);
FSZ = ftell(File);
rewind(File);
return FSZ;
}
Вам нужно будет использовать библиотечную функцию для получения сведений о файле. Поскольку C полностью независим от платформы, вам нужно будет сообщить нам, для какой платформы / операционной системы вы разрабатываете!