Inekman
Messages postés291Date d'inscriptiondimanche 2 février 2003StatutMembreDernière intervention30 juin 2006
-
4 avril 2005 à 00:56
Inekman
Messages postés291Date d'inscriptiondimanche 2 février 2003StatutMembreDernière intervention30 juin 2006
-
6 avril 2005 à 00:19
Salut les amis, j'ai un problème de lecture avec l'api readfile.
J'ai un buffer de 64ko qui contient ce que lit l'api sauf que quand
j'arrive à la fin du fichier que je suis en train de lire et que la
taille restante à lire est inférieure à la taille du buffer, alors
l'api ne lit rien du tout et la boucle boucle
sans fin puisque la taille lue reste toujours inférieure à la taille
totale du fichier...je sais pas si vous avez compris mais moi je sèche
:-(
WhiteHippo
Messages postés1154Date d'inscriptionsamedi 14 août 2004StatutMembreDernière intervention 5 avril 20123 5 avril 2005 à 00:51
Moi j'suis comme Kenavo, y'a quelquechose qui me plait pas non plus !!!!
C'est que tu n'utilises pas la taille du fichier !!!
Bon j'ai fait vite (j'suis peut être passé à côté de quelquechose) un bout de code (mais qui fonctionne) avec les API windows (sauf pour l'allocation du buffer) puisque cela te tenait tellement à coeur
N.B. Je sais, il n'y a pas beaucoup de commentaires mais je pense que les variables utilisées parlent d'elles mêmes.
const
TAILLE_BUFFER = 65536 ; // Ou plus pour un nombre de passes de copie inférieur
type
PBuffer = ^TBuffer ;
TBuffer = array[0..TAILLE_BUFFER-1] of char ;
PtrBuffer : PBuffer ;
begin
new ( PtrBuffer ) ;
if ( PtrBuffer = NIL ) then
begin
Messagedlg('Impossible d''allouer de la mémoire pour le buffer.',mtError,[mbOK],0);
Exit ;
end ;
try
// !! Attention Avec FILE_FLAG_NO_BUFFERING à la place de FILE_ATTRIBUTE_NORMAL
// ça ne fonctionne pas parce que :
// "An application must meet certain requirements when working with files
// opened with FILE_FLAG_NO_BUFFERING (c.f. Win32 Programmer's References)"
SourceHandle := CreateFile(PChar(Source), GENERIC_READ, 0, NIL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (SourceHandle = INVALID_HANDLE_VALUE) then
begin
Erreur := GetLastError() ;
Messagedlg(Format('Erreur %d à l''ouverture du fichier source %s.', [Erreur,Source]),mtError,[mbOK],0);
Exit ;
end ;
DestHandle := CreateFile(PChar(dest), GENERIC_WRITE, 0, NIL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
if (DestHandle = INVALID_HANDLE_VALUE) then
begin
// Traitement erreur : Message, exception, etc...
Erreur := GetLastError() ;
CloseHandle( SourceHandle );
Messagedlg(Format('Erreur %d à l''ouverture du fichier destination %s.', [Erreur,Dest]),mtError,[mbOK],0);
Exit ;
end ;
TailleFichierSourceLow := 0 ;
TailleFichierSourceHigh := 0 ;
TailleFichierSourceLow := GetFileSize( SourceHandle, @TailleFichierSourceHigh ) ;
if ( TailleFichierSourceLow = $FFFFFFFF ) then
begin
Erreur := GetLastError() ;
Messagedlg(Format('Erreur %d : Impossible d''obtenir la taille du fichier %s.', [Erreur,Dest]),mtError,[mbOK],0);
CloseHandle(SourceHandle);
CloseHandle(DestHandle);
Exit ;
end ;
TailleFichierSource := ( TailleFichierSourceHigh shl 32 ) + TailleFichierSourceLow ;
NombreOctetsRestants := TailleFichierSource ;
while ( NombreOctetsRestants > 0 ) do
begin
if ( NombreOctetsRestants < TAILLE_BUFFER ) then
begin
SourceOctetsALire := NombreOctetsRestants ;
DestOctetsAEcrire := NombreOctetsRestants ;
end else
begin
SourceOctetsALire := TAILLE_BUFFER ;
DestOctetsAEcrire := TAILLE_BUFFER ;
end ;
SourceOctetsLus := 0 ;
FillChar( PtrBuffer^, TAILLE_BUFFER, #0 ) ;
Resultat := ReadFile ( SourceHandle, PtrBuffer^, SourceOctetsALire, SourceOctetsLus , nil ) ;
if ( Resultat and ( SourceOctetsLus = 0 ) ) then
begin
// Fin du fichier
end else begin
if ( not Resultat ) or ( SourceOctetsLus <> SourceOctetsALire ) then
begin
Messagedlg( format( 'Erreur : Nombre d''octets lus %d différents du nombre attendu %d.'
,[SourceOctetsLus,SourceOctetsALire]),mtError,[mbOK],0);
CloseHandle(SourceHandle);
CloseHandle(DestHandle);
Exit ;
end ;
end ;
DestOctetsEcrits := 0 ;
Resultat := WriteFile ( DestHandle, PtrBuffer^, DestOctetsAEcrire, DestOctetsEcrits , nil ) ;
if ( not Resultat ) or ( DestOctetsEcrits <> DestOctetsAEcrire ) then
begin
Messagedlg( format( 'Erreur : Nombre d''octets écrits %d différents du nombre attendu %d.'
,[DestOctetsEcrits,DestOctetsAEcrire]),mtError,[mbOK],0);
CloseHandle(SourceHandle);
CloseHandle(DestHandle);
Exit ;
end ;
NombreOctetsRestants := NombreOctetsRestants - SourceOctetsALire ;
end ;
CloseHandle(SourceHandle);
CloseHandle(DestHandle);
finally
dispose( PtrBuffer );
PtrBuffer := NIL ;
end ;
end ;
Inekman
Messages postés291Date d'inscriptiondimanche 2 février 2003StatutMembreDernière intervention30 juin 2006 5 avril 2005 à 00:58
Salut WhiteHippo,
Merci beaucoup pour ta solution, ça fait plaisir. Mais tu a répondu à mon problème en 2 lignes :-D :
// !! Attention Avec FILE_FLAG_NO_BUFFERING à la place de FILE_ATTRIBUTE_NORMAL
// ça ne fonctionne pas parce que :
// "An application must meet certain requirements when working with files
// opened with FILE_FLAG_NO_BUFFERING (c.f. Win32 Programmer's References)"
Ouai donc c'en fait 4 :-)
j'ai changé le createfile en mettant FILE_ATTRIBUTE_NORMAL et mon problème s'est résolu tout seul ;-)
et pour "
C'est que tu n'utilises pas la taille du fichier !!!", c'est ma variable "total" dans la condition de la boucle. :-P
Autre question en despi et on boucle l'affaire, est-il mieux de faire un buffer de char ou un buffer de byte ?
cs_Kenavo
Messages postés702Date d'inscriptionvendredi 21 mars 2003StatutMembreDernière intervention 1 octobre 20095 4 avril 2005 à 08:29
Salut,
Y a quelque chose qui me plait pas dans ton algo (qui doit servir à
faire une copie de fichier, non ?). Tu n'utilises pas au mieux la
variable "lu" de la fonction ReadFile.
J'aurais écrit:
alire := sizeof(buffer);
repeat
if ReadFile(Source, buffer, alire, lu, nil) then // On essaye de lire 64K
WriteFile(Dest, buffer, Lu, ecrit, nil); // On copie ce qu'on a lu
until Lu <> ALire; // On n'a pas lu 64K : on est a la fin
Inekman
Messages postés291Date d'inscriptiondimanche 2 février 2003StatutMembreDernière intervention30 juin 2006 4 avril 2005 à 12:15
oui il sert à copier des données d'un fichier mais y'a juste un extrait du code ici, la partie qui pose problème ;-)
Toujours est-il que ta solution est intéressante mais on va se
retrouver avec le même problème dans la mesure où ReadFile ne lira plus
rien dès que la taille des données restantes à lire sera inférieure à
la taille du buffer :-\ donc Lu sera toujours <> de ALire et ça
bouclera sans fin
C'est ça que je comprend pas...peu importe la taille du buffer,
ReadFile devrait au moins lire la quantité de données qu'on lui demande
de lire non ? Je sais pas du tout...
Vous n’avez pas trouvé la réponse que vous recherchez ?
Emandhal
Messages postés194Date d'inscriptiondimanche 2 mars 2003StatutMembreDernière intervention10 octobre 20063 4 avril 2005 à 12:35
J'utiliserai FileRead plutot que ReadFile. Et FileWrite plutot que WriteFile.
Dans l'aide Delphi il est marqué :
function FileRead(Handle:Integer; varBuffer; Count:Integer): Integer;
C'est donc une fonction, ce qui est renvoyé, c'est le nombre de caractères lus, à partir de là il suffit de comparer ce que renvoie la fonction avec la taille du buffer. Si c'est différent (normalement inférieur) c'est que l'on est à la fin du fichier et après il suffit de copier que le nombre de caractères lus dans WriteFile.
FinFichier := False;
alire := SizeOf(buffer);
Repeat
SizeRead : = FileRead(Source, buffer^, alire
); // SizeRead: Integer;
If SizeRead<alire
Then FinFichier := True;
SizeWrite := FileWrite(Dest, buffer^, SizeRead); // SizeWrite: Integer; // SizeWrite permet de faire un controle de ce qui est écrit, comme ca, si SizeRead<>SizeWrite c'est qu'il y a eut un problème à l'écriture... Il suffit de rajouter le test adéquate.
Untilnot FinFichier;
Tout problème a sa solution... Mais en général, c'est jamais la bonne...
WhiteHippo
Messages postés1154Date d'inscriptionsamedi 14 août 2004StatutMembreDernière intervention 5 avril 20123 5 avril 2005 à 01:30
Ok pour la variable "total", j'suis plus très reveillé à cette heure là moi
Buffer de byte ou buffer de char ?? Dépend de l'utilisation que tu veux en faire derrière. Si c'est un fichier texte j'aurais tendance à dire buffer de char pour pouvoir exploiter les données en caractère, et si c'est un fichier binaire alors je dirais buffer de byte. Cependant, char ou byte c idem en Delphi, alors tu fais comme tu le sens...
Par contre je te conseille vivement d'augmenter la taille de ton buffer de lecture/ecriture!!!
cs_Kenavo
Messages postés702Date d'inscriptionvendredi 21 mars 2003StatutMembreDernière intervention 1 octobre 20095 5 avril 2005 à 14:08
J'vais p'tèt dire une incongruité, mais je donne mon avis.
Il me semble bien qu'il ne doit pas être trop gros pour ne pas générer
des swaps entre RAM et fichier d'échange, ce qui nuirait à la
performance.
Je dirais aussi qu'il doit être préférable qu'il soit d'une
taille multiple de l'unité l'allocation (bon ça, ça doit pas être trop
dur, le tout c'est de choisir un nombre "rond" en hexa).
Avec tout ça je dirais un multiple de $100000 (= 1Mo).
Si les fichiers sont gros (>10Mo) , j'irais même jusqu'à $1000000 (16Mo) sur une machine qui en a.
Emandhal
Messages postés194Date d'inscriptiondimanche 2 mars 2003StatutMembreDernière intervention10 octobre 20063 5 avril 2005 à 17:53
Je vais faire comme Kenavo...
Je dirai qu'un grand buffer (>1Mo) est bien parce que ca limite les accès au disque dur.
Mais il faut tout de meme savoir que Win95/98/Me ont une gestion de la mémoire légèrement... chaotique et un gros buffer comme ca, c'est bien plus préjudiciable que bénéfique.
Un buffer de taille variable me parrait une meilleure idée
Mais ça reste mon idée...
Tout problème a sa solution... Mais en général, c'est jamais la bonne...
Inekman
Messages postés291Date d'inscriptiondimanche 2 février 2003StatutMembreDernière intervention30 juin 2006 5 avril 2005 à 17:58
le buffer de 1 Mo ne passe pas :'( car :
---------------------------
Debugger Fault Notification
---------------------------
Project "Project1.exe" faulted with message: 'access violation at
0x0045c31f: write of address 0x01920fa0'. Process Stopped. Use Step or
Run to continue.
---------------------------
OK
---------------------------
Voilà, j'avais mis 512 ko un coup et ça marchait bien aussi mais je
sais pas c'est quoi la limite du tableau...en tout cas 1 Mo c'est pas
la peine, alors 16 Mo
WhiteHippo
Messages postés1154Date d'inscriptionsamedi 14 août 2004StatutMembreDernière intervention 5 avril 20123 5 avril 2005 à 19:03
Inekman, en reprenant mon code (qui n'est peut etre pas parfait, soit !! )et en mettant la constante à 16Mo, ça fonctionne chez moi (Copie de fichier de plus de 10Mo) !!
const
TAILLE_BUFFER = $1000000 ;
Donc, faut que tu regardes ton code de plus près, doit y avoir un hic !!
Inekman
Messages postés291Date d'inscriptiondimanche 2 février 2003StatutMembreDernière intervention30 juin 2006 6 avril 2005 à 00:19
Ayé j'ai fait comme t'as dis WhiteHippo. En fait, quand on met la
taille directement dans le tableau ça passe pas...mais je l'ai mis en
constante comme toi et ça marche good ;-) J'ai mis le buffer à 1Mo, 4
Mo etc..et ça passe nikel.
Je voudrai savoir ce que ça apporte de passer par des pointeurs, car je comprend pas encore cette philosophie