在 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);
}

注意:将整个文件读入内存可能不是最好的开始。