Sie müssen eine Bibliotheksfunktion verwenden, um die Details einer Datei abzurufen. Da C vollständig plattformunabhängig ist, müssen Sie uns mitteilen, für welche Plattform / welches Betriebssystem Sie entwickeln!
Chris Roberts
Warum char* file, warum nicht FILE* file? -1
Herr Oscar
-1, weil Dateifunktionen Dateideskriptoren und keine Dateipfade akzeptieren sollten
Herr Oscar
Antworten:
144
Basierend auf dem Code von NilObject:
#include<sys/stat.h>#include<sys/types.h>off_t fsize(constchar*filename){struct stat st;if(stat(filename,&st)==0)return st.st_size;return-1;}
Änderungen:
Das Dateinamenargument wurde a const char.
Die struct statDefinition wurde korrigiert , bei der der Variablenname fehlte.
Gibt -1bei Fehler statt zurück 0, was für eine leere Datei nicht eindeutig wäre. off_tist ein signierter Typ, daher ist dies möglich.
Wenn Sie fsize()eine Fehlermeldung drucken möchten , können Sie Folgendes verwenden:
#include<sys/stat.h>#include<sys/types.h>#include<string.h>#include<stdio.h>#include<errno.h>off_t fsize(constchar*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;}
Auf 32-Bit-Systemen sollten Sie dies mit der Option kompilieren -D_FILE_OFFSET_BITS=64, da sonst off_tnur Werte bis zu 2 GB gespeichert werden. Weitere Informationen finden Sie im Abschnitt "Verwenden von LFS" der Unterstützung großer Dateien unter Linux .
Dies ist Linux / Unix-spezifisch - wahrscheinlich erwähnenswert, da in der Frage kein Betriebssystem angegeben wurde.
Drew Hall
1
Sie könnten wahrscheinlich den Rückgabetyp in ssize_t ändern und die Größe ohne Probleme von off_t umwandeln. Es scheint sinnvoller zu sein, ein ssize_t zu verwenden :-) (Nicht zu verwechseln mit size_t, das nicht signiert ist und nicht zur Anzeige eines Fehlers verwendet werden kann.)
Ted Percival
1
Verwenden Sie für portableren Code fseek+, ftellwie von Derek vorgeschlagen.
Ciro Santilli 法轮功 冠状 病 六四 事件 2
9
Verwenden Sie für portableren Code fseek+, ftellwie von Derek vorgeschlagen. Nein. Der C-Standard besagt ausdrücklich, dass fseek()to SEEK_ENDin einer Binärdatei ein undefiniertes Verhalten ist. 7.19.9.2 Die fseekFunktion ... Ein binärer Stream muss fseekAufrufe mit einem Woher-Wert vonSEEK_END und, wie unten angegeben, aus Fußnote 234 auf S. 22 nicht sinnvoll unterstützen . 267 des C - Standard verbunden ist , und welche spezifisch Etiketten fseekzu SEEK_ENDin einem Binärstrom als undefiniertes Verhalten. .
Andrew Henle
74
Nicht benutzen int . Dateien mit einer Größe von mehr als 2 Gigabyte sind heutzutage als Schmutz üblich
Nicht benutzen unsigned int . Dateien mit einer Größe von mehr als 4 Gigabyte sind häufig als etwas weniger häufig vorkommender Schmutz
IIRC Die Standardbibliothek definiert off_tals vorzeichenlose 64-Bit-Ganzzahl, die jeder verwenden sollte. Wir können das in ein paar Jahren auf 128 Bit neu definieren, wenn 16 Exabyte-Dateien herumhängen.
Wenn Sie unter Windows arbeiten, sollten Sie GetFileSizeEx verwenden - es wird tatsächlich eine vorzeichenbehaftete 64-Bit-Ganzzahl verwendet, sodass Probleme mit 8 Exabyte-Dateien auftreten. Dummes Microsoft! :-)
Ich habe Compiler verwendet, bei denen off_t 32 Bit beträgt. Zugegeben, dies ist auf eingebetteten Systemen der Fall, auf denen 4-GB-Dateien weniger häufig sind. Wie auch immer, POSIX definiert auch off64_t und entsprechende Methoden, um die Verwirrung zu vergrößern.
Aaron Campbell
Ich liebe immer Antworten, die Windows voraussetzen und nichts anderes tun, als die Frage zu kritisieren. Könnten Sie bitte etwas hinzufügen, das POSIX-konform ist?
SS Anne
1
@ JL2210 Die akzeptierte Antwort von Ted Percival zeigt eine Posix-konforme Lösung, daher sehe ich keinen Sinn darin, das Offensichtliche zu wiederholen. Ich (und 70 andere) waren der Meinung, dass das Hinzufügen des Hinweises zu Windows und das Nichtverwenden von vorzeichenbehafteten 32-Bit-Ganzzahlen zur Darstellung von Dateigrößen ein Mehrwert ist. Prost
Orion Edwards
30
Matts Lösung sollte funktionieren, außer dass es C ++ anstelle von C ist und das anfängliche Tell nicht notwendig sein sollte.
unsignedlong fsize(char* file){FILE* f = fopen(file,"r");
fseek(f,0, SEEK_END);unsignedlong len =(unsignedlong)ftell(f);
fclose(f);return len;}
Reparierte auch deine Zahnspange für dich. ;)
Update: Dies ist nicht wirklich die beste Lösung. Es ist auf 4 GB-Dateien unter Windows beschränkt und wahrscheinlich langsamer als nur ein plattformspezifischer Aufruf wie GetFileSizeExoder stat64.
Ja du solltest. Sofern es keinen wirklich zwingenden Grund gibt, nicht plattformspezifisch zu schreiben, sollten Sie jedoch wahrscheinlich nur einen plattformspezifischen Aufruf anstelle des Musters open / seek-end / tell / close verwenden.
Derek Park
1
Entschuldigung für die späte Antwort, aber ich habe hier ein großes Problem. Die App bleibt hängen, wenn auf eingeschränkte Dateien zugegriffen wird (z. B. kennwortgeschützte Dateien oder Systemdateien). Gibt es eine Möglichkeit, den Benutzer bei Bedarf nach einem Passwort zu fragen?
Justin
@Justin, Sie sollten wahrscheinlich eine neue Frage speziell zu dem Problem, auf das Sie stoßen, öffnen und Details zu der Plattform, auf der Sie sich befinden, wie Sie auf die Dateien zugreifen und wie sich das Verhalten verhält.
Derek Park
1
Sowohl C99 als auch C11 kehren long intvon zurück ftell(). (unsigned long)Das Gießen verbessert die Reichweite nicht, da sie bereits durch die Funktion begrenzt ist. ftell()Rückgabe -1 bei Fehler und das wird mit der Besetzung verschleiert. Schlagen Sie vor fsize(), den gleichen Typ wie zurückzugeben ftell().
chux
Genau. Die Besetzung sollte dem ursprünglichen Prototyp in der Frage entsprechen. Ich kann mich nicht erinnern, warum ich es in unsigned long anstatt in unsigned int verwandelt habe.
Zitieren des C99-Standarddokuments, das ich online gefunden habe: "Das Setzen des Dateipositionsindikators auf Dateiende hat wie bei ein fseek(file, 0, SEEK_END)undefiniertes Verhalten für einen Binärdatenstrom (aufgrund möglicher nachfolgender Nullzeichen) oder für jeden Datenstrom mit zustandsabhängiger Codierung das endet nicht sicher im anfänglichen Schaltzustand. **
Ändern Sie die Definition in int, damit Fehlermeldungen übertragen werden können, und verwenden Sie dann fseek()und ftell(), um die Dateigröße zu bestimmen.
@mezhaka: Dieser CERT-Bericht ist einfach falsch. fseekound ftello(oder fseekund ftellwenn Sie nicht weiterkommen , ohne die ehemaligen und glücklich mit Grenzen für die Dateigrößen können Sie mit der Arbeit) sind der richtige Weg , um die Länge einer Datei zu bestimmen. stat-basierte Lösungen funktionieren nicht auf vielen "Dateien" (z. B. Blockgeräten) und sind nicht auf nicht POSIX-ähnliche Systeme portierbar.
R .. GitHub STOP HELPING ICE
1
Dies ist die einzige Möglichkeit, die Dateigröße auf vielen nicht posix-kompatiblen Systemen (wie meinem sehr minimalistischen mbed) zu ermitteln
Earlz
9
POSIX
Der POSIX- Standard verfügt über eine eigene Methode zum Abrufen der Dateigröße.
Fügen Sie den sys/stat.hHeader ein, um die Funktion zu verwenden.
Hinweis : Die Größe wird auf begrenzt 4GB. Wenn nicht Fat32Dateisystem, dann verwenden Sie die 64-Bit-Version!
#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)
Das ANSI C bietet nicht direkt die Möglichkeit, die Länge der Datei zu bestimmen.
Wir müssen unseren Verstand benutzen. Im Moment verwenden wir den Suchansatz!
Und wenn Sie eine Windows-App erstellen , verwenden Sie die GetFileSizeEx- API, da die CRT-Datei-E / A aufgrund von Besonderheiten bei der Dateidarstellung auf verschiedenen Systemen unübersichtlich ist, insbesondere zum Bestimmen der Dateilänge.
Das ist nicht Standard C. Es ist Teil des POSIX-Standards, aber nicht des C-Standards.
Derek Park
3
Bei einer schnellen Suche in Google wurde eine Methode mit fseek und ftell gefunden sowie einen Thread mit dieser Frage mit Antworten, die auf andere Weise nicht nur in C ausgeführt werden können.
Sie können eine Portabilitätsbibliothek wie NSPR (die Bibliothek, die Firefox unterstützt) verwenden oder deren Implementierung überprüfen (ziemlich haarig).
Ich habe diesen Code verwendet, um die Dateilänge zu ermitteln.
//opens a file with a file descriptorFILE* i_file;
i_file = fopen(source,"r");//gets a long from the file descriptor for fstatlong f_d = fileno(i_file);struct stat buffer;
fstat(f_d,&buffer);//stores file sizelong file_length = buffer.st_size;
fclose(i_file);
Suchen Sie zunächst bis zum Ende der Datei. Geben Sie dann an, wo sich der Dateizeiger befindet. Zuletzt (dies ist optional) wird zum Anfang der Datei zurückgespult. Beachten Sie, dassfp dies ein binärer Stream sein sollte.
file_size enthält die Anzahl der Bytes, die die Datei enthält. Da der vorzeichenlose lange Typ (laut klimits.h) auf 4294967295 Byte (4 Gigabyte) begrenzt ist, müssen Sie einen anderen Variablentyp finden, wenn Sie wahrscheinlich mit größeren Dateien arbeiten.
Wie unterscheidet sich das von Dereks Antwort von vor 8 Jahren?
PP
Dies ist ein undefiniertes Verhalten für einen Binärdatenstrom, und für einen Textdatenstrom ftellwird kein Wert zurückgegeben, der für die Anzahl der Bytes repräsentativ ist, die aus der Datei gelesen werden können.
Andrew Henle
0
Ich habe eine Funktion, die nur gut funktioniert stdio.h. Ich mag es sehr und es funktioniert sehr gut und ist ziemlich prägnant:
ftellerwartet als Argument einen Dateideskriptor, keinen Dateinamen.
Barmar
@Barmar, Nein ftellerwartet keinen Dateideskriptor, sondern einen FILE*. Siehe zuerst die Manpage!
Der Ansatz ist völlig falsch. Es ist eine Konstante, ftelldie 0jedes Mal zurückkehren würde!
Diese Antwort ist völlig falsch, da Sie zum einen fseek()zuerst das Ende der Datei suchen müssen und außerdem eine Zeichenfolge ftell()erwarten FILE *, keine Zeichenfolge! Es wäre gut, wenn Sie Ihre Antwort konkretisieren würden.
char* file
, warum nichtFILE* file
? -1Antworten:
Basierend auf dem Code von NilObject:
Änderungen:
const char
.struct stat
Definition wurde korrigiert , bei der der Variablenname fehlte.-1
bei Fehler statt zurück0
, was für eine leere Datei nicht eindeutig wäre.off_t
ist ein signierter Typ, daher ist dies möglich.Wenn Sie
fsize()
eine Fehlermeldung drucken möchten , können Sie Folgendes verwenden:Auf 32-Bit-Systemen sollten Sie dies mit der Option kompilieren
-D_FILE_OFFSET_BITS=64
, da sonstoff_t
nur Werte bis zu 2 GB gespeichert werden. Weitere Informationen finden Sie im Abschnitt "Verwenden von LFS" der Unterstützung großer Dateien unter Linux .quelle
fseek
+,ftell
wie von Derek vorgeschlagen.fseek
+,ftell
wie von Derek vorgeschlagen. Nein. Der C-Standard besagt ausdrücklich, dassfseek()
toSEEK_END
in einer Binärdatei ein undefiniertes Verhalten ist. 7.19.9.2 Diefseek
Funktion ... Ein binärer Stream mussfseek
Aufrufe mit einem Woher-Wert vonSEEK_END
und, wie unten angegeben, aus Fußnote 234 auf S. 22 nicht sinnvoll unterstützen . 267 des C - Standard verbunden ist , und welche spezifisch Etikettenfseek
zuSEEK_END
in einem Binärstrom als undefiniertes Verhalten. .Nicht benutzen
int
. Dateien mit einer Größe von mehr als 2 Gigabyte sind heutzutage als Schmutz üblichNicht benutzen
unsigned int
. Dateien mit einer Größe von mehr als 4 Gigabyte sind häufig als etwas weniger häufig vorkommender SchmutzIIRC Die Standardbibliothek definiert
off_t
als vorzeichenlose 64-Bit-Ganzzahl, die jeder verwenden sollte. Wir können das in ein paar Jahren auf 128 Bit neu definieren, wenn 16 Exabyte-Dateien herumhängen.Wenn Sie unter Windows arbeiten, sollten Sie GetFileSizeEx verwenden - es wird tatsächlich eine vorzeichenbehaftete 64-Bit-Ganzzahl verwendet, sodass Probleme mit 8 Exabyte-Dateien auftreten. Dummes Microsoft! :-)
quelle
Matts Lösung sollte funktionieren, außer dass es C ++ anstelle von C ist und das anfängliche Tell nicht notwendig sein sollte.
Reparierte auch deine Zahnspange für dich. ;)
Update: Dies ist nicht wirklich die beste Lösung. Es ist auf 4 GB-Dateien unter Windows beschränkt und wahrscheinlich langsamer als nur ein plattformspezifischer Aufruf wie
GetFileSizeEx
oderstat64
.quelle
long int
von zurückftell()
.(unsigned long)
Das Gießen verbessert die Reichweite nicht, da sie bereits durch die Funktion begrenzt ist.ftell()
Rückgabe -1 bei Fehler und das wird mit der Besetzung verschleiert. Schlagen Sie vorfsize()
, den gleichen Typ wie zurückzugebenftell()
.** Tu das nicht ( warum? ):
Ändern Sie die Definition in int, damit Fehlermeldungen übertragen werden können, und verwenden Sie dann
fseek()
undftell()
, um die Dateigröße zu bestimmen.quelle
fseeko
undftello
(oderfseek
undftell
wenn Sie nicht weiterkommen , ohne die ehemaligen und glücklich mit Grenzen für die Dateigrößen können Sie mit der Arbeit) sind der richtige Weg , um die Länge einer Datei zu bestimmen.stat
-basierte Lösungen funktionieren nicht auf vielen "Dateien" (z. B. Blockgeräten) und sind nicht auf nicht POSIX-ähnliche Systeme portierbar.POSIX
Der POSIX- Standard verfügt über eine eigene Methode zum Abrufen der Dateigröße.
Fügen Sie den
sys/stat.h
Header ein, um die Funktion zu verwenden.Zusammenfassung
stat(3)
.st_size
Eigenschaft.Beispiele
Hinweis : Die Größe wird auf begrenzt
4GB
. Wenn nichtFat32
Dateisystem, dann verwenden Sie die 64-Bit-Version!ANSI C (Standard)
Das ANSI C bietet nicht direkt die Möglichkeit, die Länge der Datei zu bestimmen.
Wir müssen unseren Verstand benutzen. Im Moment verwenden wir den Suchansatz!
Zusammenfassung
fseek(3)
.ftell(3)
.Beispiel
quelle
struct _stat64
und__stat64()
für _Windows.Und wenn Sie eine Windows-App erstellen , verwenden Sie die GetFileSizeEx- API, da die CRT-Datei-E / A aufgrund von Besonderheiten bei der Dateidarstellung auf verschiedenen Systemen unübersichtlich ist, insbesondere zum Bestimmen der Dateilänge.
quelle
Wenn Sie mit der Verwendung der Standard-C-Bibliothek einverstanden sind:
quelle
Bei einer schnellen Suche in Google wurde eine Methode mit fseek und ftell gefunden sowie einen Thread mit dieser Frage mit Antworten, die auf andere Weise nicht nur in C ausgeführt werden können.
Sie können eine Portabilitätsbibliothek wie NSPR (die Bibliothek, die Firefox unterstützt) verwenden oder deren Implementierung überprüfen (ziemlich haarig).
quelle
Ich habe diesen Code verwendet, um die Dateilänge zu ermitteln.
quelle
Versuche dies --
Suchen Sie zunächst bis zum Ende der Datei. Geben Sie dann an, wo sich der Dateizeiger befindet. Zuletzt (dies ist optional) wird zum Anfang der Datei zurückgespult. Beachten Sie, dass
fp
dies ein binärer Stream sein sollte.file_size enthält die Anzahl der Bytes, die die Datei enthält. Da der vorzeichenlose lange Typ (laut klimits.h) auf 4294967295 Byte (4 Gigabyte) begrenzt ist, müssen Sie einen anderen Variablentyp finden, wenn Sie wahrscheinlich mit größeren Dateien arbeiten.
quelle
ftell
wird kein Wert zurückgegeben, der für die Anzahl der Bytes repräsentativ ist, die aus der Datei gelesen werden können.Ich habe eine Funktion, die nur gut funktioniert
stdio.h
. Ich mag es sehr und es funktioniert sehr gut und ist ziemlich prägnant:quelle
Hier ist eine einfache und saubere Funktion, die die Dateigröße zurückgibt.
quelle
Sie können die Datei öffnen und mit dem Versatz 0 vom unteren Rand der Datei auf 0 gehen
Der von fseek zurückgegebene Wert entspricht der Größe der Datei.
Ich habe lange nicht in C codiert, aber ich denke, es sollte funktionieren.
quelle
Wenn Sie sich die Frage ansehen,
ftell
können Sie leicht die Anzahl der Bytes ermitteln.quelle
ftell
erwartet als Argument einen Dateideskriptor, keinen Dateinamen.ftell
erwartet keinen Dateideskriptor, sondern einenFILE*
. Siehe zuerst die Manpage!ftell
die0
jedes Mal zurückkehren würde!fseek()
zuerst das Ende der Datei suchen müssen und außerdem eine Zeichenfolgeftell()
erwartenFILE *
, keine Zeichenfolge! Es wäre gut, wenn Sie Ihre Antwort konkretisieren würden.