Как узнать размер файла c

Обновлено: 21.11.2024

Размер файла
Вам предлагается решить эту задачу в соответствии с описанием задачи, используя любой язык, который вы знаете.

Проверьте размер файла с именем input.txt для файла в текущем рабочем каталоге и другого файла в корне файловой системы.

Содержание

11l [ изменить ]

8086 Сборка [ изменить ]

Эта программа работает под управлением MS-DOS.

Действовать! [править]

DOS 2.5 [править]

DOS 2.5 возвращает размер файла в количестве секторов. Требуется прочитать весь файл, чтобы вычислить его размер в байтах.

Спарта DOS X [ изменить ]

Система Sparta DOS X сохраняет размер файла в каталоге. Считывание значений выполняется с помощью операции XIO 39. В регистрах ICAX3, ICAX4, ICAX5 значения возвращаются в 24-байтовом формате. Расчет по формуле: ICAX3 + ICAX4 * 256 + ICAX5 * 65536.

Ада [ изменить ]

Обратите внимание, что ссылка на корневой каталог, если она есть, зависит от ОС.

Эйм [ изменить ]

АЛГОЛ 68 [править]

Нет встроенного способа определения размера произвольного файла, особенно если файл является специальным каналом, например. магнитофон.

Концептуально процедура

можно использовать для бинарного поиска номера последней страницы. А если известно, что каждая страница имеет одинаковое количество строк, и каждая строка имеет одинаковое количество char[s], а набор символов не сжимаем, то размер можно быстро рассчитать . В противном случае пришлось бы подсчитывать каждую страницу и каждую строку.

Наверное, гораздо проще использовать какую-нибудь библиотеку операционной системы. Эта библиотека не является частью стандартного определения языка ALGOL 68.

Автогорячая клавиша [ изменить ]

АВК [ изменить ]

Некоторые awk не имеют прямого доступа к файловой системе, но могут выполнять системные команды, такие как dir (DOS/Windows) и ls

Топор [ изменить ]

Бекон [ изменить ]

Пакетный файл [ редактировать ]

Выводит размер файла первого параметра (также можно перетаскивать файл).

BBC BASIC [ изменить ]

C [ изменить ]

С++ [править]

Очистить [ изменить ]

Функции для получения размера файла нет, поэтому мы ищем до конца и запрашиваем положение указателя файла.

Clojure [править]

КОБОЛ [ изменить ]

ColdFusion [ изменить ]

Common Lisp [править]

D [ изменить ]

Дельфи [ изменить ]

E [ изменить ]

Эйфель [ изменить ]

Елена [ изменить ]

Эликсир [ изменить ]

Emacs Lisp [править]

Это показывает nil, если такого файла нет, поскольку атрибуты файла в этом случае возвращают nil.

Эрланг [ изменить ]

Эйфория [ изменить ]

Фактор [ изменить ]

FBSL [ изменить ]

FileLen возвращает -1, если файл не найден. FileLen также принимает дескриптор файла и указывает длину открытого файла.

Четвёртый [ изменить ]

Фортран [править]

Начиная с Fortran 95 размер стандартных внешних файлов можно определить просто с помощью INQUIRE(SIZE=. ). Следующий предыдущий пример относится к FORTRAN 77 и теперь заменен.

Исходный пример устарел .

Увы, несмотря на наличие инструкции INQUIRE(FILE="Input.txt",EXIST = ISTHERE, RECL = RL, etc.), посредством которой логическая переменная ISTHERE имеет значение (выход: присвоено слева направо) в зависимости от того, существует ли именованный файл (ввод: назначение справа налево) или нет, а параметр RECL возвращает максимально допустимую длину записи для файла, параметр, сообщающий о количестве записей, отсутствует. находятся в файле, так что размер файла остается неизвестным. Кроме того, значение, возвращаемое RECL, не обязательно связано с самим файлом, но, вероятно, является стандартным значением, таким как 132, значение по умолчанию, используемое при выборе длины переноса строки при выводе в произвольном формате, как в WRITE (6,* ) вещи, но не обязательно являющиеся ограничением на длину записываемой или читаемой строки.

Кроме того, в мире ASCII текстовые файлы часто реализуются как записи переменной длины со специальными символами, встроенными в качестве границ записи, обычно одним из CR, CRLF, LFCR или LF. Без знания того, что используется, объем памяти, занимаемый ими, будет неизвестен. Другие файловые системы могут предлагать разные типы дисковых файлов с записями фиксированного размера или с записями переменной длины со счетчиком длины записи, но это не является стандартом для всех компьютеров.

Другими словами, Fortran не определяет связь с файловой системой, посредством которой эти детали могут быть раскрыты, и в любом случае не все файловые системы поддерживают их.

Но если кто-то писал Fortran для системы B6700, его компилятор F77 предлагал дополнительные атрибуты, которые можно было вернуть с помощью оператора INQUIRE: MAXRECSIZE действительно был длиной самой длинной записи в дисковом файле (независимо от того, была ли фиксированная длина записи или переменная длина записи). ), BLOCKSIZE сообщил количество записей на блок дискового пространства, AREASIZE размер области выделения дискового пространства и AREAS их количество, в то время как KIND показывает кодовый номер типа файла (не через суффикс .txt или что-то еще) . Имея эти значения, можно определить размер файла в битах, байтах, словах (шесть символов/слово), записях, блоках и областях.

Эти средства не были перенесены в стандартизированный Fortran 90 и т. д. Таким образом, приходится разрабатывать подпрограмму, которая считывает все записи дискового файла, считая их длину. Это просто, но утомительно, как в следующем фрагменте:

Подпрограмма LONGCOUNT использует два 32-битных целых числа (первый параметр представляет собой двухэлементный массив), чтобы обеспечить гораздо большую емкость, учитывая современные возможности размера файла, но в этом нет необходимости, если доступны переменные INTEGER*8. Подсчет не будет включать какой-либо вклад от разделителей записей, таких как CR и т. Д. Файл, который более правильно рассматривать как содержащий двоичные данные (скажем, целые числа или значения с плавающей запятой), случайно будет иметь битовый шаблон CR или LF здесь и там, и они будут восприняты как пометка разделения записи при чтении файла как ФОРМАТИРОВАННОГО, что является настройкой по умолчанию.

Как узнать размер файла, который я открыл в приложении, написанном на C? Я хотел бы знать размер, потому что я хочу поместить содержимое загруженного файла в строку, которую я выделяю с помощью malloc() . Просто напишите malloc(10000*sizeof(char)); ИМХО плохая идея.

Да, но компилятор какой-то эзотерической платформы может определить char как 2 байта - тогда программа выделяет больше, чем необходимо. Никогда нельзя быть слишком уверенным.

@George "компилятор эзотерической платформы", где sizeof(char) != 1 не является настоящим компилятором C. Даже если символ 32-битный, он все равно вернет 1.

На самом деле я предпочитаю malloc(x*sizeof(char)); к malloc(x); при размещении x символов. Да, они всегда компилируются в одно и то же, но мне нравится согласованность с другим распределением памяти.

8 ответов 8

Вам нужно перейти к концу файла, а затем запросить позицию:

Затем вы можете вернуться, например:

или (если нужно перейти в начало)

@camh - Спасибо, чувак. Этот комментарий решил мою проблему с алгоритмом изменения размера файла. Для справки: можно открыть файл в двоичном режиме, поставив «b» в конце строки режима fopen.

Возвращает целое число со знаком, поэтому ограничено 2 ГБ. Но с другой стороны, ваш файл может иметь отрицательную длину 2 миллиарда байт, и они готовы к этому.

Из документации fseek: «Реализации библиотек могут не поддерживать SEEK_END (поэтому код, использующий его, не имеет реальной стандартной переносимости)».

Использование стандартной библиотеки:

Предполагая, что ваша реализация поддерживает SEEK_END:

Линукс/POSIX:

Вы можете использовать stat (если вы знаете имя файла) или fstat (если у вас есть дескриптор файла).

Вот пример статистики:

Win32:

Если у вас есть дескриптор файла, функция fstat() возвращает структуру статистики, содержащую размер файла.

Добавить "fd = fileno(f);" если у вас есть поток (например, из fopen), а не файловый дескриптор. Требуется проверка ошибок.

это, на мой взгляд, лучший реальный ответ, и я думаю, что у всех нас отключены тренировочные колеса по большей части в C, действительно ли нам нужна проверка ошибок и другой ненужный код в наших примерах, это достаточно плохо M$DN делает это у них, давайте не будем следовать их примеру, вместо этого просто скажем в конце «обязательно добавьте проверку ошибок» и покончим с этим.

МНОГИЕ пользователи SO изучают C, а не являются его прошлыми мастерами. Поэтому код, приведенный в ответах, должен показывать проверку ошибок, чтобы учащийся научился правильно кодировать.

Есть деталь, что (f)stat() возвращает общее количество байтов, выделенных для блока, в то время как последовательность fseek() / ftell() возвращает количество байтов до того, как встретится EOF.

В итоге я просто сделал короткую и удобную функцию fsize(обратите внимание, без проверки ошибок)

Это немного глупо, что в стандартной библиотеке C нет такой функции, но я понимаю, почему это будет сложно, поскольку не каждый "файл" имеет размер (например, /dev/null )

Как использовать lseek/fseek/stat/fstat для получения размера файла?

К сожалению, ftell возвращает длинное значение. Вам нужно, чтобы ftello возвращал off_t . (Или, по-видимому, в Windows, _ftelli64() , потому что, похоже, им нравится усложнять написание переносимого кода.) См. обсуждение другого ответа

fstat имеет смысл, только если у вас уже есть открытый файл или как часть процесса его открытия.Ваш fstat_filesize - это не то, что вы когда-либо захотите использовать в этой форме, только если вы действительно собираетесь хранить этот fd и читать из него или что-то в этом роде. open/fstat/close имеет нулевое преимущество перед stat; Я бы написал эту функцию для получения ФАЙЛА *fp (используйте fileno() ) или int fd . Я предполагаю, что ваши функции не предназначены для использования как есть, потому что они только печатают результаты, а не возвращают их.

Помимо дизайна fstat_filesize, да, это полезный пример проверки ошибок. За исключением того, что вы должны fprintf(stderr, . с вашими сообщениями об ошибках. А в функциях, использующих статистику POSIX и друзей, вы должны использовать strerror как часть этого, чтобы получить реальную причину сбоя, например «нет такого файла или каталога» для ENOENT или "Отказано в доступе" для EPERM. Это гораздо более полезный и стандартный способ сообщить об ошибках в программах Unix (системный вызов и имя файла лучше, чем ничего, пользователь может не думать о разрешениях, если вы им не сообщите .)

Обычно размеры файлов сохраняются автоматически. Файл начинается с размера 0 и автоматически расширяется, когда данные записываются за его конец. Также можно полностью очистить файл с помощью вызова open или fopen.

Однако иногда необходимо уменьшить размер файла. Это можно сделать с помощью функций truncate и ftruncate. Они были представлены в BSD Unix. Позднее ftruncate был добавлен в POSIX.1.

Некоторые системы позволяют расширять файл (создавая отверстия) с помощью этих функций. Это полезно при использовании ввода-вывода с отображением памяти (см. Ввод-вывод с отображением памяти), когда файлы не расширяются автоматически. Однако он не является переносимым, но должен быть реализован, если mmap позволяет отображать файлы (т. е. определено _POSIX_MAPPED_FILES).

Использование этих функций для чего-либо, кроме обычного файла, приводит к неопределенным результатам. Во многих системах такой вызов будет казаться успешным, но на самом деле ничего не делает.

Функция: int усечь (const char * имя файла, off_t длина)

Предварительно: | МТ-Сейф | AS-безопасный | AC-безопасный | См. раздел «Концепции безопасности POSIX».

Функция усечения изменяет размер имени файла на длину. Если длина меньше предыдущей длины, данные в конце будут потеряны. Для выполнения этой операции файл должен быть доступен для записи пользователем.

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

Когда исходный файл скомпилирован с _FILE_OFFSET_BITS == 64, функция truncate на самом деле является truncate64, а тип off_t имеет 64 бита, что позволяет обрабатывать файлы длиной до 2^63 байт.

В случае успеха возвращается значение 0 или -1 в случае ошибки. В дополнение к обычным ошибкам имени файла могут возникнуть следующие ошибки:

Файл является каталогом или недоступен для записи.

длина отрицательна.

Эта операция расширит файл за пределы операционной системы.

Произошла аппаратная ошибка ввода-вывода.

Файл доступен только для добавления или неизменяем.

Операция была прервана сигналом.

Функция: int truncate64 (const char * name , off64_t length )

Предварительно: | МТ-Сейф | AS-безопасный | AC-безопасный | См. раздел «Концепции безопасности POSIX».

Эта функция аналогична функции усечения. Разница в том, что аргумент длины имеет ширину 64 бита даже на 32-битных машинах, что позволяет обрабатывать файлы размером до 2^63 байт.

Когда исходный файл скомпилирован с _FILE_OFFSET_BITS == 64 на 32-битной машине, эта функция фактически доступна под именем truncate и таким образом прозрачно заменяет 32-битный интерфейс.

Функция: int ftruncate (int fd , off_t length )

Предварительно: | МТ-Сейф | AS-безопасный | AC-безопасный | См. раздел «Концепции безопасности POSIX».

Это похоже на truncate , но для идентификации объекта работает с файловым дескриптором fd для открытого файла, а не с именем файла. Для успешного выполнения операции файл должен быть открыт для записи.

Стандарт POSIX определяет реализацию того, что произойдет, если указанная новая длина файла больше, чем исходный размер. Функция ftruncate может просто оставить файл в покое и ничего не делать или может увеличить его размер до желаемого размера. В этом последнем случае расширенная область должна быть заполнена нулями. Таким образом, использование ftruncate не является надежным способом увеличения размера файла, но если это возможно, то это, вероятно, самый быстрый способ. Эта функция также работает с сегментами общей памяти POSIX, если они реализованы системой.

ftruncate особенно полезен в сочетании с mmap. Поскольку отображаемая область должна иметь фиксированный размер, нельзя увеличить файл, написав что-то за пределами последней отображаемой страницы. Вместо этого нужно увеличить сам файл, а затем переназначить файл с новым размером. Пример ниже показывает, как это работает.

Когда исходный файл скомпилирован с _FILE_OFFSET_BITS == 64, функция ftruncate на самом деле является ftruncate64, а тип off_t имеет 64 бита, что позволяет обрабатывать файлы длиной до 2^63 байт.

В случае успеха возвращается значение 0 или -1 в случае ошибки. Могут возникнуть следующие ошибки:

fd не соответствует открытому файлу.

fd является каталогом или не открыт для записи.

длина отрицательна.

Эта операция расширит файл за пределы операционной системы.

Произошла аппаратная ошибка ввода-вывода.

Файл доступен только для добавления или неизменяем.

Операция была прервана сигналом.

Функция: int ftruncate64 (int id , длина off64_t )

Предварительно: | МТ-Сейф | AS-безопасный | AC-безопасный | См. раздел «Концепции безопасности POSIX».

Эта функция аналогична функции ftruncate. Разница в том, что аргумент длины имеет ширину 64 бита даже на 32-битных машинах, что позволяет обрабатывать файлы размером до 2^63 байт.

Когда исходный файл скомпилирован с _FILE_OFFSET_BITS == 64 на 32-битной машине, эта функция фактически доступна под именем ftruncate и таким образом прозрачно заменяет 32-битный интерфейс.

Как было объявлено, здесь представлен небольшой пример использования ftruncate в сочетании с mmap:

Функция add записывает блок памяти в произвольное место в файле. Если текущий размер файла слишком мал, он расширяется. Обратите внимание, что он расширен на целое число страниц. Это требование mmap . Программа должна отслеживать реальный размер файла, и когда она закончит работу, последний вызов ftruncate должен установить реальный размер файла.

До C++17 мы часто могли жаловаться, что даже такие простые задачи, как получение размера файла, были сложными. С std::filesystem все становится немного проще!

Получить размер файла

STL до C++17 не содержала прямых средств для работы с файловой системой. Мы могли использовать только сторонние библиотеки (например, Boost) или системные API.

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

Вот код, использующий потоковую библиотеку:

Другим вариантом было также открыть файл в режиме добавления ( std::ios::ate ), и тогда не нужно было перемещать указатель файла, поскольку он автоматически располагался в конце. В Windows вы также можете использовать GetFileSizeEx или FindFirstFileEx (как указано в комментарии Артема Р.):

Я не изучил все возможные варианты, поэтому дайте мне знать, как вы можете получить размер файла.

Как насчет C++17? Есть ли шанс получить более простой код и, возможно, переносимый?

Сериал

Эта статья является частью моей серии статей о библиотечных утилитах C++17. Вот список тем серии:

Ресурсы по C++17 STL:

    от Бартека! Николай Йосуттис, Кейт Грегори, Джованни Диканио, Яцек Галович
Размер файла с std::filesystem

C++17 предлагает std::filesystem, которая упрощает выполнение многих задач с файлами и каталогами. Вы можете не только быстро получить размер файла, его атрибуты, но и создавать новые каталоги, перебирать файлы, работать с объектами пути.

Новая библиотека дает нам две функции, которые мы можем использовать:

  • std::uintmax_t std::filesystem::file_size( const std::filesystem::path& p );
  • std::uintmax_t std::filesystem::directory_entry::file_size() const;

Первая функция — это свободная функция в std::filesystem , вторая — это метод в directory_entry .

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

Например, мы можем получить размер файла с помощью следующего кода:

Или версия с error_codes :

Вы можете спросить, почему у нас есть два метода — как свободная функция и как метод.

Причина в том, что directory_entry кэширует атрибуты файлов. Вот почему, если вы перебираете каталог или обращаетесь к файлу несколько раз, кэширование может повысить производительность.

Если файл или каталог, на который указывает directory_entry, изменяется, вам нужно вызвать метод directory_entry::refresh() для обновления кеша, иначе вы можете получить «старые» значения для ваших запросов.

Вы можете поиграть с кодом в этом интерактивном образце:

(Вот также код в Coliru).

Резюме

В этом коротком посте вы увидели, как использовать функцию file_size из std::filesystem. Я призываю вас изучить это новое и мощное дополнение к C++17. Если вы работаете с файлами и каталогами, это может сделать ваш код более удобным и переносимым.

См. следующую статью из серии, в которой я обсуждаю права доступа к файлам и производительность file_size : преимущества и различия std:filesystem::file_size

Читайте также: