fseek(f, 0, SEEK_END);
size = ftell(f);
Run Code Online (Sandbox Code Playgroud)
如果 ftell(f) 告诉我们当前文件位置,这里的大小应该是从文件末尾到开头的偏移量。为什么大小不是 ftell(f)+1?难道 ftell(f) 不应该只给我们文件末尾的位置吗?
文件位置就像文本输入小部件中的光标:它们位于文件的字节之间。如果我画一张图,这可能最容易理解:
这是一个假设的文件。它包含四个大字:a,b,c,和d。每个字符都有一个自己的小盒子,我们称之为“字节”。(此文件是 ASCII。)第五个框已被划掉,因为它还不是文件的一部分,但是如果您将第五个字符附加到文件中,它就会出现。
此文件中的有效文件位置为 0、1、2、3 和 4。它们是五个,而不是四个;它们对应于盒子之前、之后和之间的垂直线。当您打开文件时(假设您不使用"a"),您从位置 0 开始,即文件中第一个字节之前的行。当您寻找到结尾时,您会到达位置 4,即文件中最后一个字节之后的行。因为我们从零开始计数,这也是文件中的字节数。(这是几种原因之一,为什么我们从零,而不是一个开始计数。)
我不得不警告你有几个原因
fseek(fp, 0, SEEK_END);
long int nbytes = ftell(fp);
Run Code Online (Sandbox Code Playgroud)
可能不会给你你真正想要的数字,这取决于你所说的“文件大小”是什么意思和文件的内容。没有特定的顺序:
在Windows中,如果你以文本模式打开一个文件,你得到的数字ftell上的文件都不会字节从文件的开始偏移; 它们更像是fgetposcookie,只能在随后的fseek. 如果您需要在 Windows 上的文本文件中四处寻找,最好以二进制模式打开文件并自己处理 DOS 和 Unix 行尾——这实际上是我对生产代码的一般建议,因为它完全有可能在 Unix 系统上有一个以 DOS 行结尾的文件,反之亦然。
在long int32 位的系统上,文件很容易大于 32 位,在这种情况下ftell会失败,返回 -1 并设置errno为EOVERFLOW。符合 POSIX.1-2001 的系统提供了一个名为的函数ftello,该函数返回一个off_t可以表示更大文件大小的数量,前提是您放在#define _FILE_OFFSET_BITS 64所有源文件的最顶部(在任何#includes之前)。我不知道 Windows 等价物是什么。
如果您的文件包含超出 ASCII 的字符,则文件中的字节数很可能与文件中的字符数不同。(例如,如果文件以 UTF-8 编码,则该字符?将占用三个字节,Ä将占用两个或三个字节取决于它是否“组合”,并且????将占用十二个字节,因为尽管是单个grapheme,它是一个由四个 Unicode 代码点组成的字符串。)如果您的目标是将整个文件读入内存,它ftell(o)仍然会告诉您要传递给的正确数字malloc,但迭代“字符”不会像for (i = 0; i < len; i++).
如果您使用 C 的“宽流”和“宽字符”,那么,就像 Windows 上的文本流一样,您从ftell该文件中获得的数字不是字节偏移量,除了对fseek. 但无论如何,宽流和字符都是一个糟糕的设计;如果您坚持在窄流和字符中手动处理 UTF-8,您实际上更有可能正确处理世界上所有的语言。