Bagaimana Anda menentukan ukuran file di C?

142

Bagaimana cara mengetahui ukuran file, dalam byte?

#include <stdio.h>

unsigned int fsize(char* file){
  //what goes here?
}
andrewrk
sumber
Anda akan perlu menggunakan fungsi perpustakaan untuk mengambil detail file. Karena C sepenuhnya tidak bergantung pada platform, Anda harus memberi tahu kami platform / sistem operasi apa yang Anda kembangkan!
Chris Roberts
Kenapa char* filekenapa tidak FILE* file? -1
-1 karena fungsi file harus menerima deskriptor file bukan jalur file

Jawaban:

147

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

Perubahan:

  • Membuat argumen nama file a const char.
  • Memperbaiki struct statdefinisi, yang nama variabelnya hilang.
  • Mengembalikan -1kesalahan, bukan0 , yang akan menjadi ambigu untuk file kosong. off_tadalah tipe yang ditandatangani jadi ini mungkin.

jika kamu mau fsize() mencetak pesan tentang kesalahan, Anda dapat menggunakan ini:

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

Pada sistem 32-bit Anda harus mengkompilasi ini dengan opsi -D_FILE_OFFSET_BITS=64, jika tidak off_thanya akan menyimpan nilai hingga 2 GB. Lihat bagian "Menggunakan LFS" dari Dukungan File Besar di Linux untuk detailnya.

Ted Percival
sumber
19
Ini khusus untuk Linux / Unix - mungkin perlu ditunjukkan karena pertanyaannya tidak menentukan OS.
Drew Hall
1
Anda mungkin dapat mengubah tipe pengembalian ke ssize_t dan mengubah ukuran dari off_t tanpa masalah. Tampaknya lebih masuk akal untuk menggunakan ssize_t :-) (Jangan bingung dengan size_t yang tidak bertanda tangan dan tidak dapat digunakan untuk menunjukkan kesalahan.)
Ted Percival
1
Untuk kode yang lebih portabel, gunakan fseek+ ftellseperti yang diusulkan oleh Derek.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
9
Untuk kode yang lebih portabel, gunakan fseek+ ftellseperti yang diusulkan oleh Derek. Tidak The C Standard secara khusus menyatakan bahwa fseek()untuk SEEK_ENDpada file biner adalah perilaku undefined. 7.19.9.2 fseekFungsi ... Aliran biner tidak perlu secara berarti mendukung fseekpanggilan dengan nilai dari manaSEEK_END , dan seperti yang disebutkan di bawah ini, yang berasal dari catatan kaki 234 di hal. 267 dari C Standard terkait, dan yang secara khusus label fseekuntuk SEEK_ENDdalam aliran biner sebagai perilaku undefined. .
Andrew Henle
Dari gnu libc manual : ... Sistem [non-POSIX] membuat perbedaan antara file yang berisi teks dan file yang berisi data biner, dan fasilitas input dan output ISO C menyediakan perbedaan ini. ... Di GNU C Library, dan di semua sistem POSIX, tidak ada perbedaan antara aliran teks dan aliran biner. Saat Anda membuka aliran, Anda mendapatkan jenis aliran yang sama terlepas dari apakah Anda meminta biner. Aliran ini dapat menangani konten file apa pun, dan tidak memiliki batasan yang terkadang dimiliki aliran teks.
Bocah Kecil
75

Jangan gunakan int. File berukuran lebih dari 2 gigabyte umum sebagai kotoran hari ini

Jangan gunakan unsigned int. File berukuran lebih dari 4 gigabyte biasa terjadi sebagai kotoran yang sedikit kurang umum

IIRC yang didefinisikan oleh pustaka standar off_t sebagai integer 64 bit unsigned, yang harus digunakan setiap orang. Kami dapat mendefinisikan ulang itu menjadi 128 bit dalam beberapa tahun ketika kami mulai memiliki 16 file exabyte berkeliaran.

Jika Anda menggunakan windows, Anda harus menggunakan GetFileSizeEx - ini sebenarnya menggunakan integer 64 bit yang ditandatangani, jadi mereka akan mulai mengalami masalah dengan 8 file exabyte. Microsoft yang bodoh! :-)

Orion Edwards
sumber
2
Saya telah menggunakan kompiler di mana off_t adalah 32 bit. Memang, ini ada di sistem tertanam di mana file 4GB kurang umum. Bagaimanapun, POSIX juga mendefinisikan off64_t dan metode terkait untuk menambah kebingungan.
Aaron Campbell
Saya selalu menyukai jawaban yang mengasumsikan Windows dan tidak melakukan apa-apa selain mengkritik pertanyaan itu. Bisakah Anda menambahkan sesuatu yang sesuai dengan POSIX?
SS Anne
1
@ JL2210 jawaban yang diterima dari Ted Percival menunjukkan solusi yang sesuai dengan posix, jadi saya tidak melihat ada gunanya mengulangi yang sudah jelas. Saya (dan 70 lainnya) berpikir bahwa menambahkan catatan tentang windows dan tidak menggunakan bilangan bulat 32 bit yang ditandatangani untuk mewakili ukuran file adalah nilai tambah di atas itu. Cheers
Orion Edwards
31

Solusi Matt seharusnya berfungsi, kecuali bahwa itu C ++, bukan C, dan perintah awal seharusnya tidak diperlukan.

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

Memperbaiki brace untuk Anda juga. ;)

Pembaruan: Ini sebenarnya bukan solusi terbaik. Ini terbatas pada file 4GB di Windows dan kemungkinan lebih lambat daripada hanya menggunakan panggilan khusus platform seperti GetFileSizeExatau stat64.

Taman Derek
sumber
Ya kamu harus. Namun, kecuali ada alasan yang sangat kuat untuk tidak menulis khusus platform, Anda mungkin sebaiknya hanya menggunakan panggilan khusus platform daripada pola buka / seek-end / beri tahu / tutup.
Derek Park
1
Maaf atas balasan yang terlambat, tetapi saya mengalami masalah besar di sini. Itu menyebabkan aplikasi macet saat mengakses file yang dibatasi (seperti dilindungi kata sandi atau file sistem). Apakah ada cara untuk meminta kata sandi kepada pengguna saat dibutuhkan?
Justin
@Justin, Anda mungkin harus membuka pertanyaan baru secara khusus tentang masalah yang Anda hadapi, dan memberikan detail tentang platform yang Anda gunakan, bagaimana Anda mengakses file, dan apa perilakunya.
Derek Park
1
Baik C99 dan C11 kembali long intdari ftell(). (unsigned long)casting tidak meningkatkan jangkauan karena telah dibatasi oleh fungsinya. ftell()return -1 on error dan itu dikaburkan dengan cast. Sarankan fsize()kembalikan tipe yang sama seperti ftell().
chux
Saya setuju. Pemerannya harus mencocokkan prototipe asli dalam pertanyaan itu. Saya tidak dapat mengingat mengapa saya mengubahnya menjadi unsigned long dan bukan unsigned int.
Derek Park
14

** Jangan lakukan ini ( mengapa? ):

Mengutip dokumen standar C99 yang saya temukan online: "Menyetel indikator posisi file ke akhir file, seperti halnya fseek(file, 0, SEEK_END), memiliki perilaku tidak terdefinisi untuk aliran biner (karena kemungkinan karakter null tertinggal) atau untuk aliran apa pun dengan pengkodean yang bergantung pada status yang tidak pasti berakhir pada status shift awal. **

Ubah definisi menjadi int agar pesan kesalahan dapat dikirim, kemudian gunakan fseek()dan ftell()untuk menentukan ukuran file.

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
}
andrewrk
sumber
5
@mezhaka: Laporan CERT itu salah. fseekodan ftello(atau fseekdan ftelljika Anda terjebak tanpa yang pertama dan senang dengan batasan ukuran file yang dapat Anda gunakan) adalah cara yang tepat untuk menentukan panjang file. statsolusi berbasis tidak bekerja pada banyak "file" (seperti perangkat blok) dan tidak portabel ke sistem non-POSIX-ish.
R .. GitHub STOP HELPING ICE
1
Ini adalah satu-satunya cara untuk mendapatkan ukuran file pada banyak sistem non-posix compliant (seperti mbed saya yang sangat minimalis)
Earlz
9

POSIX

Standar POSIX memiliki metode sendiri untuk mendapatkan ukuran file.
Sertakansys/stat.h tajuk untuk menggunakan fungsi tersebut.

Ringkasan

  • Dapatkan statistik file menggunakan stat(3) .
  • Dapatkan st_sizepropertinya.

Contoh

Catatan : Ini membatasi ukuran 4GB. Jika bukan Fat32filesystem, gunakan versi 64bit!

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

The ANSI C tidak secara langsung menyediakan cara untuk menentukan panjang file.
Kita harus menggunakan pikiran kita. Untuk saat ini, kami akan menggunakan pendekatan seek!

Ringkasan

  • Cari file sampai akhir menggunakan fseek(3) .
  • Dapatkan posisi saat ini menggunakan ftell(3).

Contoh

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

Jika file tersebut adalah stdinatau pipa. POSIX, ANSI C tidak akan berfungsi.
Ini akan kembali 0jika file tersebut adalah pipa atau stdin.

Opini : Sebaiknya gunakan standar POSIX . Sebab, memiliki dukungan 64bit.


sumber
1
struct _stat64dan __stat64()untuk _Windows.
Bob Stein
5

Jika Anda baik-baik saja menggunakan pustaka 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;
}
NilObject
sumber
24
Itu bukan standar C. Ini bagian dari standar POSIX, tapi bukan standar C.
Derek Park
4

Dan jika Anda membuat aplikasi Windows, gunakan GetFileSizeEx API karena file CRT I / O berantakan, terutama untuk menentukan panjang file, karena kekhasan dalam representasi file pada sistem yang berbeda;)


sumber
3

Pencarian cepat di Google menemukan metode menggunakan fseek dan ftell dan utas dengan pertanyaan ini dengan jawaban yang tidak dapat dilakukan hanya dalam C dengan cara lain.

Anda dapat menggunakan pustaka portabilitas seperti NSPR (pustaka yang mendukung Firefox) atau memeriksa implementasinya (agak berbulu).

Nickolay
sumber
2

Saya menggunakan rangkaian kode ini untuk menemukan panjang file.

//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);
rco16
sumber
0

Coba ini --

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

Apa yang dilakukan ini adalah yang pertama, cari ke akhir file; lalu, laporkan lokasi penunjuk file. Terakhir (ini opsional) itu mundur kembali ke awal file. Perhatikan bahwa fpharus aliran biner.

file_size berisi jumlah byte yang dimiliki file. Perhatikan bahwa karena (menurut climits.h) tipe panjang unsigned dibatasi hingga 4294967295 byte (4 gigabyte) Anda perlu mencari tipe variabel yang berbeda jika Anda cenderung menangani file yang lebih besar dari itu.

adrian
sumber
3
Bagaimana ini berbeda dengan jawaban Derek dari 8 tahun lalu?
PP
Itu adalah perilaku yang tidak ditentukan untuk aliran biner, dan untuk aliran teks ftelltidak mengembalikan nilai yang mewakili jumlah byte yang dapat dibaca dari file.
Andrew Henle
0

Saya memiliki fungsi yang hanya berfungsi dengan baik stdio.h. Saya sangat menyukainya dan bekerja dengan sangat baik dan cukup ringkas:

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

sumber
0

Berikut adalah fungsi sederhana dan bersih yang mengembalikan ukuran file.

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 
}
Abdessamad Doughri
sumber
1
Apakah Anda tidak perlu menutup file?
Jerry Jeremiah
Tidak, saya tidak suka fungsi yang mengharapkan jalur. Sebagai gantinya, harap buat agar tidak mengharapkan penunjuk file
-3

Anda dapat membuka file, pergi ke 0 relatif offset dari bagian bawah file dengan

#define SEEKBOTTOM   2

fseek(handle, 0, SEEKBOTTOM)  

nilai yang dikembalikan dari fseek adalah ukuran file.

Saya tidak membuat kode dalam C untuk waktu yang lama, tetapi saya pikir itu harus berhasil.

PabloG
sumber
12
Anda tidak perlu mendefinisikan sesuatu seperti SEEKBOTTOM. #include <stdio.h> fseek (handle, 0, SEEK_END);
sigjuice
-3

Melihat pertanyaan itu, ftelldengan mudah bisa mendapatkan jumlah byte.

  long size = ftell(FILENAME);
  printf("total size is %ld bytes",size);
zishan
sumber
ftellmengharapkan deskriptor file, bukan nama file, sebagai argumen.
Barmar
@Barmar, No ftelltidak mengharapkan deskriptor file, FILE*melainkan. Lihat halaman manual dulu!
Pendekatannya benar-benar salah, Itu konstan yang ftellakan kembali 0setiap saat!
Jawaban ini benar-benar salah, karena untuk satu, Anda harus menggunakan fseek()pertama untuk mencari akhir file, dan juga, ftell()mengharapkan a FILE *, bukan string! Anda akan dilayani dengan baik untuk menyempurnakan jawaban Anda.