C/C++ でファイルサイズ取得

C/C++ を使用して、ファイルサイズを取得する方法の備忘録。

// g++ getFileSize.cpp -lboost_system-mt -lboost_filesystem-mt

#define CAN_CUST_FPOS_TO_LONG 0

#include <stdio.h>
#if CAN_CUST_FPOS_TO_LONG
unsigend long getFileSize1(const char *fileName) {
	fpos_t fsize;
	FILE *fp = fopen(fileName, "rb"); 
	fseek(fp, 0, SEEK_END); 
	fgetpos(fp, &fsize); 
	fclose(fp);
	return (unsigend long) fsize;
}
#endif

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
unsigned long getFileSize2(const char *fileName) {
	int fd = open(fileName, O_RDONLY);
	struct stat statBuf;
	fstat(fd, &statBuf);
	close(fd);
	return (unsigned long) statBuf.st_size;
}

#include <boost/filesystem.hpp>
unsigned long getFileSize3(const char *fileName) {
	const boost::filesystem::path path(fileName);
	const boost::uintmax_t size = boost::filesystem::file_size(path);
	return (unsigned long) size;
}

int main(int argc, char *argv[]) {
#if CAN_CUST_FPOS_TO_LONG
	unsigned long size1 = getFileSize1("getFileSize.cpp");
#else
	unsigned long size1 = 0;
#endif
	unsigned long size2 = getFileSize2("getFileSize.cpp");
	unsigned long size3 = getFileSize3("getFileSize.cpp");
	printf("%ld\n", size1);
	printf("%ld\n", size2);
	printf("%ld\n", size3);

	return 0;
}

getFileSize1 は ANSI C で実装可能なんだけど、処理系によって fpos_t の型がまちまちなので、この方法はあまりよろしくない。1 バイトずつシークして数える方法もあるにはあるけど、考えただけでも遅そうなので却下。

getFileSize2 は POSIX な環境なら割と良い方法だと思う。st_size の型がなにかというのがいまいちはっきりしないんだけど、多分 long にキャスト可能。

getFileSize3 は boost を使用するポータブルな方法。Windows でもそのまま動かせるのが強み。C++ が必須になるのと、boost を導入しなければならないのがデメリット。boost::uintmax_t は環境によって uint32_t、uint64_t、unsigned long、unsigned __int64 などと異なる。簡単のためにキャストしているが、実際にはそのままこの型を使えば良いと思う。


この例では省略してるけど、 1 は fp が NULL に、2 は fd が -1 に、3 は boost::filesystem::filesystem_error が throw される可能性があるので、それぞれエラーチェックを行う必要がある。