Lidiar con archivos largos en C++

Iniciado por Desiresportal, 2 Noviembre 2018, 14:07 PM

0 Miembros y 1 Visitante están viendo este tema.

Desiresportal

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 (cpp) [Seleccionar]


#define __USE_FILE_OFFSET64
#define __USE_LARGEFILE64
#define __USE_LARGEFILE

// Mucho codigo despues...

unsigned int getFileSize(string fileName) {
    unsigned int tempReturn = 0;

    FILE *temp = fopen64(fileName.c_str(), "rb");

    if (temp != NULL) {
        feeko64(temp, 0, SEEK_END);
        tempReturn = ftello64(temp);
        fclose(temp);
    }

    return tempReturn;
}



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.

huchoko

#1
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? Eso si, esos tipos de datos son flotantes, pero creo que resolverá tu problema.

Desiresportal

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?

elgilun

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()

#include <filesystem>

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


Desiresportal

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.

huchoko

De casualidad estás en una PC de 32 bits?

Desiresportal

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.

elgilun

<filesystem> es estándar C++, es como usar cout o cin, nada más portable.

Desiresportal

"#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.

elgilun

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