Как я могу узнать размер файла, который я открыл с помощью приложения, написанного на C? Я хотел бы знать размер, потому что я хочу поместить содержимое загруженного файла в строку, которую я выделяю с помощью malloc()
. Просто писать malloc(10000*sizeof(char));
- ИМХО плохая идея.
Как я могу получить размер файла на C?
Ответы (8)
Вам нужно перейти к концу файла, а затем запросить позицию:
fseek(fp, 0L, SEEK_END);
sz = ftell(fp);
Затем вы можете вернуться, например:
fseek(fp, 0L, SEEK_SET);
или (если хотите перейти к началу)
rewind(fp);
rewind
, прежде чем люди забудут, что это значит
- person bobobobo; 23.09.2011
fseek(fp, 0L, SEEK_END);
в двоичном потоке не является строго совместимым переносимым кодом C. Согласно сноске 268 стандарта C: Настройка индикатор положения файла до конца файла, как и в случае с fseek (file, 0, SEEK_END), имеет неопределенное поведение для двоичного потока ... и _ 2_ в текстовом потоке не будет работать: Для текстового потока индикатор положения файла содержит неопределенная информация ... необязательно значимая мера количества написанных или прочитанных символов.
- person Andrew Henle; 04.05.2018
lseek()
вместо fseek()
? На странице руководства, на которую я ссылаюсь, говорится: «После успешного завершения fgetpos()
, fseek()
, fsetpos()
вернут 0.
- person tomlogic; 14.04.2020
fseek
. Действительно, на странице руководства для fseek
указано, что он вернет 0, а lseek
вернет смещение. Кроме того, возвращаясь к коду, в котором я сам использовал эту технику для определения размера файла, я действительно использовал lseek
, а не fseek
.
- person Micheal Johnson; 03.05.2020
FILE*
дескриптор файла, а другая - int
дескриптор файла. Это, как правило, не имеет значения в Linux (если вы согласны с тем, какие функции вы используете, например fopen
против open
), но у меня были проблемы с переносом программного обеспечения на другие платформы, где функции FILE*
поддерживаются, а функции int
поддерживаются. нет. Я не знаю подробностей, стоящих за этим, но я предполагаю, что один - это стандарт C, а другой - расширение Linux (или POSIX? Но я думал, что POSIX поддерживается в Windows).
- person Micheal Johnson; 03.05.2020
fopen()
находится в стандартной библиотеке C, а open
- из POSIX. stackoverflow.com/a/1658517/266392 отлично справляется с обсуждением различий.
- person tomlogic; 05.05.2020
lseek
? Я тестировал его, не добавляя ни одного, и он по-прежнему равен результату stat
. Ага, убирать устаревшие комментарии - мое хобби :)
- person mathway; 14.06.2021
Используя стандартную библиотеку:
Предполагая, что ваша реализация значимо поддерживает SEEK_END:
fseek(f, 0, SEEK_END); // seek to end of file
size = ftell(f); // get current file pointer
fseek(f, 0, SEEK_SET); // seek back to beginning of file
// proceed with allocating memory and reading the file
Linux / POSIX:
Вы можете использовать stat
(если вы знаете имя файла) или fstat
(если у вас есть дескриптор файла).
Вот пример для stat:
#include <sys/stat.h>
struct stat st;
stat(filename, &st);
size = st.st_size;
Win32:
Вы можете использовать GetFileSize или GetFileSizeEx.
FILE*
с помощью fileno
.
- person poolie; 01.05.2016
stat()
завершится ошибкой, и никоим образом не ясно, что поле st_size
структуры st
не содержит мусора стека. По крайней мере, если stat()
не удается, доставленный размер должен быть 0. И вы можете включить проверку ошибок, даже не изменяя количество строк в примере: size = (stat(filename, &st) == 0) ? st.st_size : 0;
.
- person jsbox; 18.11.2019
sys/stat.h
также доступен в Windows (по крайней мере, для меня в Visual Studio 2019).
- person Julian Kirsch; 02.04.2020
Если у вас есть дескриптор файла, fstat()
возвращает структуру статистики, которая содержит размер файла.
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
// fd = fileno(f); //if you have a stream (e.g. from fopen), not a file descriptor.
struct stat buf;
fstat(fd, &buf);
off_t size = buf.st_size;
В итоге я просто сделал короткую и приятную fsize
функцию (примечание, без проверки ошибок)
int fsize(FILE *fp){
int prev=ftell(fp);
fseek(fp, 0L, SEEK_END);
int sz=ftell(fp);
fseek(fp,prev,SEEK_SET); //go back to where we were
return sz;
}
Глупо, что стандартная библиотека C не имеет такой функции, но я понимаю, почему это может быть сложно, поскольку не каждый "файл" имеет размер (например, /dev/null
)
ftell(fp)
возвращает long
. Не нужно, чтобы можно было замкнуть на int
и потерять информацию.
- person chux - Reinstate Monica; 20.03.2021
Как использовать lseek / fseek / stat / fstat, чтобы получить размер файла?
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
void
fseek_filesize(const char *filename)
{
FILE *fp = NULL;
long off;
fp = fopen(filename, "r");
if (fp == NULL)
{
printf("failed to fopen %s\n", filename);
exit(EXIT_FAILURE);
}
if (fseek(fp, 0, SEEK_END) == -1)
{
printf("failed to fseek %s\n", filename);
exit(EXIT_FAILURE);
}
off = ftell(fp);
if (off == -1)
{
printf("failed to ftell %s\n", filename);
exit(EXIT_FAILURE);
}
printf("[*] fseek_filesize - file: %s, size: %ld\n", filename, off);
if (fclose(fp) != 0)
{
printf("failed to fclose %s\n", filename);
exit(EXIT_FAILURE);
}
}
void
fstat_filesize(const char *filename)
{
int fd;
struct stat statbuf;
fd = open(filename, O_RDONLY, S_IRUSR | S_IRGRP);
if (fd == -1)
{
printf("failed to open %s\n", filename);
exit(EXIT_FAILURE);
}
if (fstat(fd, &statbuf) == -1)
{
printf("failed to fstat %s\n", filename);
exit(EXIT_FAILURE);
}
printf("[*] fstat_filesize - file: %s, size: %lld\n", filename, statbuf.st_size);
if (close(fd) == -1)
{
printf("failed to fclose %s\n", filename);
exit(EXIT_FAILURE);
}
}
void
stat_filesize(const char *filename)
{
struct stat statbuf;
if (stat(filename, &statbuf) == -1)
{
printf("failed to stat %s\n", filename);
exit(EXIT_FAILURE);
}
printf("[*] stat_filesize - file: %s, size: %lld\n", filename, statbuf.st_size);
}
void
seek_filesize(const char *filename)
{
int fd;
off_t off;
if (filename == NULL)
{
printf("invalid filename\n");
exit(EXIT_FAILURE);
}
fd = open(filename, O_RDONLY, S_IRUSR | S_IRGRP);
if (fd == -1)
{
printf("failed to open %s\n", filename);
exit(EXIT_FAILURE);
}
off = lseek(fd, 0, SEEK_END);
if (off == -1)
{
printf("failed to lseek %s\n", filename);
exit(EXIT_FAILURE);
}
printf("[*] seek_filesize - file: %s, size: %lld\n", filename, (long long) off);
if (close(fd) == -1)
{
printf("failed to close %s\n", filename);
exit(EXIT_FAILURE);
}
}
int
main(int argc, const char *argv[])
{
int i;
if (argc < 2)
{
printf("%s <file1> <file2>...\n", argv[0]);
exit(0);
}
for(i = 1; i < argc; i++)
{
seek_filesize(argv[i]);
stat_filesize(argv[i]);
fstat_filesize(argv[i]);
fseek_filesize(argv[i]);
}
return 0;
}
if(off == (-1L))
не требуется (long)
- person Imobilis; 01.06.2018
Думали ли вы, что не нужно рассчитывать размер файла и при необходимости просто увеличивать массив? Вот пример (без проверки ошибок):
#define CHUNK 1024
/* Read the contents of a file into a buffer. Return the size of the file
* and set buf to point to a buffer allocated with malloc that contains
* the file contents.
*/
int read_file(FILE *fp, char **buf)
{
int n, np;
char *b, *b2;
n = CHUNK;
np = n;
b = malloc(sizeof(char)*n);
while ((r = fread(b, sizeof(char), CHUNK, fp)) > 0) {
n += r;
if (np - n < CHUNK) {
np *= 2; // buffer is too small, the next read could overflow!
b2 = malloc(np*sizeof(char));
memcpy(b2, b, n * sizeof(char));
free(b);
b = b2;
}
}
*buf = b;
return n;
}
Это имеет то преимущество, что работает даже с потоками, в которых невозможно получить размер файла (например, stdin).
realloc
вместо использования промежуточного указателя и необходимости free()
.
- person Victor Zamanian; 13.03.2011
np += (np / 2) + (np / 4);
- все целые, промежуточные результаты не выходят за рамки преждевременного переполнения. Скорее я бы использовал 1.5, но 1.75 лучше показывает идею. Конечно, следите за переполнением, и, в частности, любое кратное предыдущему размеру может переполниться, когда фактический размер этого не делает. Если размер вашего файла (2^31)-1
, вероятно, будет предпринята попытка выделить буфер с -(2^31)
, а не с 2^31
байтами.
- person Steve314; 13.11.2016
np += (np / 2) + (np / 4)
не дает точного умножения на 1,75 - результаты могут быть слишком маленькими, потому что от битов, которые были усечены, не распространяется перенос, - но для этой цели этого должно быть достаточно. Для умножения на 1,5 должно быть правильно np += (np / 2);
.
- person Steve314; 13.11.2016
Если вы работаете в Linux, серьезно подумайте об использовании g_file_get_contents из glib. Он обрабатывает весь код для загрузки файла, выделения памяти и обработки ошибок.
#include <stdio.h>
#define MAXNUMBER 1024
int main()
{
int i;
char a[MAXNUMBER];
FILE *fp = popen("du -b /bin/bash", "r");
while((a[i++] = getc(fp))!= 9)
;
a[i] ='\0';
printf(" a is %s\n", a);
pclose(fp);
return 0;
}
HTH
sizeof(char)==1
. См., Например, parashift.com/c++-faq-lite/ intrinsic-types.html # faq-26.1 - person sleske   schedule 08.02.2011malloc(x*sizeof(char));
malloc(x);
при выделении x символов. Да, они всегда компилируются в одно и то же, но мне нравится согласованность с другими выделениями памяти. - person moltenform   schedule 16.04.2011p = malloc(N * sizeof (*p))
- не кодируйте жестко тип, при котором компилятор не может проверить это за вас. - person Bernd Jendrissek   schedule 19.01.2014fstat
сfileno
, если у вас естьFILE*
:fstat(fileno(f), &stat)
- person sshilovsky   schedule 16.02.2014