简体   繁体   English

你如何确定C中文件的大小?

[英]How do you determine the size of a file in C?

How can I figure out the size of a file, in bytes?如何计算文件的大小(以字节为单位)?

#include <stdio.h>

unsigned int fsize(char* file){
  //what goes here?
}

Based on NilObject's code:基于 NilObject 的代码:

#include <sys/stat.h>
#include <sys/types.h>

off_t fsize(const char *filename) {
    struct stat st; 

    if (stat(filename, &st) == 0)
        return st.st_size;

    return -1; 
}

Changes:变化:

  • Made the filename argument a const char .将文件名参数const char
  • Corrected the struct stat definition, which was missing the variable name.更正了struct stat定义,该定义缺少变量名称。
  • Returns -1 on error instead of 0 , which would be ambiguous for an empty file.出错时返回-1而不是0 ,这对于空文件来说是不明确的。 off_t is a signed type so this is possible. off_t是有符号类型,所以这是可能的。

If you want fsize() to print a message on error, you can use this:如果你想让fsize()在出错时打印一条消息,你可以使用这个:

#include <sys/stat.h>
#include <sys/types.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>

off_t fsize(const char *filename) {
    struct stat st;

    if (stat(filename, &st) == 0)
        return st.st_size;

    fprintf(stderr, "Cannot determine size of %s: %s\n",
            filename, strerror(errno));

    return -1;
}

On 32-bit systems you should compile this with the option -D_FILE_OFFSET_BITS=64 , otherwise off_t will only hold values up to 2 GB.在 32 位系统上,您应该使用选项-D_FILE_OFFSET_BITS=64编译它,否则off_t最多只能保存 2 GB 的值。 See the "Using LFS" section of Large File Support in Linux for details.有关详细信息,请参阅Linux大文件支持的“使用 LFS”部分。

Don't use int .不要使用int Files over 2 gigabytes in size are common as dirt these days如今,大小超过 2 GB 的文件很常见

Don't use unsigned int .不要使用unsigned int Files over 4 gigabytes in size are common as some slightly-less-common dirt大小超过 4 GB 的文件很常见,因为一些不太常见的污垢

IIRC the standard library defines off_t as an unsigned 64 bit integer, which is what everyone should be using. IIRC 标准库将off_t定义为一个无符号的 64 位整数,这是每个人都应该使用的。 We can redefine that to be 128 bits in a few years when we start having 16 exabyte files hanging around.几年后,当我们开始有 16 艾字节的文件时,我们可以将其重新定义为 128 位。

If you're on windows, you should use GetFileSizeEx - it actually uses a signed 64 bit integer, so they'll start hitting problems with 8 exabyte files.如果你在 Windows 上,你应该使用GetFileSizeEx - 它实际上使用一个有符号的 64 位整数,所以他们会开始遇到 8 艾字节文件的问题。 Foolish Microsoft!愚蠢的微软! :-) :-)

Matt's solution should work, except that it's C++ instead of C, and the initial tell shouldn't be necessary. Matt 的解决方案应该有效,只是它是 C++ 而不是 C,并且不需要初始告诉。

unsigned long fsize(char* file)
{
    FILE * f = fopen(file, "r");
    fseek(f, 0, SEEK_END);
    unsigned long len = (unsigned long)ftell(f);
    fclose(f);
    return len;
}

Fixed your brace for you, too.也为你修好了支具。 ;) ;)

Update: This isn't really the best solution.更新:这并不是最好的解决方案。 It's limited to 4GB files on Windows and it's likely slower than just using a platform-specific call like GetFileSizeEx or stat64 .它在 Windows 上仅限于 4GB 文件,并且可能比仅使用特定于平台的调用(如GetFileSizeExstat64

**Don't do this ( why? ): **不要这样做( 为什么? ):

Quoting the C99 standard doc that i found online: "Setting the file position indicator to end-of-file, as with fseek(file, 0, SEEK_END) , has undefined behavior for a binary stream (because of possible trailing null characters) or for any stream with state-dependent encoding that does not assuredly end in the initial shift state.**引用我在网上找到的 C99 标准文档:“将文件位置指示符设置为文件结尾,与fseek(file, 0, SEEK_END) ,对于二进制流具有未定义的行为(因为可能出现尾随空字符)或对于任何具有状态相关编码但不一定以初始移位状态结束的流。**

Change the definition to int so that error messages can be transmitted, and then use fseek() and ftell() to determine the file size.把定义改成int,这样可以传输错误信息,然后用fseek()ftell()来确定文件大小。

int fsize(char* file) {
  int size;
  FILE* fh;

  fh = fopen(file, "rb"); //binary mode
  if(fh != NULL){
    if( fseek(fh, 0, SEEK_END) ){
      fclose(fh);
      return -1;
    }

    size = ftell(fh);
    fclose(fh);
    return size;
  }

  return -1; //error
}

POSIX POSIX

The POSIX standard has its own method to get file size. POSIX标准有自己的方法来获取文件大小。
Include the sys/stat.h header to use the function.包含sys/stat.h标头以使用该函数。

Synopsis概要

  • Get file statistics using stat(3) .使用stat(3)获取文件统计信息。
  • Obtain the st_size property.获取st_size属性。

Examples例子

Note : It limits the size to 4GB .注意:它将大小限制为4GB If not Fat32 filesystem then use the 64bit version!如果不是Fat32文件系统,则使用 64 位版本!

#include <stdio.h>
#include <sys/stat.h>

int main(int argc, char** argv)
{
    struct stat info;
    stat(argv[1], &info);

    // 'st' is an acronym of 'stat'
    printf("%s: size=%ld\n", argv[1], info.st_size);
}
#include <stdio.h>
#include <sys/stat.h>

int main(int argc, char** argv)
{
    struct stat64 info;
    stat64(argv[1], &info);

    // 'st' is an acronym of 'stat'
    printf("%s: size=%ld\n", argv[1], info.st_size);
}

ANSI C (standard) ANSI C(标准)

The ANSI C doesn't directly provides the way to determine the length of the file. ANSI C没有直接提供确定文件长度的方法。
We'll have to use our mind.我们将不得不使用我们的头脑。 For now, we'll use the seek approach!现在,我们将使用搜索方法!

Synopsis概要

Example例子

#include <stdio.h>

int main(int argc, char** argv)
{
    FILE* fp = fopen(argv[1]);
    int f_size;

    fseek(fp, 0, SEEK_END);
    f_size = ftell(fp);
    rewind(fp); // to back to start again

    printf("%s: size=%ld", (unsigned long)f_size);
}

If the file is stdin or a pipe.如果文件是stdin或管道。 POSIX, ANSI C won't work. POSIX,ANSI C将不起作用。
It will going return 0 if the file is a pipe or stdin .如果文件是管道或stdin ,它将返回0

Opinion : You should use POSIX standard instead.意见:您应该改用POSIX标准。 Because, it has 64bit support.因为,它支持 64 位。

If you're fine with using the std c library:如果您可以使用 std c 库:

#include <sys/stat.h>
off_t fsize(char *file) {
    struct stat filestat;
    if (stat(file, &filestat) == 0) {
        return filestat.st_size;
    }
    return 0;
}

如果您正在构建 Windows 应用程序,请使用GetFileSizeEx API,因为 CRT 文件 I/O 很混乱,尤其是在确定文件长度时,由于不同系统上文件表示的特殊性;)

I found a method using fseek and ftell and a thread with this question with answers that it can't be done in just C in another way.我找到了一个使用 fseek 和 ftell 的方法,以及一个关于这个问题的线程,其中的答案是它不能以另一种方式在 C 中完成。

You could use a portability library like NSPR (the library that powers Firefox).您可以使用像NSPR (支持 Firefox 的库)这样的可移植性库。

I used this set of code to find the file length.我使用这组代码来查找文件长度。

//opens a file with a file descriptor
FILE * i_file;
i_file = fopen(source, "r");

//gets a long from the file descriptor for fstat
long f_d = fileno(i_file);
struct stat buffer;
fstat(f_d, &buffer);

//stores file size
long file_length = buffer.st_size;
fclose(i_file);

In plain ISO C , there is only one way to determine the size of a file which is guaranteed to work: To read the entire file from the start, until you encounter end-of-file.在普通ISO C中,只有一种方法可以确定保证有效的文件大小:从头读取整个文件,直到遇到文件结尾。

However, this is highly inefficient.然而,这是非常低效的。 If you want a more efficient solution, then you will have to either如果您想要一个更有效的解决方案,那么您将不得不

  • rely on platform-specific behavior, or依赖特定于平台的行为,或者
  • revert to platform-specific functions, such as stat on Linux or GetFileSize on Microsoft Windows.恢复为特定于平台的函数,例如 Linux 上的stat或 Microsoft GetFileSize上的 GetFileSize。

In contrast to what other answers have suggested, the following code is not guaranteed to work:与其他答案所建议的相反,不能保证以下代码有效:

fseek( fp, 0, SEEK_END );
long size = ftell( fp );

Even if we assume that the data type long is large enough to represent the file size (which is questionable on some platforms, most notably Microsoft Windows), the posted code has the following problems:即使我们假设数据类型long足够大以表示文件大小(这在某些平台上是有问题的,尤其是 Microsoft Windows),发布的代码也存在以下问题:

The posted code is not guaranteed to work on text streams, because according to §7.21.9.4 ¶2 of the ISO C11 standard , the value of the file position indicator returned by ftell contains unspecified information.不保证发布的代码适用于文本流,因为根据ISO C11 标准的 §7.21.9.4 ¶2, ftell返回的文件 position 指标的值包含未指定的信息。 Only for binary streams is this value guaranteed to be the number of characters from the beginning of the file.仅对于二进制流,此值保证是从文件开头算起的字符数。 There is no such guarantee for text streams.文本流没有这样的保证。

The posted code is also not guaranteed to work on binary streams, because according to §7.21.9.2 ¶3 of the ISO C11 standard , binary streams are not required to meaningfully support SEEK_END .发布的代码也不能保证在二进制流上工作,因为根据ISO C11 标准的 §7.21.9.2 ¶3 ,二进制流不需要有意义地支持SEEK_END

That being said, on most common platforms, the posted code will work, if we assume that the data type long is large enough to represent the size of the file.也就是说,在大多数常见平台上,如果我们假设数据类型long足够大以表示文件的大小,则发布的代码将起作用。

However, on Microsoft Windows, the characters \r\n (carriage return followed by line feed) will be translated to \n for text streams (but not for binary streams), so that the file size you get will count \r\n as two bytes, although you are only reading a single character ( \n ) in text mode.但是,在 Microsoft Windows 上,字符\r\n (回车后跟换行符)将被转换为\n对于文本流(但不是二进制流),因此您获得的文件大小将计算\r\n作为两个字节,尽管您只是在文本模式下读取单个字符( \n )。 Therefore, the results you get will not be consistent.因此,您获得的结果将不一致。

On POSIX -based platforms (eg Linux), this is not an issue, because on those platforms, there is no difference between text mode and binary mode.在基于POSIX的平台(例如 Linux)上,这不是问题,因为在那些平台上,文本模式和二进制模式之间没有区别。

C++ MFC extracted from windows file details, not sure if this is better performing than seek but if it is extracted from metadata I think it is faster because it doesn't need to read the entire file从 Windows 文件详细信息中提取的C++ MFC ,不确定这是否比搜索性能更好,但如果它是从元数据中提取的,我认为它更快,因为它不需要读取整个文件

ULONGLONG GetFileSizeAtt(const wchar_t *wFile)
{
    WIN32_FILE_ATTRIBUTE_DATA fileInfo;
    ULONGLONG FileSize = 0ULL;
    //https://docs.microsoft.com/nl-nl/windows/win32/api/fileapi/nf-fileapi-getfileattributesexa?redirectedfrom=MSDN
    //https://docs.microsoft.com/nl-nl/windows/win32/api/fileapi/ns-fileapi-win32_file_attribute_data?redirectedfrom=MSDN
    if (GetFileAttributesEx(wFile, GetFileExInfoStandard, &fileInfo))
    {
        ULARGE_INTEGER ul;
        ul.HighPart = fileInfo.nFileSizeHigh;
        ul.LowPart = fileInfo.nFileSizeLow;
        FileSize = ul.QuadPart;
    }
    return FileSize;
}

Here's a simple and clean function that returns the file size.这是一个返回文件大小的简单而干净的函数。

long get_file_size(char *path)
{
    FILE *fp;
    long size = -1;
    /* Open file for reading */
    fp = fopen(path, "r");
    fseek(fp, 0, SEEK_END);
    size = ftell(fp); 
    fclose(fp);
    return 
}

Try this --尝试这个 -

fseek(fp, 0, SEEK_END);
unsigned long int file_size = ftell(fp);
rewind(fp);

What this does is first, seek to the end of the file;这样做是首先,寻找文件的末尾; then, report where the file pointer is.然后,报告文件指针在哪里。 Lastly (this is optional) it rewinds back to the beginning of the file.最后(这是可选的)它倒回到文件的开头。 Note that fp should be a binary stream.注意fp应该是一个二进制流。

file_size contains the number of bytes the file contains. file_size 包含文件包含的字节数。 Note that since (according to climits.h) the unsigned long type is limited to 4294967295 bytes (4 gigabytes) you'll need to find a different variable type if you're likely to deal with files larger than that.请注意,由于(根据 climits.h) unsigned long 类型被限制为 4294967295 字节(4 GB),如果您可能处理大于该值的文件,则需要找到不同的变量类型。

I have a function that works well with only stdio.h .我有一个仅适用于stdio.h的函数。 I like it a lot and it works very well and is pretty concise:我非常喜欢它,而且效果很好,而且非常简洁:

size_t fsize(FILE *File) {
    size_t FSZ;
    fseek(File, 0, 2);
    FSZ = ftell(File);
    rewind(File);
    return FSZ;
}

You can open the file, go to 0 offset relative from the bottom of the file with您可以打开文件,使用从文件底部相对的 0 偏移量

#define SEEKBOTTOM   2

fseek(handle, 0, SEEKBOTTOM)  

the value returned from fseek is the size of the file. fseek 返回的值是文件的大小。

I didn't code in C for a long time, but I think it should work.我很长一段时间没有用 C 编写代码,但我认为它应该可以工作。

How can I figure out the size of a file, in bytes?如何计算文件大小(以字节为单位)?

#include <stdio.h>

unsigned int fsize(char* file){
  //what goes here?
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM