Necesitará usar una función de biblioteca para recuperar los detalles de un archivo. Como C es completamente independiente de la plataforma, ¡deberá informarnos para qué plataforma / sistema operativo está desarrollando!
Chris Roberts
¿Por qué char* file, por qué no FILE* file? -1
Sr. Oscar el
-1 porque las funciones de archivo deben aceptar descriptores de archivo, no rutas de archivo
Sr. Oscar
Respuestas:
144
Basado en el código de 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;}
Cambios:
Hizo el argumento del nombre de archivo a const char.
Se corrigió la struct statdefinición, a la que le faltaba el nombre de la variable.
Devuelve -1por error en lugar de 0, lo que sería ambiguo para un archivo vacío. off_tes un tipo con signo, por lo que esto es posible.
Si desea fsize()imprimir un mensaje de error, puede usar esto:
#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;}
En sistemas de 32 bits, debe compilar esto con la opción -D_FILE_OFFSET_BITS=64; de lo contrario off_t, solo tendrá valores de hasta 2 GB. Consulte la sección "Uso de LFS" de Soporte de archivos grandes en Linux para más detalles.
Esto es específico de Linux / Unix, probablemente valga la pena señalarlo ya que la pregunta no especificaba un sistema operativo.
Drew Hall el
1
Probablemente podría cambiar el tipo de retorno a ssize_t y emitir el tamaño desde un off_t sin ningún problema. Parecería tener más sentido usar un ssize_t :-) (No debe confundirse con size_t que no está firmado y no se puede usar para indicar un error).
Ted Percival
1
Para un código más portátil, use fseek+ ftellsegún lo propuesto por Derek.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
9
Para un código más portátil, use fseek+ ftellsegún lo propuesto por Derek. No. El C estándar establece específicamente que fseek()a SEEK_ENDen un archivo binario es un comportamiento indefinido. 7.19.9.2 La fseekfunción ... Una secuencia binaria no necesita admitir significativamente fseekllamadas con un valor de origen deSEEK_END , y como se indica a continuación, que es de la nota 234 en la p. 267 de la C Standard vinculado, y que expresamente etiquetas fseeka SEEK_ENDen una corriente binaria como un comportamiento indefinido. .
Andrew Henle
74
No utilice int. Los archivos de más de 2 gigabytes de tamaño son comunes en la actualidad.
No utilice unsigned int. Los archivos de más de 4 gigabytes de tamaño son comunes como algo de tierra un poco menos común
IIRC, la biblioteca estándar, se define off_tcomo un entero de 64 bits sin signo, que es lo que todos deberían usar. Podemos redefinir que sean 128 bits en unos pocos años cuando comencemos a tener 16 archivos exabyte dando vueltas.
Si está en Windows, debe usar GetFileSizeEx ; en realidad usa un entero de 64 bits con signo, por lo que comenzarán a resolver problemas con 8 archivos exabyte. Tonto de Microsoft! :-)
He usado compiladores donde off_t es de 32 bits. De acuerdo, esto es en sistemas integrados donde los archivos de 4GB son menos comunes. De todos modos, POSIX también define off64_t y los métodos correspondientes para agregar a la confusión.
Aaron Campbell
Siempre me encantan las respuestas que asumen Windows y no hacen nada más que criticar la pregunta. ¿Podría agregar algo que cumpla con POSIX?
SS Anne
1
@ JL2210 la respuesta aceptada de Ted Percival muestra una solución compatible con posix, por lo que no tengo sentido repetir lo obvio. Yo (y otros 70) pensé que agregar la nota sobre Windows y no usar enteros de 32 bits con signo para representar tamaños de archivo era un valor agregado. Saludos
Orion Edwards
30
La solución de Matt debería funcionar, excepto que es C ++ en lugar de C, y la información inicial no debería ser necesaria.
unsignedlong fsize(char* file){FILE* f = fopen(file,"r");
fseek(f,0, SEEK_END);unsignedlong len =(unsignedlong)ftell(f);
fclose(f);return len;}
También arregló su abrazadera para usted. ;)
Actualización: esta no es realmente la mejor solución. Está limitado a archivos de 4GB en Windows y es probable que sea más lento que usar una llamada específica de la plataforma como GetFileSizeExo stat64.
Si deberías. Sin embargo, a menos que haya una razón realmente convincente para no escribir una plataforma específica, probablemente debería usar una llamada específica de la plataforma en lugar del patrón abierto / buscar-fin / decir / cerrar.
Derek Park
1
Lamento la respuesta tardía, pero tengo un problema importante aquí. Hace que la aplicación se bloquee al acceder a archivos restringidos (como protegidos por contraseña o archivos del sistema). ¿Hay alguna manera de pedirle al usuario una contraseña cuando sea necesario?
Justin
@Justin, probablemente deberías abrir una nueva pregunta específicamente sobre el problema con el que te encuentras y proporcionar detalles sobre la plataforma en la que te encuentras, cómo estás accediendo a los archivos y cuál es el comportamiento.
Derek Park el
1
Ambos C99 y C11 regresan long intde ftell(). (unsigned long)el lanzamiento no mejora el rango ya que está limitado por la función. ftell()devuelve -1 por error y eso se ofusca con el elenco. Sugerir fsize()devolver el mismo tipo que ftell().
chux - Restablecer Monica
Estoy de acuerdo. El elenco debía coincidir con el prototipo original en la pregunta. Sin embargo, no recuerdo por qué lo convertí en unsigned long en lugar de unsigned int.
Citando el documento estándar C99 que encontré en línea: "Establecer el indicador de posición del archivo al final del archivo, como con fseek(file, 0, SEEK_END), tiene un comportamiento indefinido para una secuencia binaria (debido a posibles caracteres nulos finales) o para cualquier secuencia con codificación dependiente del estado que seguramente no termina en el estado de cambio inicial. **
Cambie la definición a int para que se puedan transmitir mensajes de error, y luego use fseek()y ftell()para determinar el tamaño del archivo.
@mezhaka: Ese informe del CERT es simplemente incorrecto. fseekoy ftello(o fseeky ftellsi le pegan sin la primera y feliz con límites en el tamaño de los archivos se puede trabajar con) es la forma correcta para determinar la longitud de un archivo. statLas soluciones basadas en sistemas no funcionan en muchos "archivos" (como dispositivos de bloque) y no son portátiles para sistemas que no son POSIX-ish.
R .. GitHub DEJA DE AYUDAR AL HIELO
1
Esta es la única forma de obtener el tamaño del archivo en muchos sistemas que no son compatibles con posix (como mi mbed muy minimalista)
Earlz
9
POSIX
El estándar POSIX tiene su propio método para obtener el tamaño del archivo.
Incluya el sys/stat.hencabezado para usar la función.
Nota : limita el tamaño a 4GB. Si no es un Fat32sistema de archivos, ¡use la versión de 64 bits!
#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 (estándar)
El ANSI C no proporciona directamente la forma de determinar la longitud del archivo.
Tendremos que usar nuestra mente. Por ahora, utilizaremos el enfoque de búsqueda.
Y si está creando una aplicación de Windows, use la API GetFileSizeEx ya que la E / S del archivo CRT es desordenada, especialmente para determinar la longitud del archivo, debido a peculiaridades en las representaciones de archivos en diferentes sistemas;)
Ese no es el estándar C. Es parte del estándar POSIX, pero no es el estándar C.
Derek Park el
3
Una búsqueda rápida en Google encontró un método usando fseek y ftell y un hilo con esta pregunta con respuestas que no se puede hacer solo en C de otra manera.
Podría usar una biblioteca de portabilidad como NSPR (la biblioteca que alimenta Firefox) o verificar su implementación (bastante complicada).
Usé este conjunto de código para encontrar la longitud del archivo.
//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);
Lo que esto hace es primero, buscar hasta el final del archivo; luego, informe dónde está el puntero del archivo. Por último (esto es opcional), se rebobina al principio del archivo. Tenga en cuenta quefp debería ser una secuencia binaria.
file_size contiene el número de bytes que contiene el archivo. Tenga en cuenta que dado que (según climits.h) el tipo largo sin signo está limitado a 4294967295 bytes (4 gigabytes) necesitará encontrar un tipo de variable diferente si es probable que maneje archivos más grandes que eso.
Ese es un comportamiento indefinido para una secuencia binaria, y para una secuencia de texto ftellno devuelve un valor representativo del número de bytes que se pueden leer del archivo.
Andrew Henle
0
Tengo una función que funciona bien solo con stdio.h. Me gusta mucho y funciona muy bien y es bastante conciso:
ftellespera un descriptor de archivo, no un nombre de archivo, como argumento.
Barmar
@Barmar, No ftellno espera un descriptor de archivo, espera un FILE*en su lugar. ¡Vea la página del manual primero!
El enfoque es completamente incorrecto, ¡es constante que ftellvolvería siempre 0!
Esta respuesta es completamente incorrecta, ya que para una, debe usarla fseek()primero para buscar el final del archivo y, además, ftell()espera una FILE *, ¡no una cadena! Estarías bien servido para desarrollar tu respuesta.
char* file
, por qué noFILE* file
? -1Respuestas:
Basado en el código de NilObject:
Cambios:
const char
.struct stat
definición, a la que le faltaba el nombre de la variable.-1
por error en lugar de0
, lo que sería ambiguo para un archivo vacío.off_t
es un tipo con signo, por lo que esto es posible.Si desea
fsize()
imprimir un mensaje de error, puede usar esto:En sistemas de 32 bits, debe compilar esto con la opción
-D_FILE_OFFSET_BITS=64
; de lo contrariooff_t
, solo tendrá valores de hasta 2 GB. Consulte la sección "Uso de LFS" de Soporte de archivos grandes en Linux para más detalles.fuente
fseek
+ftell
según lo propuesto por Derek.fseek
+ftell
según lo propuesto por Derek. No. El C estándar establece específicamente quefseek()
aSEEK_END
en un archivo binario es un comportamiento indefinido. 7.19.9.2 Lafseek
función ... Una secuencia binaria no necesita admitir significativamentefseek
llamadas con un valor de origen deSEEK_END
, y como se indica a continuación, que es de la nota 234 en la p. 267 de la C Standard vinculado, y que expresamente etiquetasfseek
aSEEK_END
en una corriente binaria como un comportamiento indefinido. .No utilice
int
. Los archivos de más de 2 gigabytes de tamaño son comunes en la actualidad.No utilice
unsigned int
. Los archivos de más de 4 gigabytes de tamaño son comunes como algo de tierra un poco menos comúnIIRC, la biblioteca estándar, se define
off_t
como un entero de 64 bits sin signo, que es lo que todos deberían usar. Podemos redefinir que sean 128 bits en unos pocos años cuando comencemos a tener 16 archivos exabyte dando vueltas.Si está en Windows, debe usar GetFileSizeEx ; en realidad usa un entero de 64 bits con signo, por lo que comenzarán a resolver problemas con 8 archivos exabyte. Tonto de Microsoft! :-)
fuente
La solución de Matt debería funcionar, excepto que es C ++ en lugar de C, y la información inicial no debería ser necesaria.
También arregló su abrazadera para usted. ;)
Actualización: esta no es realmente la mejor solución. Está limitado a archivos de 4GB en Windows y es probable que sea más lento que usar una llamada específica de la plataforma como
GetFileSizeEx
ostat64
.fuente
long int
deftell()
.(unsigned long)
el lanzamiento no mejora el rango ya que está limitado por la función.ftell()
devuelve -1 por error y eso se ofusca con el elenco. Sugerirfsize()
devolver el mismo tipo queftell()
.** No hagas esto ( ¿por qué? ):
Cambie la definición a int para que se puedan transmitir mensajes de error, y luego use
fseek()
yftell()
para determinar el tamaño del archivo.fuente
fseeko
yftello
(ofseek
yftell
si le pegan sin la primera y feliz con límites en el tamaño de los archivos se puede trabajar con) es la forma correcta para determinar la longitud de un archivo.stat
Las soluciones basadas en sistemas no funcionan en muchos "archivos" (como dispositivos de bloque) y no son portátiles para sistemas que no son POSIX-ish.POSIX
El estándar POSIX tiene su propio método para obtener el tamaño del archivo.
Incluya el
sys/stat.h
encabezado para usar la función.Sinopsis
stat(3)
.st_size
propiedad.Ejemplos
Nota : limita el tamaño a
4GB
. Si no es unFat32
sistema de archivos, ¡use la versión de 64 bits!ANSI C (estándar)
El ANSI C no proporciona directamente la forma de determinar la longitud del archivo.
Tendremos que usar nuestra mente. Por ahora, utilizaremos el enfoque de búsqueda.
Sinopsis
fseek(3)
.ftell(3)
.Ejemplo
fuente
struct _stat64
y__stat64()
para _Windows.Y si está creando una aplicación de Windows, use la API GetFileSizeEx ya que la E / S del archivo CRT es desordenada, especialmente para determinar la longitud del archivo, debido a peculiaridades en las representaciones de archivos en diferentes sistemas;)
fuente
Si está bien con el uso de la biblioteca std c:
fuente
Una búsqueda rápida en Google encontró un método usando fseek y ftell y un hilo con esta pregunta con respuestas que no se puede hacer solo en C de otra manera.
Podría usar una biblioteca de portabilidad como NSPR (la biblioteca que alimenta Firefox) o verificar su implementación (bastante complicada).
fuente
Usé este conjunto de código para encontrar la longitud del archivo.
fuente
Prueba esto --
Lo que esto hace es primero, buscar hasta el final del archivo; luego, informe dónde está el puntero del archivo. Por último (esto es opcional), se rebobina al principio del archivo. Tenga en cuenta que
fp
debería ser una secuencia binaria.file_size contiene el número de bytes que contiene el archivo. Tenga en cuenta que dado que (según climits.h) el tipo largo sin signo está limitado a 4294967295 bytes (4 gigabytes) necesitará encontrar un tipo de variable diferente si es probable que maneje archivos más grandes que eso.
fuente
ftell
no devuelve un valor representativo del número de bytes que se pueden leer del archivo.Tengo una función que funciona bien solo con
stdio.h
. Me gusta mucho y funciona muy bien y es bastante conciso:fuente
Aquí hay una función simple y limpia que devuelve el tamaño del archivo.
fuente
Puede abrir el archivo, ir a 0 desplazamiento relativo desde la parte inferior del archivo con
El valor devuelto por fseek es el tamaño del archivo.
No codifiqué en C durante mucho tiempo, pero creo que debería funcionar.
fuente
Mirando la pregunta,
ftell
puede obtener fácilmente el número de bytes.fuente
ftell
espera un descriptor de archivo, no un nombre de archivo, como argumento.ftell
no espera un descriptor de archivo, espera unFILE*
en su lugar. ¡Vea la página del manual primero!ftell
volvería siempre0
!fseek()
primero para buscar el final del archivo y, además,ftell()
espera unaFILE *
, ¡no una cadena! Estarías bien servido para desarrollar tu respuesta.