IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Windows Discussion :

InternetReadFile ne lit pas les gros fichiers


Sujet :

Windows

  1. #1
    Membre du Club
    Inscrit en
    Mai 2006
    Messages
    126
    Détails du profil
    Informations forums :
    Inscription : Mai 2006
    Messages : 126
    Points : 54
    Points
    54
    Par défaut InternetReadFile ne lit pas les gros fichiers
    Bonjour,

    Je suis en train de developper un programme en C++ qui est sense pouvoir se mettre a jour en se connectant sur un serveur. J'ai donc ecrit une routine qui s'occupe de telecharger un fichier. Cette routine fonctionne tres bien pour des fichiers pas trop gros, comme des images GIF par exemple. Par contre j'ai besoin de telecharger un fichier d'environ 5Mo, et la ca deconne completement. Ca lit une centaine d'octets seulement. Voici ma routine:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    HINTERNET InternetSession=InternetOpen("Unamed",INTERNET_OPEN_TYPE_DIRECT,NULL,NULL,0);
    
    if (!InternetSession)
      return 0;
    
    HINTERNET OpenUrl=InternetOpenUrl(InternetSession,DownloadURL,NULL,0,0,0);
    
    if (!OpenUrl)
      return 0;
          
    DWORD RemainingBytes;
    
    if (!InternetQueryDataAvailable(OpenUrl,&RemainingBytes,0,0))
      return 0;
                
    char *File=new char[RemainingBytes];
    char *Ptr=File;
    DWORD NumBytesRead;
    bool Test;
        
    do
      {
        Test=InternetReadFile(OpenUrl,Ptr,RemainingBytes,&NumBytesRead);
        Ptr+=NumBytesRead;
        RemainingBytes-=NumBytesRead;
      } while (!Test || NumBytesRead);
    
    // Do something with File
    
    delete []File;
    InternetCloseHandle(OpenUrl);
    InternetCloseHandle(InternetSession);
    Notez que lorsque j'affiche la valeur de RemainingBytes juste apres l'appel de InternetQueryDataAvailable, je n'obtiens pas toujours la valeur correcte de la taille du fichier. Mais meme si j'initialise RemainingBytes a la main avec la taille reelle du fichier, ca ne marche quand meme pas.

    Par contre aucun probleme avec les fichiers de moins de 100ko. Une idee?

  2. #2
    Expert éminent sénior
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 068
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 068
    Points : 12 111
    Points
    12 111
    Par défaut
    Si vous sortez avec "Test == TRUE", c'est quoi la valeur de GetLastError() ?

  3. #3
    Membre du Club
    Inscrit en
    Mai 2006
    Messages
    126
    Détails du profil
    Informations forums :
    Inscription : Mai 2006
    Messages : 126
    Points : 54
    Points
    54
    Par défaut
    Citation Envoyé par bacelar Voir le message
    Si vous sortez avec "Test == TRUE", c'est quoi la valeur de GetLastError() ?
    Il me semble que je fais correctement les choses: Sur la MSDN il est clairement indique qu'il faut appeler InternetReadFile UNTIL la fonction renvoie true ET le nombre de bytes lus est nul. WHILE etant le contraire de UNTIL, la condition pour continuer doit etre le contraire de la condition pour s'arreter. Enfin le contraire de A && (!B) est bel et bien (!A) || B. Donc je pense que mon test d'arret est correct.

    Pour repondre a la question, GetLastError a la sortie de ma boucle renvoit 0. En fait InternetReadFile ne me renvoie jamais false, sauf si j'appele une fois de plus la fonction apres qu'elle ait deja returner un nombre de bytes lus nul. De plus quand j'essaye de telecharger mon fichier de 5M bytes, un seul appel a InternetReadFile me retourne soi-disant les 5M bytes de lus, et ceci instantanement.

  4. #4
    Membre régulier
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    72
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Janvier 2005
    Messages : 72
    Points : 77
    Points
    77
    Par défaut
    Bonjour,

    Dans le cas du test de votre sortie de boucle, si Test est à FALSE vous continuez à boucler. C'est pas bon je pense.

    Sinon concernant InternetQueryDataAvailable() MSDN dit :
    This function returns the number of bytes of data that are available to be read immediately by a subsequent call to InternetReadFile. If there is currently no data available and the end of the file has not been reached, the request waits until data becomes available. The amount of data remaining will not be recalculated until all available data indicated by the call to InternetQueryDataAvailable is read.
    Donc si je comprends bien vous devez faire en boucle:
    -InternetQueryDataAvailable() jusqu'à ce que RemainingBytes = 0
    -Lecture du nombre d'octets indiqué par RemainingBytes

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    BOOL Result;
    DWORD RemainingBytes;
    
    do
       {
       Result  = InternetQueryDataAvailable(HndFile,&RemainingBytes,0,0);
       if(Result && RemainingBytes)
          {
          DWORD ByteToRead = RemainingBytes;
           do
             {
             Result = InternetReadFile(HndFile,Ptr,ByteToRead,&ByteRead);
             if(Result)
                {
                ByteToRead -= ByteRead;
                Ptr += ByteRead;
                }
             }
             while(Result && ByteRead);
          }
       }
    while(Result && RemainingBytes);

  5. #5
    Membre du Club
    Inscrit en
    Mai 2006
    Messages
    126
    Détails du profil
    Informations forums :
    Inscription : Mai 2006
    Messages : 126
    Points : 54
    Points
    54
    Par défaut
    Non, j'ai essaye votre boucle, mais j'obtiens toujours le meme resultat.

    J'ai inclu dans ma boucle un test qui stoppe le programme si Test=false (car d'apres MSDN il s'agirait alors d'une erreur). Or ma variable Test reste constament vraie. Donc tous les test que je fait indiquent que tout se passe bien. Or en fait rien ne se passe. Mes tests indiquent egalement que UN SEUL appel a InternetQueryDataAvailable me donne bien la taille correcte du fichier. Ils indiquent egalement que UN SEUL appel a InternetReadFile me donne un nombre d'octets lus egal a la taille totale du fichier, et cela instantanement!!!

    Et le fichier telecharge contient tout sauf le contenu de l'original! Je ne comprends pas, ca marche tres bien avec des fichiers plus petits.

    Je suis d'accord sur le fait que
    This function returns the number of bytes of data that are available to be read immediately by a subsequent call to InternetReadFile. If there is currently no data available and the end of the file has not been reached, the request waits until data becomes available. The amount of data remaining will not be recalculated until all available data indicated by the call to InternetQueryDataAvailable is read.
    implique qu'il faut en effet inclure l'appel de InternetQueryDataAvailable dans une boucle comme celle que vous m'avez donnee. Mais dans mon cas il ne se passe qu'une seule iteration.

    Ceci me suggere d'ailleur une autre question: D'apres la MSDN on est sense pouvoir utiliser InternetQueryDataAvailable afin de determiner la taille d'un fichier AVANT de le telecharger. Mais si la fonction InternetQueryDataAvailable peut eventuellement renvoyer une valeur inferieure a la taille du fichier, comment connaitre cette taille avant de le telecharger (afin d'allouer la memoire necessaire)?

  6. #6
    Membre du Club
    Inscrit en
    Mai 2006
    Messages
    126
    Détails du profil
    Informations forums :
    Inscription : Mai 2006
    Messages : 126
    Points : 54
    Points
    54
    Par défaut
    Bon, voici un programme complet pret a etre compile. Il est sense telecharger un fichier a l'adresse que vous indiquez et le sauvegarder dans un fichier nomme "Downloaded.dat". Je vous laisse verifier que ca ne marche pas pour les gros fichiers. N'oubliez pas d'ajouter le -lwininet dans lors de la compilation:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    using namespace std;
    
    #include <iostream>
    #include <fstream>
    #include <wininet.h>
    
    char DownloadURL[]="http://AddresseDuFichier";
    
    int main(void)
      {
        HINTERNET InternetSession=InternetOpen("Unamed",INTERNET_OPEN_TYPE_DIRECT,NULL,NULL,0);
    
        if (!InternetSession)
          {
            cout << "Cannot open Internet\n";
            return 0;
          }
    
        HINTERNET OpenUrl=InternetOpenUrl(InternetSession,DownloadURL,NULL,0,0,0);
    
        if (!OpenUrl)
          {
            cout << "Cannot open URL " << DownloadURL << "\n";
            return 0;
          }
          
        BOOL Test1,Test2;
        DWORD RemainingBytes;
        ofstream File;
        File.open("Downloaded.dat",ios::binary);
    
        do
          {
            Test1=InternetQueryDataAvailable(OpenUrl,&RemainingBytes,0,0);
            cout << "Remaining bytes: " << RemainingBytes << "\n";
    
            if (!Test1)
              {
                cout << "Cannot query data. Error " << GetLastError() << "\n";
                return 0;
              }
    
            char *Buffer=new char[RemainingBytes];
            char *Ptr=Buffer;
            DWORD BytesToRead=RemainingBytes;
            DWORD BytesRead;
    
            do
              {
                Test2=InternetReadFile(OpenUrl,Ptr,BytesToRead,&BytesRead);
                cout << "Bytes read: " << BytesRead << "\n";
    
                if(!Test2)
                  {
                    cout << "Cannot read data. Error " << GetLastError() << "\n";
                    return 0;
                  }
                 
                BytesToRead-=BytesRead;
                Ptr+=BytesRead;
              } while(Test2 && BytesRead);
    
            File.write(Buffer,RemainingBytes);
            delete []Buffer;
          } while(Test1 && RemainingBytes);
    
        File.close();
        InternetCloseHandle(OpenUrl);
        InternetCloseHandle(InternetSession);
        return 0;
      }
    Vous pouvez verifier qu'il fonctionne tres bien pour telecharger des fichiers de quelques dizaines de Ko, en revanche ca foire completement pour un fichier de 5Mo. La sortie indique en temps reel ce que fait le programme. Pour un petit fichier, on voit que le telechargement se fait par paquets. En revanche pour un gros fichier, la sortie indique que le telechargement se fait en un seul paquet, et ceci de maniere instantanee!

    Si quelqu'un peut me dire se qu'il se passe...

  7. #7
    Membre du Club
    Inscrit en
    Mai 2006
    Messages
    126
    Détails du profil
    Informations forums :
    Inscription : Mai 2006
    Messages : 126
    Points : 54
    Points
    54
    Par défaut
    Une amelioration, mais je ne sais pas trop pourquoi: Le nom du gros fichier que j'essayais de telecharger contenenait des espaces, donc dans l'URL je les indiquais par "%20". Depuis que j'ai supprime ces espaces dans le nom du fichier, la fonction ci-dessus se decide enfin a telecharger le fichier.

    Cela dit, ca n'est pas une explication satisfaisante, car les noms des petits fichier pour lesquels ca marchait contenait egalement des espaces.

    Je marque quand meme comme "resolu".

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Graveur ne lit pas les DVD
    Par marsupilami34 dans le forum Composants
    Réponses: 2
    Dernier message: 17/12/2007, 14h31
  2. mon jar ne lit pas les sons wav
    Par poulette3000 dans le forum AWT/Swing
    Réponses: 8
    Dernier message: 13/05/2007, 19h56

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo