Będziesz musiał użyć funkcji biblioteki, aby pobrać szczegóły pliku. Ponieważ C jest całkowicie niezależny od platformy, musisz nam powiedzieć, dla jakiej platformy / systemu operacyjnego tworzysz!
Chris Roberts,
Dlaczego char* filenie FILE* file? -1
Pan Oscar,
-1, ponieważ funkcje plików powinny akceptować deskryptory plików, a nie ścieżki do plików
Pan Oscar
Odpowiedzi:
144
Na podstawie kodu 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;}
Zmiany:
Zmieniono argument nazwa pliku na const char.
Poprawiono struct statdefinicję, w której brakowało nazwy zmiennej.
Zwraca -1w przypadku błędu zamiast 0, co byłoby niejednoznaczne dla pustego pliku. off_tjest typem ze znakiem, więc jest to możliwe.
Jeśli chcesz fsize()wydrukować komunikat o błędzie, możesz użyć tego:
#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;}
W systemach 32-bitowych należy to skompilować z opcją -D_FILE_OFFSET_BITS=64, w przeciwnym razie off_tbędą przechowywane tylko wartości do 2 GB. Szczegółowe informacje można znaleźć w sekcji „Korzystanie z LFS” w dokumencie Obsługa dużych plików w systemie Linux .
Jest to specyficzne dla systemu Linux / Unix - prawdopodobnie warto na to zwrócić uwagę, ponieważ pytanie nie określało systemu operacyjnego.
Drew Hall
1
Prawdopodobnie możesz zmienić typ zwracania na ssize_t i rzutować rozmiar z off_t bez żadnych problemów. Wydaje się, że bardziej sensowne byłoby użycie ssize_t :-) (nie mylić z size_t, który jest bez znaku i nie może być użyty do wskazania błędu.)
Ted Percival
1
Aby uzyskać bardziej przenośny kod, użyj fseek+ ftellzgodnie z propozycją Dereka.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
9
Aby uzyskać bardziej przenośny kod, użyj fseek+ ftellzgodnie z propozycją Dereka. Nie C Standardowy wyraźnie stanowi, że fseek()aby SEEK_ENDna plik binarny jest niezdefiniowane zachowanie. 7.19.9.2 fseekFunkcja ... Strumień binarny nie musi w znaczący sposób obsługiwać fseekwywołań o wartości pochodzeniaSEEK_END i, jak wspomniano poniżej, z przypisu 234 na str. 267 połączonego C standardowa, która specyficznie etykiet fseekdo SEEK_ENDw binarnego strumienia niezdefiniowana zachowanie. .
Andrew Henle,
74
Nie używaj int. Pliki o rozmiarze ponad 2 gigabajtów są obecnie powszechne jako brud
Nie używaj unsigned int. Pliki o rozmiarze powyżej 4 gigabajtów są powszechne jako nieco mniej powszechny brud
IIRC biblioteka standardowa definiuje off_tjako 64-bitową liczbę całkowitą bez znaku, której każdy powinien używać. Możemy przedefiniować to na 128 bitów w ciągu kilku lat, kiedy zaczniemy trzymać w pobliżu 16 eksabajtów.
Jeśli korzystasz z systemu Windows, powinieneś użyć GetFileSizeEx - w rzeczywistości używa on 64-bitowej liczby całkowitej ze znakiem, więc zaczną napotykać problemy z 8 plikami eksabajtowymi. Głupi Microsoft! :-)
Użyłem kompilatorów, w których off_t to 32 bity. To prawda, dotyczy to systemów wbudowanych, w których pliki 4 GB są mniej powszechne. W każdym razie POSIX definiuje również off64_t i odpowiednie metody, które mogą być przyczyną zamieszania.
Aaron Campbell
Zawsze uwielbiam odpowiedzi, które zakładają Windows i nie robię nic poza krytyką pytania. Czy mógłbyś dodać coś, co jest zgodne z POSIX?
SS Anne
1
@ JL2210 zaakceptowana odpowiedź od Teda Percivala pokazuje rozwiązanie zgodne z Posix, więc nie widzę sensu powtarzania tego, co oczywiste. Ja (i 70 innych) uważałem, że dodanie uwagi o oknach i niestosowanie 32-bitowych liczb całkowitych ze znakiem do reprezentowania rozmiarów plików było dodatkowym dodatkiem. Pozdrawiam
Orion Edwards
30
Rozwiązanie Matta powinno działać, z tym wyjątkiem, że jest to C ++ zamiast C, a początkowe polecenie tell nie powinno być konieczne.
unsignedlong fsize(char* file){FILE* f = fopen(file,"r");
fseek(f,0, SEEK_END);unsignedlong len =(unsignedlong)ftell(f);
fclose(f);return len;}
Naprawiono też aparat ortodontyczny. ;)
Aktualizacja: to naprawdę nie jest najlepsze rozwiązanie. Jest ograniczony do plików 4 GB w systemie Windows i prawdopodobnie działa wolniej niż zwykłe wywołanie specyficzne dla platformy, takie jak GetFileSizeExlub stat64.
Tak, powinieneś. Jednak jeśli nie ma naprawdę ważnego powodu, aby nie pisać specyficznej dla platformy, prawdopodobnie powinieneś po prostu użyć wywołania specyficznego dla platformy, a nie wzorca open / seek-end / tell / close.
Derek Park
1
Przepraszam za późną odpowiedź, ale mam tutaj poważny problem. Powoduje zawieszanie się aplikacji podczas uzyskiwania dostępu do plików z ograniczeniami (takich jak pliki chronione hasłem lub pliki systemowe). Czy w razie potrzeby można poprosić użytkownika o hasło?
Justin
@Justin, prawdopodobnie powinieneś otworzyć nowe pytanie dotyczące konkretnego problemu i podać szczegółowe informacje na temat platformy, na której się znajdujesz, sposobu uzyskiwania dostępu do plików i zachowania.
Derek Park
1
Zarówno C99, jak i C11 powracają long intz ftell(). (unsigned long)rzucanie nie poprawia zasięgu, który jest już ograniczony przez funkcję. ftell()zwraca -1 w przypadku błędu i to zostaje zaciemnione przy rzutowaniu. Zaproponuj fsize()zwrot tego samego typu coftell() .
chux - Przywróć Monikę
Zgadzam się. Obsada miała pasować do oryginalnego prototypu w pytaniu. Nie pamiętam jednak, dlaczego zmieniłem go na unsigned long zamiast unsigned int.
Cytując standardowy dokument C99, który znalazłem online: „Ustawienie wskaźnika pozycji pliku na koniec pliku, tak jak w przypadku fseek(file, 0, SEEK_END), ma niezdefiniowane zachowanie dla strumienia binarnego (z powodu możliwych końcowych znaków zerowych) lub dowolnego strumienia z kodowaniem zależnym od stanu to z pewnością nie kończy się w początkowym stanie zmiany. **
Zmień definicję na int, aby można było przesyłać komunikaty o błędach, a następnie użyj fseek()i, ftell()aby określić rozmiar pliku.
@mezhaka: Ten raport CERT jest po prostu błędny. fseekoi ftello(lub fseeki ftelljeśli utkniesz bez poprzedniego i zadowolony z ograniczeniami rozmiary plików można pracować z) jest poprawny sposób określenia długości pliku. statrozwiązania oparte na systemie nie działają na wielu "plikach" (takich jak urządzenia blokowe) i nie są przenośne do systemów innych niż POSIX-ish.
R .. GitHub STOP HELPING ICE
1
To jedyny sposób, aby uzyskać rozmiar pliku na wielu systemach niezgodnych z POSIX (takich jak mój bardzo minimalistyczny mbed)
Earlz
9
POSIX
Standard POSIX ma własną metodę uzyskiwania rozmiaru pliku.
Dołącz sys/stat.hnagłówek, aby użyć funkcji.
Uwaga : ogranicza rozmiar do 4GB. Jeśli nie jest to Fat32system plików, użyj wersji 64-bitowej!
#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)
ANSI C. bezpośrednio nie zapewnia drogę do określenia długości pliku.
Będziemy musieli użyć naszego umysłu. Na razie użyjemy metody wyszukiwania!
A jeśli tworzysz aplikację dla Windows, użyj GetFileSizeEx API, ponieważ I / O pliku CRT jest niechlujne, szczególnie przy określaniu długości pliku, ze względu na osobliwości reprezentacji plików na różnych systemach;)
To nie jest standard C. Jest częścią standardu POSIX, ale nie jest standardem C.
Derek Park
3
Szybkie wyszukiwanie w Google znalazło metodę wykorzystującą fseek i ftell oraz wątek z tym pytaniem z odpowiedziami, że nie można tego zrobić w C w inny sposób.
Możesz użyć biblioteki przenośności, takiej jak NSPR (biblioteka, która obsługuje przeglądarkę Firefox) lub sprawdzić jej implementację (raczej włochata).
Użyłem tego zestawu kodu, aby znaleźć długość pliku.
//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);
To, co to robi, to najpierw szukanie do końca pliku; następnie zgłoś, gdzie znajduje się wskaźnik pliku. Na koniec (jest to opcjonalne) przewija się z powrotem do początku pliku. Zwróć na to uwagęfp powinien to być strumień binarny.
file_size zawiera liczbę bajtów, które zawiera plik. Zwróć uwagę, że ponieważ (według climits.h) typ long unsigned jest ograniczony do 4294967295 bajtów (4 gigabajty), musisz znaleźć inny typ zmiennej, jeśli masz do czynienia z plikami większymi niż to.
Jest to niezdefiniowane zachowanie dla strumienia binarnego, a dla strumienia tekstowego ftellnie zwraca wartości reprezentującej liczbę bajtów, które można odczytać z pliku.
Andrew Henle
0
Mam funkcję, która działa dobrze tylko z stdio.h. Bardzo mi się podoba i działa bardzo dobrze i jest dość zwięzły:
ftelloczekuje deskryptora pliku, a nie nazwy pliku jako argumentu.
Barmar
@Barmar, No ftellnie oczekuje deskryptora pliku, oczekuje FILE*zamiast tego. Najpierw zobacz stronę podręcznika!
Podejście jest całkowicie błędne, jest stałe, ftellże powróci 0za każdym razem!
Ta odpowiedź jest całkowicie błędna, ponieważ po pierwsze, musisz użyć fseek()najpierw do wyszukania końca pliku, a także ftell()oczekuje , że FILE *nie ma ciągu! Dobrze by było, gdybyś uściślił swoją odpowiedź.
char* file
nieFILE* file
? -1Odpowiedzi:
Na podstawie kodu NilObject:
Zmiany:
const char
.struct stat
definicję, w której brakowało nazwy zmiennej.-1
w przypadku błędu zamiast0
, co byłoby niejednoznaczne dla pustego pliku.off_t
jest typem ze znakiem, więc jest to możliwe.Jeśli chcesz
fsize()
wydrukować komunikat o błędzie, możesz użyć tego:W systemach 32-bitowych należy to skompilować z opcją
-D_FILE_OFFSET_BITS=64
, w przeciwnym razieoff_t
będą przechowywane tylko wartości do 2 GB. Szczegółowe informacje można znaleźć w sekcji „Korzystanie z LFS” w dokumencie Obsługa dużych plików w systemie Linux .źródło
fseek
+ftell
zgodnie z propozycją Dereka.fseek
+ftell
zgodnie z propozycją Dereka. Nie C Standardowy wyraźnie stanowi, żefseek()
abySEEK_END
na plik binarny jest niezdefiniowane zachowanie. 7.19.9.2fseek
Funkcja ... Strumień binarny nie musi w znaczący sposób obsługiwaćfseek
wywołań o wartości pochodzeniaSEEK_END
i, jak wspomniano poniżej, z przypisu 234 na str. 267 połączonego C standardowa, która specyficznie etykietfseek
doSEEK_END
w binarnego strumienia niezdefiniowana zachowanie. .Nie używaj
int
. Pliki o rozmiarze ponad 2 gigabajtów są obecnie powszechne jako brudNie używaj
unsigned int
. Pliki o rozmiarze powyżej 4 gigabajtów są powszechne jako nieco mniej powszechny brudIIRC biblioteka standardowa definiuje
off_t
jako 64-bitową liczbę całkowitą bez znaku, której każdy powinien używać. Możemy przedefiniować to na 128 bitów w ciągu kilku lat, kiedy zaczniemy trzymać w pobliżu 16 eksabajtów.Jeśli korzystasz z systemu Windows, powinieneś użyć GetFileSizeEx - w rzeczywistości używa on 64-bitowej liczby całkowitej ze znakiem, więc zaczną napotykać problemy z 8 plikami eksabajtowymi. Głupi Microsoft! :-)
źródło
Rozwiązanie Matta powinno działać, z tym wyjątkiem, że jest to C ++ zamiast C, a początkowe polecenie tell nie powinno być konieczne.
Naprawiono też aparat ortodontyczny. ;)
Aktualizacja: to naprawdę nie jest najlepsze rozwiązanie. Jest ograniczony do plików 4 GB w systemie Windows i prawdopodobnie działa wolniej niż zwykłe wywołanie specyficzne dla platformy, takie jak
GetFileSizeEx
lubstat64
.źródło
long int
zftell()
.(unsigned long)
rzucanie nie poprawia zasięgu, który jest już ograniczony przez funkcję.ftell()
zwraca -1 w przypadku błędu i to zostaje zaciemnione przy rzutowaniu. Zaproponujfsize()
zwrot tego samego typu coftell()
.** Nie rób tego ( dlaczego? ):
Zmień definicję na int, aby można było przesyłać komunikaty o błędach, a następnie użyj
fseek()
i,ftell()
aby określić rozmiar pliku.źródło
fseeko
iftello
(lubfseek
iftell
jeśli utkniesz bez poprzedniego i zadowolony z ograniczeniami rozmiary plików można pracować z) jest poprawny sposób określenia długości pliku.stat
rozwiązania oparte na systemie nie działają na wielu "plikach" (takich jak urządzenia blokowe) i nie są przenośne do systemów innych niż POSIX-ish.POSIX
Standard POSIX ma własną metodę uzyskiwania rozmiaru pliku.
Dołącz
sys/stat.h
nagłówek, aby użyć funkcji.Streszczenie
stat(3)
.st_size
nieruchomość.Przykłady
Uwaga : ogranicza rozmiar do
4GB
. Jeśli nie jest toFat32
system plików, użyj wersji 64-bitowej!ANSI C (standard)
ANSI C. bezpośrednio nie zapewnia drogę do określenia długości pliku.
Będziemy musieli użyć naszego umysłu. Na razie użyjemy metody wyszukiwania!
Streszczenie
fseek(3)
.ftell(3)
.Przykład
źródło
struct _stat64
i__stat64()
dla _Windows.A jeśli tworzysz aplikację dla Windows, użyj GetFileSizeEx API, ponieważ I / O pliku CRT jest niechlujne, szczególnie przy określaniu długości pliku, ze względu na osobliwości reprezentacji plików na różnych systemach;)
źródło
Jeśli nie masz nic przeciwko korzystaniu z biblioteki std c:
źródło
Szybkie wyszukiwanie w Google znalazło metodę wykorzystującą fseek i ftell oraz wątek z tym pytaniem z odpowiedziami, że nie można tego zrobić w C w inny sposób.
Możesz użyć biblioteki przenośności, takiej jak NSPR (biblioteka, która obsługuje przeglądarkę Firefox) lub sprawdzić jej implementację (raczej włochata).
źródło
Użyłem tego zestawu kodu, aby znaleźć długość pliku.
źródło
Spróbuj tego --
To, co to robi, to najpierw szukanie do końca pliku; następnie zgłoś, gdzie znajduje się wskaźnik pliku. Na koniec (jest to opcjonalne) przewija się z powrotem do początku pliku. Zwróć na to uwagę
fp
powinien to być strumień binarny.file_size zawiera liczbę bajtów, które zawiera plik. Zwróć uwagę, że ponieważ (według climits.h) typ long unsigned jest ograniczony do 4294967295 bajtów (4 gigabajty), musisz znaleźć inny typ zmiennej, jeśli masz do czynienia z plikami większymi niż to.
źródło
ftell
nie zwraca wartości reprezentującej liczbę bajtów, które można odczytać z pliku.Mam funkcję, która działa dobrze tylko z
stdio.h
. Bardzo mi się podoba i działa bardzo dobrze i jest dość zwięzły:źródło
Oto prosta i przejrzysta funkcja, która zwraca rozmiar pliku.
źródło
Możesz otworzyć plik, przejść do przesunięcia 0 względem dołu pliku za pomocą
wartość zwracana przez fseek to rozmiar pliku.
Długo nie kodowałem w C, ale myślę, że powinno działać.
źródło
Patrząc na pytanie,
ftell
można łatwo uzyskać liczbę bajtów.źródło
ftell
oczekuje deskryptora pliku, a nie nazwy pliku jako argumentu.ftell
nie oczekuje deskryptora pliku, oczekujeFILE*
zamiast tego. Najpierw zobacz stronę podręcznika!ftell
że powróci0
za każdym razem!fseek()
najpierw do wyszukania końca pliku, a takżeftell()
oczekuje , żeFILE *
nie ma ciągu! Dobrze by było, gdybyś uściślił swoją odpowiedź.