Because C was meant to be portable. And back when C became popular, file storage techniques varied wildly, so the definition of file structure is pretty loose.
From the C standard, chapter 7.19.2 Streams:
Characters may have to be added, altered, or deleted on input and output to conform to differing conventions for representing text in the host environment. Thus, there need not be a one-to-one correspondence between the characters in a stream and those in the external representation. Data read in from a text stream will necessarily compare equal to the data that were earlier written out to that stream only if: the data consist only of printing characters and the control characters horizontal tab and new-line; no new-line character is immediately preceded by space characters; and the last character is a new-line character. Whether space characters that are written out immediately before a new-line character appear when read in is implementation-defined.
A binary stream is an ordered sequence of characters that can transparently record internal data. Data read in from a binary stream shall compare equal to the data that were earlier written out to that stream, under the same implementation. Such a stream may, however, have an implementation-defined number of null characters appended to the end of the stream.
Lots of "implementation-defined" in there...
And then remember that this was the time where core memory was measured in kilobytes, and punch cards / tape drives were common. Even
if those devices had the metadata to tell the file size beforehand, you just didn't load the whole file to memory, you processed it record by record.
And even if you
knew the file size, given how streams are defined, you still didn't know how much space the file would require in memory.