2017-01-18 5 views
2
#include <fstream> 
#include <string> 
#include <cassert> 

long long GetFileSizeA(const std::string& file_path) 
{ 
    return std::ifstream 
    { 
     file_path, std::ios::ate  
    }.tellg(); 
} 

long long GetFileSizeB(const std::string& file_path) 
{ 
    return std::ifstream 
    { 
     file_path, std::ios::ate | std::ios::binary 
    }.tellg(); 
} 

int main() 
{ 
    auto a = GetFileSizeA("~/test.log"); 
    auto b = GetFileSizeB("~/test.log"); 

    assert(a == b); // always true? 
} 

Si le fichier contient de nombreuses ~/test.log\r\n séquences, ne la norme C de garantie GetFileSizeA est identique à GetFileSizeB?Dois-je ouvrir un fichier en mode [ios :: binaire] pour obtenir sa taille?

Répondre

1

la norme ne en aucun cas garantir que les deux sont égaux (ni le C ou état standard C++ si les fichiers contiennent \r\n ou \n ou \r que la ligne de fin, qui est définie par le système d'exploitation et/ou de l'application. La bibliothèque C standard, et par extension, la bibliothèque C++, garantit que si vous lisez le fichier en mode texte, il transformera toutes les fins de ligne réelles, dans le formulaire interne \n). Cela ne garantit pas non plus que ce n'est pas toujours la même valeur. Plus important encore, vous trouverez peut-être que si vous lisez une partie du fichier et demandez "où suis-je", que la réponse est différente entre si vous lisez en tant que fichier binaire ou en tant que fichier ASCII. Si vous envisagez par exemple de mapper le fichier en mémoire et de le traiter comme une grande chaîne de caractères, sans traduire les nouvelles lignes, vous devez le faire en tant que fichier binaire.

1

Il n'existe pas de telle garantie par la norme C++.

En fait, le code

std::ifstream{file_path, std::ios::ate | std::ios::binary}.tellg(); 

est pas garanti comme prévu, non plus. L'opération tellg() sur les flux basés sur des fichiers se résume à quelques fonctions intermédiaires (std::basic_istream::tellg ->std::basic_streambuf::pubseekoff ->std::basic_filebuf::seekoff) et l'utilisation de la formulation 'comme' à std::fseek(). Ce dernier isn't required to support seeking in binary streams relative to the end position:

int fseek(std::FILE* stream, long offset, int origin);

Définit l'indicateur de position de fichier pour le flux de flux de fichiers.

Si le flux est ouvert en mode binaire, la nouvelle position est exactement décalage octets mesurés à partir du début du fichier si l'origine est SEEK_SET, de la position actuelle du fichier si l'origine est SEEK_CUR, et de la fin de le fichier si l'origine est SEEK_END. Les flux binaires ne sont pas requis pour prendre en charge SEEK_END, en particulier si octets nuls supplémentaires sont sortis.