Come posso capire la dimensione di un file, in byte?
#include <stdio.h>
unsigned int fsize(char* file){
//what goes here?
}
char* file
, perché no FILE* file
? -1
Come posso capire la dimensione di un file, in byte?
#include <stdio.h>
unsigned int fsize(char* file){
//what goes here?
}
char* file
, perché no FILE* file
? -1
Risposte:
Basato sul codice di 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;
}
I cambiamenti:
const char
.struct stat
definizione, in cui mancava il nome della variabile.-1
in caso di errore anziché 0
, il che sarebbe ambiguo per un file vuoto. off_t
è un tipo firmato quindi questo è possibile.Se si desidera fsize()
stampare un messaggio in caso di errore, è possibile utilizzare questo:
#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;
}
Sui sistemi a 32 bit è necessario compilarlo con l'opzione -D_FILE_OFFSET_BITS=64
, altrimenti off_t
conterrà solo valori fino a 2 GB. Per i dettagli, consultare la sezione "Uso di LFS" del supporto per file di grandi dimensioni in Linux .
fseek
+ ftell
come proposto da Derek.
fseek
+ ftell
come proposto da Derek. No. Il C standard prevede espressamente che fseek()
ad SEEK_END
un file binario è un comportamento indefinito. 7.19.9.2 La fseek
funzione ... Un flusso binario non deve necessariamente supportare in modo significativo le fseek
chiamate con un valore diSEEK_END
, e come indicato di seguito, che è dalla nota 234 a pag. 267 della collegata C standard, e che in particolare etichette fseek
a SEEK_END
in un flusso binario come comportamento indefinito. .
Non usare int
. I file di dimensioni superiori a 2 gigabyte sono comuni come sporcizia in questi giorni
Non usare unsigned int
. I file di dimensioni superiori a 4 gigabyte sono comuni come sporcizia leggermente meno comune
IIRC la libreria standard definisce off_t
come un intero a 64 bit senza segno, che è quello che tutti dovrebbero usare. Possiamo ridefinirlo in 128 anni in pochi anni quando iniziamo ad avere 16 file exabyte in giro.
Se sei su Windows, dovresti usare GetFileSizeEx : in realtà utilizza un intero con segno a 64 bit, quindi inizieranno a colpire i problemi con 8 file exabyte. Microsoft sciocca! :-)
La soluzione di Matt dovrebbe funzionare, tranne per il fatto che è C ++ anziché C, e la spiegazione iniziale non dovrebbe essere necessaria.
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;
}
Risolto il problema anche con te. ;)
Aggiornamento: questa non è davvero la soluzione migliore. È limitato a file da 4 GB su Windows ed è probabilmente più lento del semplice utilizzo di una chiamata specifica della piattaforma come GetFileSizeEx
o stat64
.
long int
da ftell()
. (unsigned long)
il casting non migliora l'intervallo in quanto già limitato dalla funzione. ftell()
restituisce -1 in caso di errore e viene offuscato dal cast. Suggerisci fsize()
restituire lo stesso tipo di ftell()
.
** Non farlo ( perché? ):
Citando il documento standard C99 che ho trovato online: "L'impostazione dell'indicatore di posizione del file su end-of-file, come con
fseek(file, 0, SEEK_END)
, ha un comportamento indefinito per un flusso binario (a causa di possibili caratteri null finali) o per qualsiasi flusso con codifica dipendente dallo stato che sicuramente non termina nello stato iniziale del turno. **
Modificare la definizione in int in modo che i messaggi di errore possano essere trasmessi, quindi utilizzare fseek()
e ftell()
per determinare la dimensione del 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
}
fseeko
e ftello
(o fseek
e ftell
se sei bloccato senza il primo e soddisfatto dei limiti sulle dimensioni dei file con cui puoi lavorare) sono il modo corretto di determinare la lunghezza di un file. stat
le soluzioni basate su base non funzionano su molti "file" (come i dispositivi a blocchi) e non sono portabili su sistemi non POSIX.
Lo standard POSIX ha il suo metodo per ottenere le dimensioni del file.
Includi l' sys/stat.h
intestazione per usare la funzione.
stat(3)
.st_size
proprietà.Nota : limita la dimensione a 4GB
. Se non il Fat32
filesystem, usa la versione a 64 bit!
#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);
}
L' ANSI C non fornisce direttamente il modo per determinare la lunghezza del file.
Dovremo usare la nostra mente. Per ora, useremo l'approccio seek!
#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);
}
Se il file è
stdin
o una pipe. POSIX, ANSI C non funzionerà.
Restituirà0
se il file è una pipe ostdin
.Opinione : si dovrebbe usare invece lo standard POSIX . Perché, ha il supporto a 64 bit.
struct _stat64
e __stat64()
per _Windows.
E se stai creando un'app di Windows, usa l' API GetFileSizeEx poiché l'I / O dei file CRT è disordinato, soprattutto per determinare la lunghezza del file, a causa delle peculiarità nelle rappresentazioni dei file su sistemi diversi;)
Se stai bene usando la libreria 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;
}
Una rapida ricerca su Google ha trovato un metodo che utilizza fseek e ftell e un thread con questa domanda con risposte che non possono essere fatte in C in un altro modo.
È possibile utilizzare una libreria di portabilità come NSPR (la libreria che alimenta Firefox) o verificarne l'implementazione (piuttosto pelosa).
Ho usato questo set di codice per trovare la lunghezza del 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);
Prova questo --
fseek(fp, 0, SEEK_END);
unsigned long int file_size = ftell(fp);
rewind(fp);
Quello che fa è prima di tutto, cerca fino alla fine del file; quindi, segnala dove si trova il puntatore del file. Infine (questo è facoltativo) si riavvolge all'inizio del file. Si noti che fp
dovrebbe essere un flusso binario.
file_size contiene il numero di byte contenuti nel file. Si noti che poiché (in base a climits.h) il tipo lungo senza segno è limitato a 4294967295 byte (4 gigabyte), è necessario trovare un tipo di variabile diverso se si rischia di gestire file di dimensioni maggiori.
ftell
non restituisce un valore rappresentativo del numero di byte che è possibile leggere dal file.
Ho una funzione che funziona bene solo con stdio.h
. Mi piace molto e funziona molto bene ed è piuttosto conciso:
size_t fsize(FILE *File) {
size_t FSZ;
fseek(File, 0, 2);
FSZ = ftell(File);
rewind(File);
return FSZ;
}
Ecco una funzione semplice e pulita che restituisce le dimensioni del 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
}
È possibile aprire il file, andare a 0 offset rispetto dalla parte inferiore del file con
#define SEEKBOTTOM 2
fseek(handle, 0, SEEKBOTTOM)
il valore restituito da fseek è la dimensione del file.
Non ho programmato il codice in C per molto tempo, ma penso che dovrebbe funzionare.
Osservando la domanda, è ftell
possibile ottenere facilmente il numero di byte.
long size = ftell(FILENAME);
printf("total size is %ld bytes",size);
ftell
si aspetta un descrittore di file, non un nome file, come argomento.
ftell
non si aspetta un descrittore di file, si aspetta FILE*
invece un . Vedi prima la pagina man!
fseek()
prima per cercare la fine del file e, inoltre, si ftell()
aspetta un FILE *
, non una stringa! Saresti ben servito per dare corpo alla tua risposta.