在 C 中获取文件大小的正确方法
Proper way to get file size in C
我正在处理套接字编程中的作业,其中我必须在 sparc 和 linux 机器之间发送文件。在以字符流发送文件之前,我必须获取文件大小并告诉客户端。以下是我尝试获取尺寸的一些方法,但我不确定哪种方法合适。
出于测试目的,我创建了一个内容为“test”的文件 (space + (string)test)
方法 1 - 使用 fseeko() 和 ftello()
这是我在https://www.securecoding.cert.org/confluence/display/c/FIO19-C.+Do+not+use+fseek()+and+ftell()+to+compute+the+size+of+a+regular+file上找到的方法
虽然 fssek() 有 "Setting the file position indicator to end-of-file, as with fseek(file, 0, SEEK_END), has undefined behavior for a binary stream" 的问题,但据说 fseeko() 已经解决了这个问题,但它只适用于 POSIX 系统(这很好,因为我使用的环境是 sparc 和 linux)
fd = open(file_path, O_RDONLY);
fp = fopen(file_path, "rb");
/* Ensure that the file is a regular file */
if ((fstat(fd, &st) != 0) || (!S_ISREG(st.st_mode))) {
/* Handle error */
}
if (fseeko(fp, 0 , SEEK_END) != 0) {
/* Handle error */
}
file_size = ftello(fp);
fseeko(fp, 0, SEEK_SET);
printf("file size %zu\n", file_size);
此方法效果很好,可以正确获取尺寸。但是,它仅限于常规文件。我试过google这个词"regular file",但我还是没有完全理解它。而且我不知道这个功能对我的项目是否可靠。
方法 2 - 使用 strlen()
由于最大。我项目中的一个文件大小是 4MB,所以我可以调用一个 4MB 的缓冲区。之后,文件被读入缓冲区,我尝试使用 strlen 来获取文件大小(或更准确地说是内容的长度)。由于 strlen() 是可移植的,我可以改用这种方法吗?代码片段是这样的
fp = fopen(file_path, "rb");
fread(file_buffer, 1024*1024*4, 1, fp);
printf("strlen %zu\n", strlen(file_buffer));
这个方法也行 returns
strlen 8
但是网上没看到有类似的方法使用这种方法。所以我在想,也许我错过了什么,或者这种方法有一些我没有意识到的局限性。
常规文件意味着它没有像设备、套接字、管道等那样特殊,而是 "normal" 文件。
看来根据您在发送之前的任务描述,您必须检索普通文件的大小。
所以你的方法是对的:
FILE* fp = fopen(...);
if(fp) {
fseek(fp, 0 , SEEK_END);
long fileSize = ftell(fp);
fseek(fp, 0 , SEEK_SET);// needed for next read from beginning of file
...
fclose(fp);
}
但您无需打开文件即可完成:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
struct stat buffer;
int status;
status = stat("path to file", &buffer);
if(status == 0) {
// size of file is in member buffer.st_size;
}
OP 可以像 "max. size of a file in my project is 4MB".
一样 easy 来做到这一点
不使用 strlen()
,而是使用 fread()
中的 return 值。 stlen()
在第一个空字符处停止,因此可能会报告一个太小的值。 另外我们不知道读取的数据中是否包含空字符,所以它可能不是字符串。如果代码需要将数据用作字符串,则附加一个空字符(并分配 +1)。但在那种情况下,我希望文件需要以文本模式打开。
请注意,许多 OS 在写入之前甚至不使用分配的内存。
Why is malloc not "using up" the memory on my computer?
fp = fopen(file_path, "rb");
if (fp) {
#define MAX_FILE_SIZE 4194304
char *buf = malloc(MAX_FILE_SIZE);
if (buf) {
size_t numread = fread(buf, sizeof *buf, MAX_FILE_SIZE, fp);
// shrink if desired
char *tmp = realloc(buf, numread);
if (tmp) {
buf = tmp;
// Use buf with numread char
}
free(buf);
}
fclose(fp);
}
注意:将整个文件读入内存可能不是最好的开始。
我正在处理套接字编程中的作业,其中我必须在 sparc 和 linux 机器之间发送文件。在以字符流发送文件之前,我必须获取文件大小并告诉客户端。以下是我尝试获取尺寸的一些方法,但我不确定哪种方法合适。
出于测试目的,我创建了一个内容为“test”的文件 (space + (string)test)
方法 1 - 使用 fseeko() 和 ftello()
这是我在https://www.securecoding.cert.org/confluence/display/c/FIO19-C.+Do+not+use+fseek()+and+ftell()+to+compute+the+size+of+a+regular+file上找到的方法 虽然 fssek() 有 "Setting the file position indicator to end-of-file, as with fseek(file, 0, SEEK_END), has undefined behavior for a binary stream" 的问题,但据说 fseeko() 已经解决了这个问题,但它只适用于 POSIX 系统(这很好,因为我使用的环境是 sparc 和 linux)
fd = open(file_path, O_RDONLY);
fp = fopen(file_path, "rb");
/* Ensure that the file is a regular file */
if ((fstat(fd, &st) != 0) || (!S_ISREG(st.st_mode))) {
/* Handle error */
}
if (fseeko(fp, 0 , SEEK_END) != 0) {
/* Handle error */
}
file_size = ftello(fp);
fseeko(fp, 0, SEEK_SET);
printf("file size %zu\n", file_size);
此方法效果很好,可以正确获取尺寸。但是,它仅限于常规文件。我试过google这个词"regular file",但我还是没有完全理解它。而且我不知道这个功能对我的项目是否可靠。
方法 2 - 使用 strlen()
由于最大。我项目中的一个文件大小是 4MB,所以我可以调用一个 4MB 的缓冲区。之后,文件被读入缓冲区,我尝试使用 strlen 来获取文件大小(或更准确地说是内容的长度)。由于 strlen() 是可移植的,我可以改用这种方法吗?代码片段是这样的
fp = fopen(file_path, "rb");
fread(file_buffer, 1024*1024*4, 1, fp);
printf("strlen %zu\n", strlen(file_buffer));
这个方法也行 returns
strlen 8
但是网上没看到有类似的方法使用这种方法。所以我在想,也许我错过了什么,或者这种方法有一些我没有意识到的局限性。
常规文件意味着它没有像设备、套接字、管道等那样特殊,而是 "normal" 文件。 看来根据您在发送之前的任务描述,您必须检索普通文件的大小。 所以你的方法是对的:
FILE* fp = fopen(...);
if(fp) {
fseek(fp, 0 , SEEK_END);
long fileSize = ftell(fp);
fseek(fp, 0 , SEEK_SET);// needed for next read from beginning of file
...
fclose(fp);
}
但您无需打开文件即可完成:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
struct stat buffer;
int status;
status = stat("path to file", &buffer);
if(status == 0) {
// size of file is in member buffer.st_size;
}
OP 可以像 "max. size of a file in my project is 4MB".
一样 easy 来做到这一点不使用 strlen()
,而是使用 fread()
中的 return 值。 stlen()
在第一个空字符处停止,因此可能会报告一个太小的值。
请注意,许多 OS 在写入之前甚至不使用分配的内存。
Why is malloc not "using up" the memory on my computer?
fp = fopen(file_path, "rb");
if (fp) {
#define MAX_FILE_SIZE 4194304
char *buf = malloc(MAX_FILE_SIZE);
if (buf) {
size_t numread = fread(buf, sizeof *buf, MAX_FILE_SIZE, fp);
// shrink if desired
char *tmp = realloc(buf, numread);
if (tmp) {
buf = tmp;
// Use buf with numread char
}
free(buf);
}
fclose(fp);
}
注意:将整个文件读入内存可能不是最好的开始。