In plain ISO C, there is only one way to determine the size of a file which is guaranteed to work: To read the entire file from the start, until you encounter end-of-file.
However, this is highly inefficient. If you want a more efficient solution, then you will have to either
- rely on platform-specific behavior, or
- revert to platform-specific functions, such as
stat
on Linux orGetFileSize
on Microsoft Windows.
In contrast to what other answers have suggested, the following code is not guaranteed to work:
fseek( fp, 0, SEEK_END );
long size = ftell( fp );
Even if we assume that the data type long
is large enough to represent the file size (which is questionable on some platforms, most notably Microsoft Windows), the posted code has the following problems:
The posted code is not guaranteed to work on text streams, because according to §7.21.9.4 ¶2 of the ISO C11 standard, the value of the file position indicator returned by ftell
contains unspecified information. Only for binary streams is this value guaranteed to be the number of characters from the beginning of the file. There is no such guarantee for text streams.
The posted code is also not guaranteed to work on binary streams, because according to §7.21.9.2 ¶3 of the ISO C11 standard, binary streams are not required to meaningfully support SEEK_END
.
That being said, on most common platforms, the posted code will work, if we assume that the data type long
is large enough to represent the size of the file.
However, on Microsoft Windows, the characters rn
(carriage return followed by line feed) will be translated to n
for text streams (but not for binary streams), so that the file size you get will count rn
as two bytes, although you are only reading a single character (n
) in text mode. Therefore, the results you get will not be consistent.
On POSIX-based platforms (e.g. Linux), this is not an issue, because on those platforms, there is no difference between text mode and binary mode.
GetFileSize
The GetFileSize function retrieves the size, in bytes, of the specified file.
DWORD GetFileSize(
HANDLE hFile, // handle of file to get size of
LPDWORD lpFileSizeHigh
// pointer to high-order word for file size
);
Parameters
- hFile
- Specifies an open handle of the file whose size is being returned. The handle must have been created with either GENERIC_READ or GENERIC_WRITE access to the file.
- lpFileSizeHigh
- Pointer to the variable where the high-order word of the file size is returned. This parameter can be NULL if the application does not require the high-order word.
Return Values
If the function succeeds, the return value is the low-order doubleword of the file size, and, if lpFileSizeHigh is non-NULL, the function puts the high-order doubleword of the file size into the variable pointed to by that parameter.
If the function fails and lpFileSizeHigh is NULL, the return value is 0xFFFFFFFF. To get extended error information, call GetLastError.
If the function fails and lpFileSizeHigh is non-NULL, the return value is 0xFFFFFFFF and GetLastError will return a value other than NO_ERROR.
Remarks
You cannot use the GetFileSize function with a handle of a nonseeking device such as a pipe or a communications device. To determine the file type for hFile, use the GetFileType function.
The GetFileSize function obtains the uncompressed size of a file. Use the GetCompressedFileSize function to obtain the compressed size of a file.
Note that if the return value is 0xFFFFFFFF and lpFileSizeHigh is non-NULL, an application must call GetLastError to determine whether the function has succeeded or failed. The following sample code illustrates this point:
Code Snippet
// // Case One: calling the function with //
lpFileSizeHigh == NULL
// Try to obtain hFile's size dwSize = GetFileSize (hFile, NULL) ;
// If we failed ...
if (dwSize == 0xFFFFFFFF) {
// Obtain the error code.
dwError = GetLastError() ;
// Deal with that failure.
.
.
.
} // End of error handler
//
// Case Two: calling the function with
//
lpFileSizeHigh != NULL
// Try to obtain hFile's huge size.
dwSizeLow = GetFileSize (hFile, & dwSizeHigh) ;
// If we failed ...
if (dwSizeLow == 0xFFFFFFFF && (dwError = GetLastError()) != NO_ERROR )
{
// Deal with that failure.
.
.
.
}
// End of error handler.
QuickInfo
Windows NT: Requires version 3.1 or later.
Windows: Requires Windows 95 or later.
Windows CE: Requires version 1.0 or later.
Header: Declared in winbase.h.
Import Library: Use kernel32.lib.
Как оказалось, узнать размер файла в языке C — совсем нетривиальная задача. В процессе её решения как минимум вы обязательно столкнетесь с переполнением целочисленного типа данных. В данной статье я приведу 4 способа получения размера файла с использованием функций из стандартной библиотеки C, функций из библиотеки POSIX и функций из библиотек Windows.
Способ 1: решение «в лоб» (скомпилируется везде, но работает очень долго)
Мы просто откроем файл в бинарном режиме и в цикле считаем из него байт за байтом.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
#include <stdio.h> #include <stdlib.h> #include <stdint.h> // для int64_t #include <inttypes.h> // для правильного вывода int64_t в printf int64_t getFileSize(const char* file_name){ int64_t _file_size = 0; FILE* fd = fopen(file_name, «rb»); if(fd == NULL){ _file_size = —1; } else{ while(getc(fd) != EOF) _file_size++; fclose(fd); } return _file_size; } #define FILE_PATH «some_file.txt» int main(){ int64_t file_size = getFileSize(FILE_PATH); printf(«File size: %» PRId64 «n», file_size); return 0; } |
Очевидным недостатком способа является скорость работы. Если у нас файл будет на много гигабайт, то только размер файла будет считаться относительно долго (это сколько байт то надо считать?), а надо же еще остальную программу выполнять.
Достоинство такого способа — работать должен на любой платформе. Ну и конечно можно ускорить процесс за счет считывания бОльшего количества байт.
Способ 2: с использованием функций fseek и ftell (ограничен для объемных файлов и работает не всегда верно)
Данный способ основан на использовании функций стандартной библиотеки C: fseek и ftell. Что происходит — открываем файл в бинарном режиме, перемещаем внутренний указатель положения в файле сразу в конец с помощью fseek, получаем номер последнего байта с помощью ftell.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
#include <stdio.h> #include <stdlib.h> #include <stdint.h> // для int64_t #include <inttypes.h> // для правильного вывода int64_t в printf int64_t getFileSize(const char* file_name){ int64_t _file_size = 0; FILE* fd = fopen(file_name, «rb»); if(fd == NULL){ _file_size = —1; } else{ fseek(fd, 0, SEEK_END); _file_size = ftello(fd); fclose(fd); } return _file_size; } #define FILE_PATH «some_file.txt» int main(){ int64_t file_size = getFileSize(FILE_PATH); printf(«File size: %» PRId64 «n», file_size); return 0; } |
Проблем у данного способа несколько.
Первое — это возвращаемый тип функции ftell. У разных компиляторов на разных платформах по разному. Если у вас 32х битная система, то данный способ будет работать только для файлов, размером меньше 2048 Мб, поскольку максимальное значение для возвращаемого функцией типа long там будет 2147483647. На системах с большей разрядностью будет работать лучше, из-за большего значения максимума для long. Но подобная нестабильность будет мешать. Хотя у меня на 64х битой системе на компиляторе gcc данный способ для файлов больше 8 Гб выводил некорректные значения.
Второе — гарантированность работы fseek и ftell. Коротко говоря, на разных платформах работает по-разному. Где то будет точно возвращать значение положения последнего байта, где то будет возвращать неверное значение. То есть точность данного способа негарантированна.
Плюсом является то, что эти функции из стандартной библиотеки — скомпилируется почти везде.
Стоит сказать, что хитрые инженеры из Microsoft придумали функции _fseeki64 и _ftelli64, которые, как понятно из их названия, работают с int64, что решает проблему с размером файла в MSVC под Windows.
Способ 3: (под Linux (POSIX))
Данный способ основан на использовании системном вызове fstat с использованием специальной структуры struct stat. Как работает: открываем файл через open() или fopen(), вызываем fstat для дескриптора файла (если открыли через fopen, то в fstat надо положить результат fileno от указателя потока FILE), указав на буферную структуру для результатов, и получаем значения поля буферной структуры st_size.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
#include <stdio.h> #include <stdlib.h> #include <stdint.h> // для int64_t #include <inttypes.h> // для правильного вывода int64_t в printf #ifdef __linux__ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #endif int64_t getFileSize(const char* file_name){ int64_t _file_size = 0; struct stat _fileStatbuff; int fd = open(file_name, O_RDONLY); if(fd == —1){ _file_size = —1; } else{ if ((fstat(fd, &_fileStatbuff) != 0) || (!S_ISREG(_fileStatbuff.st_mode))) { _file_size = —1; } else{ _file_size = _fileStatbuff.st_size; } close(fd); } return _file_size; } #define FILE_PATH «some_file.txt» int main(){ int64_t file_size = getFileSize(FILE_PATH); printf(«File size: %» PRId64 «n», file_size); return 0; } |
Гарантированно работает под Linux. Тип поля st_size будет как знаковый int64. Под Windows с использованием Mingw также можно использовать такой способ (с fopen и fileno), но я точно не знаю как там обстоят дела с типом поля структуры st_size.
Способ 4: (под Windows (начиная с Windows XP)):
Еще один способ конкретно под системы Windows с помощью функции GetFileSizeEx, которая доступна в системах, начиная с Windows XP. Для систем постарее используйте GetFileSize (но там снова проблема с максимальным размером файла из-за типа данных).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
#include <stdio.h> #include <stdlib.h> #include <stdint.h> // для int64_t #include <inttypes.h> // для правильного вывода int64_t в printf #ifdef _WIN32 // без этих двух строк не скомпилируется // при использовании функции GetFileSizeEx() #define WINVER 0x0501 #define _WIN32_WINNT WINVER #include <windows.h> #include <sysstat.h> #endif int64_t getFileSize(const char* file_name){ int64_t _file_size = 0; HANDLE hFile; hFile = CreateFile(TEXT(file_name), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); if(hFile == INVALID_HANDLE_VALUE){ _file_size = —1; } else{ LARGE_INTEGER u_winFsz; GetFileSizeEx(hFile, &u_winFsz); CloseHandle(hFile); _file_size = u_winFsz.QuadPart; } return _file_size; } #define FILE_PATH «some_file.txt» int main(){ int64_t file_size = getFileSize(FILE_PATH); printf(«File size: %» PRId64 «n», file_size); return 0; } |
GetFileSizeEx гарантированно работает под Windows. Не работает больше нигде. Тип под размер файла: LONGLONG, который равен размеру знаковому int64. То есть узнаем размер для файлов с максимум 9223372036854775807 байт (до 8589934592 Гб).
Выводы: лучше использовать платформозависимые способы, которые под конкретную систему выдаст гарантированный корректный результат, а не изобретать велосипеды.
Свои варианты оставляйте в комментариях, будет интересно посмотреть!
Функция GetFileSize
извлекает размер указанного файла. Размер
файла, который может быть сообщен при
помощи этой функции ограничивается
значением двойного слова (DWORD).
Чтобы извлечь размер файла, который
является большим, чем значение двойного
слова (DWORD), используйте функцию GetFileSizeEx.
Синтаксис
DWORD GetFileSize( HANDLE hFile, // дескриптор файла LPDWORD lpFileSizeHigh // старшее слово размера файла );
Параметры
hFile
[in] Дескриптор файла, размер
которого должен возвратиться. Этот
дескриптор должен быть создан или с правом
доступа GENERIC_READ или GENERIC_WRITE.
Для получения дополнительной информации,
см. статью Защита файла и права доступа.
lpFileSizeHigh
[out] Указатель на переменную,
в которой возвращается старшее слово
размера файла . Этот параметр может быть
ПУСТО (NULL), если приложению не требуется
старшего слова.
Возвращаемые значения
Если функция завершается
успешно, возвращаемое значение — младшая
часть двойного слова размера файла, и если
параметр lpFileSizeHigh — не ПУСТО (NULL),
функция помещает старшую часть двойного
слова
размера файла в переменную, на которую
указывает этот параметр.
Если функция завершается
ошибкой, и lpFileSizeHigh равен ПУСТО (NULL),
возвращаемое значение — INVALID_FILE_SIZE.
Чтобы получить дополнительные данные об
ошибке, вызовите
GetLastError.
Если функция завершается
ошибкой, и lpFileSizeHigh — не ПУСТО (NULL),
возвращаемое значение — INVALID_FILE_SIZE,
а GetLastError возвратит другое значение, а не
NO_ERROR.
Замечания
Нельзя использовать функцию GetFileSize
с дескриптором не искомого устройства типа канала или
коммуникационного устройства. Чтобы выяснить тип файла для параметра
hFile, используйте функцию
GetFileType.
Функция GetFileSize извлекает
несжатый размер файла. Используйте функцию
GetCompressedFileSize,
чтобы получить сжатый размер файла.
Обратите
внимание! на то, что это, если
возвращаемое значение — INVALID_FILE_SIZE
и параметр lpFileSizeHigh — не ПУСТО (NULL),
приложение должно вызвать GetLastError,
чтобы выяснить, успешно ли завершилась
функция или завершилась ошибкой.
Причина, по которой функция, может
оказаться завершенной ошибкой, состоит в
том, что lpFileSizeHigh может быть не-ПУСТО
(NULL), или размер файла мог быть 0xffffffff. В
этой ситуации, GetLastError возвратит NO_ERROR
после успешного завершения. Нижеследующий типовой код иллюстрирует
этот момент:
Код примера
// Случай первый: вызываемая функция с // lpFileSizeHigh == NULL // Попробуем получить размер hFile. dwSize = GetFileSize (hFile, NULL) ; // Если мы получаем ошибку ... if (dwSize == INVALID_FILE_SIZE) { // Получим код ошибки. dwError = GetLastError() ; // Разберемся с этой ошибкой. . . . } // Закончим обработку ошибки. // // Случай второй: вызываемая функция с // lpFileSizeHigh != NULL // Попробуем получить огромный размер hFile. dwSizeLow = GetFileSize (hFile, & dwSizeHigh) ; // Если мы получаем ошибку ... if (dwSizeLow == INVALID_FILE_SIZE && (dwError = GetLastError()) != NO_ERROR ) { // Разберемся с этой ошибкой. . . . } // Закончим обработку ошибки.
Другой пример, см.
Создание
представления
данных внутри файла.
Смотри также
Обзор Управление файлами, Функции,
используемые в управлении файлами,
GetCompressedFileSize,
GetFileSizeEx,
GetFileType
Размещение
|
||
К |
Windows XP |
Да |
л |
Windows 2000 Professional |
Да |
и |
Windows NT Workstation |
Да |
е |
Windows Me |
Да |
н |
Windows 98 |
Да |
т |
Windows 95
|
Да |
С |
Windows Server 2003 |
Да |
е | Windows 2000 Server |
Да |
р | Windows NT Server |
Да |
в | ||
е | ||
р | ||
Используемая
|
Kernel32.lib |
|
Используемая DLL |
— | |
Заголовочный файл |
||
— объявлено в
|
Winbase.h |
|
— включено в |
Windows.h |
|
Unicode |
Нет |
|
Замечания по платформе |
Не имеется |
In this article, I will discuss two approaches for getting the file size using the C programming language.
Approach 1
When we have to get the file size first approach that comes to our mind is to open the file, seek the cursor to the end of the file, and then get the position of the cursor which is nothing but the size of the file.
Let’s understand how can we achieve this.
- First, open a file using
fopen
. The first argument is the file path and the second argument ismode
and it returns thefile descriptor
. Since we don’t have to modify the file open it in read mode using"r"
. - Now move the cursor to the end of the file using
fseek
which takes the following arguments respectively.-
fd
file descriptor of the file opened. -
offset
how much to offset w.r.t the third argument position. -
whence
from where the cursor should consider moving from.
We have three options for it,SEEK_SET
relative to the start of the file,SEEK_CUR
relative to the current position, andSEEK_END
relative to the end of the file.
-
Since we have to move to the end of the file we take relative to the end of the file and offset it as zero, as we have to move zero from the end. fseek
return -1
if it fails.
- Now use
ftell
to get the current position which takesfd
as an argument and returns the current position which is our file size. On failing it returns-1
.
NOTE: If the cursor move by 1 unit we consider it as 1 byte because the size of
char
is 1 byte andfopen
reads the file character by character only.
Code
#include <stdio.h>
// function get file size
long get_file_size(char *);
int main() {
char *filename = "a.out";
printf(
"Size of file `%s` is %ldn",
filename,
get_file_size(filename)
);
return 0;
}
long get_file_size(char *filename) {
FILE *fp = fopen(filename, "r");
if (fp==NULL)
return -1;
if (fseek(fp, 0, SEEK_END) < 0) {
fclose(fp);
return -1;
}
long size = ftell(fp);
// release the resources when not required
fclose(fp);
return size;
}
Enter fullscreen mode
Exit fullscreen mode
Output
Size of file `a.out` is 51880 bytes
Enter fullscreen mode
Exit fullscreen mode
Approach 2
In this approach, we use stat
API to get the file information which also includes file size.
For this, we simply call the stat
function which takes a file path as the first argument and pointer to the stat struct variable as the second argument and returns -1
on failure.
To get the file size we can simply use the st_size
attribute.
Code
#include <sys/stat.h> // stat
// inherit the above base code here
long get_file_size(char *filename) {
struct stat file_status;
if (stat(filename, &file_status) < 0) {
return -1;
}
return file_status.st_size;
}
Enter fullscreen mode
Exit fullscreen mode
Output
Size of file `a.out` is 51880 bytes
Enter fullscreen mode
Exit fullscreen mode
Using this we can get some other information about a file such as permission, creation time, user id, group id, etc. Also, there are some other functions defined that can be used based on requirements. Check out its man page for more info.
Which one should be used?
The second approach is more recommended because of the following reason.
- It’s fast as we don’t have to open a file which in the first approach has to be done. Some compilers may buffer a file on opening which makes the first approach slower.
- The code is more clear to other developers that we are trying to get file info.
But this code is not portable. As other APIs are developed on OS like windows to get file info.
Whereas the first approach code is portable. As same code works normally without any problem.
So, in conclusion, which strategy we should take is entirely dependent on our requirements.
This article is highly inspired by the content provided by Jacob Sorber on his youtube channel.
❤️Thank you so much for reading this article. I’m a passionate engineering student learning new things so If you find any mistakes or have any suggestions please let me know in the comments.
Also, consider sharing and giving a thumbs up If this post helps you in any way.
C# Get File Size
The Length property of the FileInfo class returns the size of a file in bytes. The following code snippet returns the size of a file. Don’t forget to import System.IO and System.Text namespaces in your project.
- long size = fi.Length;
- Console.WriteLine(«File Size in Bytes: {0}», size);
C# Get File Size Code Example
Here is a complete code example. The following code example uses a FileInfo class to create an object by passing a complete filename. The FileInfo class provides properties to get information about a file such as file name, size, full path, extension, directory name, is read only, when the file was created and last updated.
Note: Make sure to replace the file name with your file name. Also, you can comment //Create a new file code if you already have a file. You may also want to convert the size from bytes to KB, MB, and GB by dividing bytes by 1024, 1024×1024 and so on.
- string fileName = @«C:TempMaheshTXFI.txt»;
- FileInfo fi = new FileInfo(fileName);
- using (FileStream fs = fi.Create())
- {
- Byte[] txt = new UTF8Encoding(true).GetBytes(«New file.»);
- fs.Write(txt, 0, txt.Length);
- Byte[] author = new UTF8Encoding(true).GetBytes(«Author Mahesh Chand»);
- fs.Write(author, 0, author.Length);
- }
- string justFileName = fi.Name;
- Console.WriteLine(«File Name: {0}», justFileName);
- string fullFileName = fi.FullName;
- Console.WriteLine(«File Name: {0}», fullFileName);
- string extn = fi.Extension;
- Console.WriteLine(«File Extension: {0}», extn);
- string directoryName = fi.DirectoryName;
- Console.WriteLine(«Directory Name: {0}», directoryName);
- bool exists = fi.Exists;
- Console.WriteLine(«File Exists: {0}», exists);
- if (fi.Exists)
- {
- long size = fi.Length;
- Console.WriteLine(«File Size in Bytes: {0}», size);
- bool IsReadOnly = fi.IsReadOnly;
- Console.WriteLine(«Is ReadOnly: {0}», IsReadOnly);
- DateTime creationTime = fi.CreationTime;
- Console.WriteLine(«Creation time: {0}», creationTime);
- DateTime accessTime = fi.LastAccessTime;
- Console.WriteLine(«Last access time: {0}», accessTime);
- DateTime updatedTime = fi.LastWriteTime;
- Console.WriteLine(«Last write time: {0}», updatedTime);
- }