簡體   English   中英

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

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

如何計算文件的大小(以字節為單位)?

#include <stdio.h>

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

基於 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; 
}

變化:

  • 將文件名參數const char
  • 更正了struct stat定義,該定義缺少變量名稱。
  • 出錯時返回-1而不是0 ,這對於空文件來說是不明確的。 off_t是有符號類型,所以這是可能的。

如果你想讓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;
}

在 32 位系統上,您應該使用選項-D_FILE_OFFSET_BITS=64編譯它,否則off_t最多只能保存 2 GB 的值。 有關詳細信息,請參閱Linux大文件支持的“使用 LFS”部分。

不要使用int 如今,大小超過 2 GB 的文件很常見

不要使用unsigned int 大小超過 4 GB 的文件很常見,因為一些不太常見的污垢

IIRC 標准庫將off_t定義為一個無符號的 64 位整數,這是每個人都應該使用的。 幾年后,當我們開始有 16 艾字節的文件時,我們可以將其重新定義為 128 位。

如果你在 Windows 上,你應該使用GetFileSizeEx - 它實際上使用一個有符號的 64 位整數,所以他們會開始遇到 8 艾字節文件的問題。 愚蠢的微軟! :-)

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

也為你修好了支具。 ;)

更新:這並不是最好的解決方案。 它在 Windows 上僅限於 4GB 文件,並且可能比僅使用特定於平台的調用(如GetFileSizeExstat64

**不要這樣做( 為什么? ):

引用我在網上找到的 C99 標准文檔:“將文件位置指示符設置為文件結尾,與fseek(file, 0, SEEK_END) ,對於二進制流具有未定義的行為(因為可能出現尾隨空字符)或對於任何具有狀態相關編碼但不一定以初始移位狀態結束的流。**

把定義改成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標准有自己的方法來獲取文件大小。
包含sys/stat.h標頭以使用該函數。

概要

  • 使用stat(3)獲取文件統計信息。
  • 獲取st_size屬性。

例子

注意:它將大小限制為4GB 如果不是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(標准)

ANSI C沒有直接提供確定文件長度的方法。
我們將不得不使用我們的頭腦。 現在,我們將使用搜索方法!

概要

例子

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

如果文件是stdin或管道。 POSIX,ANSI C將不起作用。
如果文件是管道或stdin ,它將返回0

意見:您應該改用POSIX標准。 因為,它支持 64 位。

如果您可以使用 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 很混亂,尤其是在確定文件長度時,由於不同系統上文件表示的特殊性;)

我找到了一個使用 fseek 和 ftell 的方法,以及一個關於這個問題的線程,其中的答案是它不能以另一種方式在 C 中完成。

您可以使用像NSPR (支持 Firefox 的庫)這樣的可移植性庫。

我使用這組代碼來查找文件長度。

//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);

在普通ISO C中,只有一種方法可以確定保證有效的文件大小:從頭讀取整個文件,直到遇到文件結尾。

然而,這是非常低效的。 如果您想要一個更有效的解決方案,那么您將不得不

  • 依賴特定於平台的行為,或者
  • 恢復為特定於平台的函數,例如 Linux 上的stat或 Microsoft GetFileSize上的 GetFileSize。

與其他答案所建議的相反,不能保證以下代碼有效:

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

即使我們假設數據類型long足夠大以表示文件大小(這在某些平台上是有問題的,尤其是 Microsoft Windows),發布的代碼也存在以下問題:

不保證發布的代碼適用於文本流,因為根據ISO C11 標准的 §7.21.9.4 ¶2, ftell返回的文件 position 指標的值包含未指定的信息。 僅對於二進制流,此值保證是從文件開頭算起的字符數。 文本流沒有這樣的保證。

發布的代碼也不能保證在二進制流上工作,因為根據ISO C11 標准的 §7.21.9.2 ¶3 ,二進制流不需要有意義地支持SEEK_END

也就是說,在大多數常見平台上,如果我們假設數據類型long足夠大以表示文件的大小,則發布的代碼將起作用。

但是,在 Microsoft Windows 上,字符\r\n (回車后跟換行符)將被轉換為\n對於文本流(但不是二進制流),因此您獲得的文件大小將計算\r\n作為兩個字節,盡管您只是在文本模式下讀取單個字符( \n )。 因此,您獲得的結果將不一致。

在基於POSIX的平台(例如 Linux)上,這不是問題,因為在那些平台上,文本模式和二進制模式之間沒有區別。

從 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;
}

這是一個返回文件大小的簡單而干凈的函數。

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 
}

嘗試這個 -

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

這樣做是首先,尋找文件的末尾; 然后,報告文件指針在哪里。 最后(這是可選的)它倒回到文件的開頭。 注意fp應該是一個二進制流。

file_size 包含文件包含的字節數。 請注意,由於(根據 climits.h) unsigned long 類型被限制為 4294967295 字節(4 GB),如果您可能處理大於該值的文件,則需要找到不同的變量類型。

我有一個僅適用於stdio.h的函數。 我非常喜歡它,而且效果很好,而且非常簡潔:

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

您可以打開文件,使用從文件底部相對的 0 偏移量

#define SEEKBOTTOM   2

fseek(handle, 0, SEEKBOTTOM)  

fseek 返回的值是文件的大小。

我很長一段時間沒有用 C 編寫代碼,但我認為它應該可以工作。

如何計算文件大小(以字節為單位)?

#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