C'deki bir dosyanın boyutunu nasıl belirlersiniz?


137

Bir dosyanın boyutunu bayt olarak nasıl anlayabilirim?

#include <stdio.h>

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

Bir dosyanın ayrıntılarını almak için bir kütüphane işlevi kullanmanız gerekecektir. C tamamen platformdan bağımsız olduğundan, hangi platform / işletim sistemi için geliştirdiğinizi bize bildirmeniz gerekir!
Chris Roberts

Neden char* file, neden olmasın FILE* file? -1
Bay Oscar

-1 çünkü dosya işlevleri dosya yollarını değil dosya tanımlayıcılarını kabul etmelidir
Bay Oscar

Yanıtlar:


144

NilObject koduna göre:

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

değişiklikler:

  • Dosya adı argümanını a const char.
  • struct statDeğişken adı eksik olan tanım düzeltildi .
  • İade -1yerine hata 0, hangi boş dosya için belirsiz olacaktır. off_timzalı bir tür olduğundan bu mümkündür.

Hatalı fsize()bir mesaj yazdırmak istiyorsanız , bunu kullanabilirsiniz:

#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 bit sistemlerde bunu seçenekle derlemelisiniz -D_FILE_OFFSET_BITS=64, aksi off_ttakdirde yalnızca 2 GB'a kadar olan değerleri tutacaktır. Ayrıntılar için Linux'ta Büyük Dosya Desteğinin "LFS Kullanımı" bölümüne bakın.


19
Bu Linux / Unix'e özgüdür - muhtemelen bir işletim sistemi belirtmediği için belirtmeye değer.
Drew Hall

1
Muhtemelen dönüş türünü ssize_t olarak değiştirebilir ve herhangi bir sorun olmadan off_t'den bir boyut atayabilirsiniz. Bir ssize_t kullanmak daha mantıklı görünebilir :-) (İmzasız ve hatayı belirtmek için kullanılamayan size_t ile karıştırılmamalıdır.)
Ted Percival

1
Daha taşınabilir kod için Derek tarafından önerilen şekilde fseek+ kullanın ftell.
Ciro Santilli 法轮功 7 病 六四 事件 法轮功

9
Daha taşınabilir kod için Derek tarafından önerilen şekilde fseek+ kullanın ftell. Hayır C Standart özellikle belirtiyor fseek()için SEEK_ENDbir ikili dosya tanımsız davranıştır üzerinde. 7.19.9.2 fseekfonksiyonu ... anlamlı desteklemeyen bir ikili akış gerek fseekbir nereden değeri ile çağrıSEEK_END p dipnot 234 arasındadır ve aşağıdaki belirtildiği. Bağlı C, standartlar, özellikle etiketlerin 267 fseekiçin SEEK_ENDtanımlanmamış bir davranış gibi bir ikili akışında. .
Andrew Henle

74

Kullanma int. 2 gigabaytın üzerindeki dosyalar bu günlerde kir olarak yaygındır

Kullanma unsigned int. 4 gigabaytın üzerindeki dosyalar biraz daha az yaygın olan kir olarak yaygındır

IIRC, standart kütüphane off_timzasız bir 64 bit tamsayı olarak tanımlar , bu da herkesin kullanması gereken şeydir. 16 exabyte dosyasını asmaya başladığımızda birkaç yıl içinde 128 bit olarak yeniden tanımlayabiliriz.

Windows kullanıyorsanız, şunu kullanmalısınız: GetFileSizeEx - aslında imzalı bir 64 bit tam sayı kullanır, bu nedenle 8 exabyte dosyasıyla ilgili sorunlara başlamaya başlarlar. Aptalca Microsoft! :-)


1
Ben off_t 32 bit olduğu derleyiciler kullandım. Bu 4GB dosyalarının daha az yaygın olduğu gömülü sistemlerde geçerlidir. Her neyse, POSIX ayrıca karışıklık eklemek için off64_t ve karşılık gelen yöntemleri de tanımlar.
Aaron Campbell

Windows'u varsayan ve soruyu eleştirmekten başka bir şey yapmayan cevapları her zaman seviyorum. POSIX uyumlu bir şey ekler misiniz?
SS Anne

1
@ JL2210, Ted Percival'ın kabul edilen cevabı posix uyumlu bir çözüm gösteriyor, bu yüzden açık olanı tekrarlamakta bir anlam görmüyorum. Ben (ve diğerleri 70) pencereler hakkında not ekleyerek ve dosya boyutlarını temsil etmek için imzalı 32 bit tamsayılar kullanmamak bunun üzerine bir katma değer olduğunu düşündüm. Şerefe
Orion Edwards

30

Matt'in çözümü, C yerine C ++ dışında çalışmalı ve ilk anlatım gerekli olmamalıdır.

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

Sizin için de küme ayracı düzeltildi. ;)

Güncelleme: Bu gerçekten en iyi çözüm değil. Windows'ta 4GB dosyalarla sınırlıdır ve muhtemelen GetFileSizeExveya gibi platforma özgü bir arama kullanmaktan daha yavaştır stat64.


Evet yapmalısın. Bununla birlikte, platforma özgü yazmamak için gerçekten zorlayıcı bir neden yoksa, muhtemelen sadece open / seek-end / tell / close modeli yerine platforma özgü bir çağrı kullanmalısınız.
Derek Park

1
Geç cevap için üzgünüm, ama burada büyük bir sorun yaşıyorum. Uygulamanın kısıtlanmış dosyalara (şifre korumalı veya sistem dosyaları gibi) erişirken askıda kalmasına neden olur. Gerektiğinde kullanıcıdan şifre istemenin bir yolu var mı?
Justin

@Justin, muhtemelen özellikle karşılaştığınız sorun hakkında yeni bir soru açmalı ve üzerinde bulunduğunuz platform, dosyalara nasıl eriştiğiniz ve davranışların ne olduğu hakkında ayrıntılar vermelisiniz.
Derek Park

1
Hem C99 ve C11 dönüş long intdan ftell(). (unsigned long)Döküm, işlevle zaten sınırlı olan aralığı geliştirmez. ftell()hata durumunda -1 döndürür ve bu, dökümle karıştırılır. İle fsize()aynı türü döndürmenizi öneririz ftell().
chux - Monica

Katılıyorum. Oyuncular, söz konusu orijinal prototiple eşleşecekti. Yine de neden imzasız int yerine imzasız uzun sürdüğümü hatırlayamıyorum.
Derek Park

15

** Bunu yapma ( neden? ):

Çevrimiçi bulduğum C99 standart dokümanı alıntılamak: "Dosya konumu göstergesini olduğu gibi dosya sonuna ayarlamak, fseek(file, 0, SEEK_END)ikili akış (olası boş karakterlerden dolayı) veya duruma bağlı kodlamaya sahip herhangi bir akış için tanımlanmamış bir davranışa sahiptir ilk vardiya durumunda kesinlikle bitmeyen. **

Hata iletileri bulaşan böylece int ve sonra kullanmak tanımını değiştirin fseek()ve ftell()dosya boyutunu belirlemek için.

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
}

5
@mezhaka: Bu CERT raporu yanlış. fseekove ftello(veya fseekve ftellsen çalışabilirsiniz boyutları dosya üzerinde limitlerine eski ve mutlu olmadan sıkışmış iseniz) bir dosyanın uzunluğunu belirlemek için doğru bir yoldur. stattabanlı çözümler işe yaramaz (örneğin blok cihazları gibi) birçok "dosya" konulu ve non-POSIX imsi sistemlere taşınabilir değildir.
R .. GitHub BUZA YARDIMCI DURDUR

1
Posix uyumlu olmayan birçok sistemde (çok minimalist mbedim gibi) dosya boyutunu almanın tek yolu budur
Earlz

9

POSIX

POSIX standardı dosya boyutunu almak için kendi yöntemi vardır.
Dahil etsys/stat.hİşlevi kullanmak başlığı .

özet

  • Düğmesini kullanarak dosya istatistiklerini alın stat(3).
  • st_sizeMülkü edinin .

Örnekler

Not : Boyutu ile sınırlar 4GB. Fat32Dosya sistemi değilse 64bit sürümünü kullanın!

#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 (standart)

ANSI C doğrudan dosyanın uzunluğunu belirlemek için bir yol sağlar etmez.
Aklımızı kullanmalıyız. Şimdilik arama yaklaşımını kullanacağız!

özet

  • Düğmesini kullanarak dosyayı sonuna kadar arayın fseek(3).
  • Düğmesini kullanarak geçerli konumu alın ftell(3).

Misal

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

Dosya stdinveya kanal ise. POSIX, ANSI C çalışmaz. Dosya bir pipo veya ise
geri dönecektir .0stdin

Görüş : Bunun yerine POSIX standardını kullanmalısınız. Çünkü 64 bit desteği var.


1
struct _stat64ve __stat64()_Windows için.
Bob Stein

5

Ve bir Windows uygulaması oluşturuyorsanız, GetFileSizeEx API'sini CRT dosyası G / Ç'nin dağınık olması nedeniyle kullanın, özellikle farklı sistemlerde dosya sunumlarındaki özellikler nedeniyle dosya uzunluğunu belirlemek için;)


5

Std c kütüphanesini kullanmakta sorun yaşıyorsanız:

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

24
Bu standart C değil. POSIX standardının bir parçası, ancak C standardı değil.
Derek Park


1

Dosya uzunluğunu bulmak için bu kod kümesini kullandım.

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

1

Bunu dene --

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

Bunun ilk önce yaptığı dosyanın sonuna bakın; daha sonra dosya tanıtıcısının nerede olduğunu bildirin. Son olarak (bu isteğe bağlıdır) dosyanın başına geri sarar. Bunun fpikili bir akış olması gerektiğini unutmayın .

file_size dosyanın içerdiği bayt sayısını içerir. (İklime göre. H) imzasız uzun tip 4294967295 bayt (4 gigabayt) ile sınırlı olduğundan, bundan daha büyük dosyalarla ilgilenmeniz gerekiyorsa farklı bir değişken türü bulmanız gerektiğini unutmayın.


3
Bu Derek'in 8 yıl önceki cevabından ne farkı var ?
PP

Bu, ikili bir akış için tanımlanmamış bir davranıştır ve bir metin akışı için ftell, dosyadan okunabilen bayt sayısını temsil eden bir değer döndürmez.
Andrew Henle

0

Sadece iyi çalışan bir fonksiyonum var stdio.h. Çok beğendim ve çok iyi çalışıyor ve oldukça özlü:

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

0

İşte dosya boyutunu döndüren basit ve temiz bir işlev.

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); 
    fp.close();
    return 
}

1
Dosyayı kapatmanıza gerek yok mu?
Jerry Jeremiah

Hayır, bir yol bekleyen işlevleri sevmiyorum. Bunun yerine, lütfen bir dosya işaretçisi exppect olun
Mr Oscar

-3

Dosyayı açabilir, dosyanın alt kısmından göreli olarak 0 ofsetine gidebilirsiniz.

#define SEEKBOTTOM   2

fseek(handle, 0, SEEKBOTTOM)  

fseek'ten döndürülen değer dosyanın boyutudur.

C'de uzun süre kod yazmadım, ama işe yarayacağını düşünüyorum.


12
SEEKBOTTOM gibi bir şey tanımlamanız gerekmez. #include <stdio.h> fseek (tanıtıcı, 0, SEEK_END);
sigjuice

-4

Soruya bakarak, ftellbayt sayısını kolayca alabilirsiniz.

  long size = ftell(FILENAME);
  printf("total size is %ld bytes",size);

ftellargüman olarak dosya adı değil dosya tanımlayıcı bekler.
Barmar

@Barmar, No ftellbir dosya tanımlayıcı beklemez, FILE*bunun yerine bir dosya bekler . Önce man sayfasına bakın!

Yaklaşım tamamen yanlış, her ftellzaman dönecek sabit 0!

Bu yanıt yanlıştır, biri için, fseek()önce dosyanın sonunu aramak için kullanmanız gerekir ve ayrıca bir dize değil , bir ftell()bekler FILE *! Cevabınızı düzeltmek için iyi hizmet edersiniz.
Bay Oscar
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.