web-dev-qa-db-fra.com

fonction tellg () donne une mauvaise taille de fichier?

J'ai fait un exemple de projet pour lire un fichier dans un tampon. Lorsque j'utilise la fonction tellg (), cela me donne une valeur supérieure à celle de la fonctionread qui est lue dans le fichier. Je pense qu'il y a un bug. 

voici mon code:

MODIFIER:

void read_file (const char* name, int *size , char*& buffer)
{
  ifstream file;

  file.open(name,ios::in|ios::binary);
  *size = 0;
  if (file.is_open())
  {
    // get length of file
    file.seekg(0,std::ios_base::end);
    int length = *size = file.tellg();
    file.seekg(0,std::ios_base::beg);

    // allocate buffer in size of file
    buffer = new char[length];

    // read
    file.read(buffer,length);
    cout << file.gcount() << endl;
   }
   file.close();
}

principale:

void main()
{
  int size = 0;
  char* buffer = NULL;
  read_file("File.txt",&size,buffer);

  for (int i = 0; i < size; i++)
    cout << buffer[i];
  cout << endl; 
}
20
Elior

tellg ne rapporte pas la taille du fichier, ni le décalage depuis le début en octets. Il indique une valeur de jeton qui peut Être utilisée plus tard pour rechercher le même endroit, et rien de plus . (Il n'est même pas garanti que vous puissiez convertir le type en un type intégral )

Du moins en fonction de la spécification du langage: en pratique, Sur les systèmes Unix, la valeur renvoyée sera le décalage en octets Depuis le début du fichier et, sous Windows, ce sera Le décalage à partir de le début du fichier pour les fichiers ouverts en mode binaire . Pour Windows (et la plupart des systèmes non-Unix), en mode texte , Il n'y a pas de correspondance directe et immédiate entre ce que retourne tellg et le nombre d'octets que vous devez lire pour atteindre cette position. Sous Windows, tout ce sur quoi vous pouvez vraiment compter est Que la valeur ne sera pas inférieure au nombre d'octets que vous avez à lire (et dans la plupart des cas réels, ne sera pas trop supérieur, bien que cela puisse être jusqu'à deux fois plus).

S'il est important de savoir exactement combien d'octets vous pouvez lire, Le seul moyen fiable de le faire est de lire. Vous devriez être capable de le faire avec quelque chose comme:

file.ignore( std::numeric_limits<std::streamsize>::max() );
std::streamsize length = file.gcount();
file.clear();   //  Since ignore will have set eof.
file.seekg( 0, std::ios_base::beg );

Enfin, deux autres remarques concernant votre code:

Tout d'abord, la ligne:

*buffer = new char[length];

ne devriez pas compiler: vous avez déclaré buffer comme étant un char*, so *buffer est de type char et n'est pas un pointeur. Compte tenu de ce que vous semblez faire, vous voudrez probablement déclarer buffer comme A char**. Mais une bien meilleure solution serait de le déclareren tant que std::vector<char>& ou std::string&. (De cette façon, vous N'aura pas à renvoyer la taille également, et vous ne perdrez pas de mémoire S'il y a une exception.)

Deuxièmement, la condition de boucle à la fin est fausse. Si vous voulez vraiment lire un caractère à la fois,

while ( file.get( buffer[i] ) ) {
    ++ i;
}

devrait faire l'affaire. Une meilleure solution serait probablement de lire des blocs de données:

while ( file.read( buffer + i, N ) || file.gcount() != 0 ) {
    i += file.gcount();
}

ou même:

file.read( buffer, size );
size = file.gcount();

EDIT: Je viens de remarquer une troisième erreur: si vous ne parvenez pas à ouvrir le fichier , Vous ne le dites pas à l'appelant. À tout le moins, vous devriez Régler la size à 0 (mais une sorte d'erreur plus précise Le traitement est probablement préférable).

45
James Kanze

En C++ 17, il existe des méthodes et des fonctions std::filesystemfile_size, qui peuvent ainsi rationaliser l'ensemble de la tâche.

Avec ces fonctions/méthodes, il est possible de ne pas ouvrir un fichier, mais de lire les données en cache (surtout avec la méthode std::filesystem::directory_entry::file_size)

Ces fonctions ne nécessitent également que des autorisations de lecture dans les répertoires et non des autorisations de lecture de fichiers (comme le fait tellg()).

1
fen
void read_file (int *size, char* name,char* buffer)
*buffer = new char[length];

Ces lignes ressemblent à un bogue: vous créez un tableau de caractères et enregistrez dans un caractère tampon [0]. Ensuite, vous lisez un fichier dans un tampon, qui n'est toujours pas initialisé.

Vous devez passer buffer par pointeur:

void read_file (int *size, char* name,char** buffer)
*buffer = new char[length];

Ou par référence, qui est la manière c ++ et est moins sujette aux erreurs:

void read_file (int *size, char* name,char*& buffer)
buffer = new char[length];
...
0
Arks