Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: Desiresportal en 2 Noviembre 2018, 14:07 pm



Título: Lidiar con archivos largos en C++
Publicado por: Desiresportal en 2 Noviembre 2018, 14:07 pm
He terminado un programa y me he topado con un par de bugs.

Uno de ellos tiene que ver con obtener el tamaño de un archivo. Utilizo el siguiente codigo para obtener el tamaño del archivo:

Código
  1.  
  2. #define __USE_FILE_OFFSET64
  3. #define __USE_LARGEFILE64
  4. #define __USE_LARGEFILE
  5.  
  6. // Mucho codigo despues...
  7.  
  8. unsigned int getFileSize(string fileName) {
  9.    unsigned int tempReturn = 0;
  10.  
  11.    FILE *temp = fopen64(fileName.c_str(), "rb");
  12.  
  13.    if (temp != NULL) {
  14.        feeko64(temp, 0, SEEK_END);
  15.        tempReturn = ftello64(temp);
  16.        fclose(temp);
  17.    }
  18.  
  19.    return tempReturn;
  20. }
  21.  
  22.  

El caso es que pese a usar "fopen64()" e incluir los "#define" para usar archivos largos, no supera los 2GB. Estoy haciendo pruebas con un archivo de 2,7GB y me dice que el tamaño es de 2GB.

¿Alguna idea de como puedo solucionarlo?

Lo incluyo todo correctamente y el compilador no me da ningun error. ¿Tendría que añadir algun parametro mas a la orden de compilado?

Uso ubuntu y codeblocks. Supongo que esto es portable a Windows y para mi proximo proyecto necesito dejarlo zanjado porque lo desarrollaré para ambos sistemas operativos.


Título: Re: Lidiar con archivos largos en C++
Publicado por: huchoko en 2 Noviembre 2018, 17:15 pm
Creo que el error es la variable tempReturn, la cúal es un int sin signo, pero es extraño, ya que un integer sin signo debería tener un rango de 4294967296.
Has tratado con un double o float (https://www.tutorialspoint.com/cplusplus/cpp_data_types.htm)? Eso si, esos tipos de datos son flotantes, pero creo que resolverá tu problema.


Título: Re: Lidiar con archivos largos en C++
Publicado por: Desiresportal en 2 Noviembre 2018, 18:57 pm
Nada. Con Double o Float me lanza un error de compilacion diciendo algo del "unsigned". Me parece que dice que no se pueden combinar.

De todos modos, me parece que eso no debería ser problema. Me parece que el problema viene de las funciones FILE. Ya probe tambien a usar "tempReturn++;" para comprobar si el limite venía del "unsigned int", pero no pasaba nada fuera de lo normal. Solo devolvía un byte por encima de los 2GB.

¿Alguna otra idea?


Título: Re: Lidiar con archivos largos en C++
Publicado por: elgilun en 2 Noviembre 2018, 20:53 pm
Desde C++17 está disponible la librería <filesystem> o para algún estándar anterior está también boost::filesystem

Se puede usar directamente file_size()

Código:
#include <filesystem>

uintmax_t getFileSize(const std::string& fileName)
{
    return std::filesystem::file_size(fileName);
}


Título: Re: Lidiar con archivos largos en C++
Publicado por: Desiresportal en 3 Noviembre 2018, 15:30 pm
Personalmente prefiero usar un codigo algo enrevesado que andar usando librerias extra. Mas que nada para poder mover el codigo fuente entre maquinas y no tener que andar instalando en todas ellas todas las liberias posibles.

He visto que tengo una funcion llamada "filength()". ¿Esa me servirá para este caso concreto?

De todos modos, sigo teniendo el problema de leer y escribir mas allá de los 2GB. En el ejemplo que he puesto solo necesito el tamaño del archivo, pero mas adelante voy a necesitar la opcion de trabajar con archivos de un tamaño superior a los 2GB. Ese es el verdadero problema.


Título: Re: Lidiar con archivos largos en C++
Publicado por: huchoko en 3 Noviembre 2018, 15:43 pm
De casualidad estás en una PC de 32 bits?


Título: Re: Lidiar con archivos largos en C++
Publicado por: Desiresportal en 3 Noviembre 2018, 19:02 pm
Uso maquinas de 32 bits, 64 bits y ARM. Para el desarrollo de este programa estoy usando una maquina de 64 bits.

Dudo mucho que un sistema operativo de 32 bits sea quien limite el uso de archivos superiores a 2GB. ¿A caso no puedes ver videos de mas de 2GB en un equipo de 32 bits?

Pues de eso va la cosa. De eliminar esa limitacion que no sé de donde viene y poder trasladar el codigo fuente sin tener que instalar librerias extra en el resto de maquinas. Y finalmente poder usar el programa compilado en maquinas de 32 bits, 64 bits y ARM.


Título: Re: Lidiar con archivos largos en C++
Publicado por: elgilun en 3 Noviembre 2018, 20:14 pm
<filesystem> es estándar C++, es como usar cout o cin, nada más portable.


Título: Re: Lidiar con archivos largos en C++
Publicado por: Desiresportal en 4 Noviembre 2018, 13:35 pm
"#include <filesystem>" no me funciona. Codeblocks no me la reconoce como una libreria existente.

Tambien he probado a leer caracter por caracter con "fgetc()" para asegurarme que el problema no venía de "fseeko64()" y un posible limite. La conclusion es que cualquier operacion con el sistema de archivos supone un problema para archivos mayores de 2GB.

Ya no sé que mas hacer sin instalar librerias extra.


Título: Re: Lidiar con archivos largos en C++
Publicado por: elgilun en 4 Noviembre 2018, 15:30 pm
Codeblocks no es un compilador, es un editor para código que usa un compilador.

Deberías poder actualizar tu compilador (un gcc 8, por ejemplo) y verificar que en las propiedades de tu proyecto se incluya la opción "-std=c++1z" o "-std=c++17".

Suerte


Título: Re: Lidiar con archivos largos en C++
Publicado por: Desiresportal en 4 Noviembre 2018, 15:55 pm
Ahora que lo acabo de mirar he visto una lista de compiladores mas larga que la que ví la ultima vez (antes solo había un compilador. El que traía Ubuntu, creo.).

Pero en el compilador GNU GCC no veo esas propiedades. Veo todas las anteriores.

- c++98
- c++11
- c++14
- c++0x
- c99
- ansi
- m32 (que yo recuerde esto era incompatible con el compilador ARM)
- m64

Esta lista la veo en "compiler flags" ya que realmente no genero ningun proyecto. Me gusta usar scripts directamente sin tener que andar con el asistente para proyectos y demas. Eso lo dejo para cuando quiero darle un icono al ejecutable y cosas así. Por lo general, cuando he terminado un programa y quiero dejarlo "pulido", por así decirlo.


Título: Re: Lidiar con archivos largos en C++
Publicado por: Desiresportal en 5 Noviembre 2018, 12:25 pm
Anoche pensé que tal vez el problema venía de usar la libreria equivocada. Pero he probado a usar "fstream" y mas de lo mismo. Es mas, no he conseguido abrir el archivo siguiendo la ruta apropiada. He tenido que sacar el archivo a la misma carpeta que el ejecutable para que este pudiese abrirlo. Y aun así sigo teniendo el limite de los 2GB.

¿Que hago?


Título: Re: Lidiar con archivos largos en C++
Publicado por: Desiresportal en 5 Noviembre 2018, 13:14 pm
Jajajajajajaja!!.....

Podeis imaginaros un facepalm epico como el que nunca se haya visto hasta ahora. Así sigo aún.

Usaba un float para comprobar el resultado y al sacarlo en consola salía un numero entero debido a que usaba "itoa()". Eso convertia el float en entero para sacarlo en texto.

Fallo mio. Espero que no me vuelva a ocurrir.

Muchas gracias por la ayuda. Ya decía yo que era muy raro que a todos les funcionase y a mi no...

Doy el tema por resuelto. Muchas gracias por la ayuda.


Título: Re: Lidiar con archivos largos en C++
Publicado por: AlbertoBSD en 5 Noviembre 2018, 22:11 pm
Que bueno que lo solucionaste.

Saludos!