First off, let me point out that the question, as stated, is a bit of a fool's errand: On platforms where there are files and such, there are well defined ways of accessing this information in the most efficient manner. Given the limited number of environments to which one must generally cater, abstracting away the functionality to simple platform specific functions is the way to go.
So, basically, reading the entire file, and counting bytes along the way is the only universal way so long as the "file" is of finite size.
One can tweak around the edges a bit (say, for a 10GB file, do we really want 10 billion fgetc calls?)
For example, below I used fread to read the file in chunks up to 64K in size:
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
static const size_t SIZE_T_MAX = (size_t) -1;
static const size_t CHUNK_SIZE = 64 * 1024;
int
calc_file_size_slowly(const char *const filename, size_t *size) {
FILE *fp;
int ret = -1;
size_t bytes_read = 0;
unsigned char *buffer = malloc(CHUNK_SIZE);
assert(buffer);
errno = 0;
fp = fopen(filename, "rb");
if (!fp) {
goto FAIL_FOPEN;
}
errno = 0;
*size = 0;
while ((bytes_read = fread(buffer, 1, CHUNK_SIZE, fp)) > 0) {
if (ferror(fp)) {
goto FAIL_FERROR;
}
if ((*size + bytes_read) > *size) {
(*size) += bytes_read;
}
else {
goto FAIL_OVERFLOW;
}
errno = 0;
}
if (feof(fp)) {
ret = 0;
goto DONE;
}
FAIL_FOPEN:
{
ret = errno;
goto DONE;
}
FAIL_FERROR:
{
ret = errno;
fclose(fp);
goto DONE;
}
FAIL_OVERFLOW:
{
ret = EOVERFLOW;
fclose(fp);
goto DONE;
}
DONE:
free(buffer);
return ret;
}
int main(int argc, char *argv[]) {
int i;
for (i = 1; i < argc; i += 1) {
size_t size;
if (calc_file_size_slowly(argv[i], &size) == 0) {
printf("%s: %lu bytes\n", argv[i], size);
}
}
}
Output:
C:\...\Temp> dir wpi.msi
...
2015-05-15 12:12 PM 1,859,584 wpi.msi
...
C:\...\Temp> mysizer wpi.msi
Bytes read=65536
Bytes read=65536
Bytes read=65536
Bytes read=65536
Bytes read=65536
Bytes read=65536
Bytes read=65536
Bytes read=65536
Bytes read=65536
Bytes read=65536
Bytes read=65536
Bytes read=65536
Bytes read=65536
Bytes read=65536
Bytes read=65536
Bytes read=65536
Bytes read=65536
Bytes read=65536
Bytes read=65536
Bytes read=65536
Bytes read=65536
Bytes read=65536
Bytes read=65536
Bytes read=65536
Bytes read=65536
Bytes read=65536
Bytes read=65536
Bytes read=65536
Bytes read=24576
wpi.msi: 1859584 bytes