|
Publicité ' | |||||||||||||||||||||||
|
|
#1 | ||||||
|
Invité de passage
![]() Étudiant Inscription : mars 2012 Messages : 6 ![]() |
Bonjour,
Je cherche à réaliser une classe permettant de lire simplement un flux provenant d'un fichier ou d'une socket. Pour cela, j'ai commencé à créer la fonction readAll(BufferedReader), qui permet de lire entièrement le contenu du flux. Remarque : Je ne peux utiliser la fonction BufferedReader.readLine() car il m'est impossible de connaitre le caractère qui a provoqué la sortie de la fonction ('\r', '\n' ou '\r' suivi de '\n'), a moins de lire 2 fois le flux et de stocker les positions des fins de ligne (ce qui me semble impossible pour les sockets). Je n'ai pas non plus opté pour une lecture caractère par caractère, étant donné la lenteur du traitement. J'ai donc choisi d'utiliser la fonction BufferedReader.read(char[]) avec un buffer assez grand pour ameliorer la vitesse (même si ça ne me satisfais pas vraiment, en comparaison avec le readLine(), qui reste plus rapide). Voici donc le code actuel de la fonction readAll(BufferedReader) (je l'ai mise en static pour les tests): Code :
Pour vérifier que cette fonction s'exécute correctement, j'ai donc créé une fonction write(BufferedWriter, String), toujours en static, dont voici le code : Code :
Je teste donc ces deux fonction grâce à ce main : Code :
Je tiens aussi à préciser que je n'ai réalisé aucun test sur des sockets, donc il est possible que cela ne fonctionne pas avec celles ci. Lors de l'exécution du code, aucune exception n'est levée, mais j'obtiens un problème : certain caractères "apparaissent" dans le fichier de sortie, lorsque je compare les fichiers avec un éditeur de texte (Notepad++). Il s'agit en fait de points d'interrogation qui apparaissent indépendamment de la taille du buffer et des caractères qui précèdent et qui suivent, mais qui se retrouvent toujours aux mêmes endroits. Après beaucoup de tests, il semble que cela vienne du reader.read(buffer), et non pas du passage du char[] au StringBuilder comme je le pensais au départ. J'ai pensé aussi qu'il pouvait s'agir d'un problème d'encodage mais les points d'interrogation "apparaissent" bien : je veux dire par là que les deux caractères qui les entourent dans le fichier de sortie sont bien présents dans le fichier d'entrée, mais qu'il sont collés dans le fichier d'entrée. Je commence sérieusement à désespérer après plusieurs heures de recherches sur des solutions ou des manières alternatives, je pensais être moins embêté pour simplement copier des fichiers. Cordialement. |
||||||
|
|
00
|
|
|
#2 | ||||||||||
|
Expert Confirmé Sénior
![]() ![]() Développeur Java/Web Inscription : avril 2002 Messages : 12 654 ![]() |
Citation:
Je ne pense pas que le BufferedReader readLine() soit plus performant. Surtout qu'il utilise lui aussi un buffer de 8192... Sinon quelques remarques général sur ton code :
Bref perso je ferais plutôt quelque chose comme cela : Code :
Maintenant pour en revenir sur ton problème : il y a de fortes chances que cela viennent d'un problème d'encodage. En effet tu ne spécifies pas l'encodage du fichier, et c'est donc l'encodage par défaut du système qui est utilisé. Si celui-ci est différent que celui du fichier, alors certains caractères peuvent être mal décodé, et donc mal réencodé quand tu écris le fichier... Bref : tu dois spécifier l'encodage de tes fichiers textes, par exemple : Code :
Citation:
Tu les décodes via un charset lors de la lecture, et tu les réencodes à l'écriture. Si tu veux seulement copier des fichiers il est plus prudent de passer par des bytes qui t'évites ces encodages/décodages... a++
__________________
adiGuba [ tutoriels | blog | twitter ] Rédacteur/Modérateur Java |
||||||||||
|
30
|
|
|
#3 |
![]() ![]() |
J'ajoute que flush() est généralement inutile.
Et qu'il l'est toujours avant un close(), puisque l'une des responsabilités de close() est de traiter tout ce qui restait en suspend pour s'en débarrasser définitivement.
__________________
Si tu donnes un poisson à un homme, il mangera un jour. Si tu lui apprends à pêcher du poisson, il videra le lac et au bout de deux ans son village ne mangera plus jamais. Partagez vos connaissances, mais aussi comment s'en servir. |
|
|
10
|
|
|
#4 | ||
|
Invité de passage
![]() Étudiant Inscription : mars 2012 Messages : 6 ![]() |
Merci à vous deux pour ces réponses qui m'ont bien aidé
A propos de vos remarques :
Voici donc mon nouveau code (fonctionnel) mais certains points me gênent toujours : Code :
Exemple : pour copier un fichier d'environ 40 Méga Octets avec un pas de 8 Kilo Octets (8 * 1024 * taille d'un byte, qui est comme tu l'as dis adiGuba la taille standart pour un buffer de BufferedReader), le copie était tellement longue que j'ai du arrêter avant la fin ( + d'une minute) et en plus la place occupée par le programme en RAM augmentait (dans les 400Mo vers la fin je crois). Toutefois, ça me gène d'allouer directement un buffer de 4Mo (1024 * 1024 * 4 * taille d'un byte) comme dans le code ici, je trouve ça assez brutal comme méthode. Toutefois, avec un tel buffer, je met environ entre 500ms et 1s pour copier les 40 Méga Octets et moins de 500ms lorsque je prend un buffer de taille supérieure à la taille du fichier. Je trouve aussi que c'est assez moche de faire de multiples appels à Arrays.copyOf(), mais ça à l'air de fonctionner parfaitement. Si vous avez d'autres méthodes plus propres mais tout autant fonctionnelles, je prend. N'hésitez pas non plus à critiquer tout le code comme vous l'avez fait si quelque chose vous gêne encore, je suis là aussi preneur EDIT : En plus ce que je n'aime pas dans ma méthode, c'est que la totalité de ce qui est à copier se trouve à un moment dans la RAM. Pour des fichiers de plus d'1 GO ça commence à poser problème.. Cordialement |
||
|
|
00
|
|
|
#5 | ||||||||||||||||||||||||||
|
Expert Confirmé Sénior
![]() ![]() Développeur Java/Web Inscription : avril 2002 Messages : 12 654 ![]() |
Citation:
Plus généralement plutôt que de chercher à tout prix ce qui est le plus performant, il faut plutôt chercher à utiliser ce qui est utile Citation:
C'est juste que si le BufferedReader n'est pas obligatoire, c'est bête de l'imposer... Imagine que demain tu vas utiliser un Reader qui lit des données depuis une base de donnée par exemple. Tout est déjà bufférisé mais tu ne pourras pas utiliser directement ce Reader avec ta méthode car elle impose inutilement un BufferedReader... Dans une méthode c'est toujours bien de conserver des types très abstrait, cela permet plus de liberté d'utilisation... Citation:
Mais encore une fois c'est juste une remarque Citation:
Citation:
Quand tu lis un code comme celui-là : Code :
A l'inverse lorsque tu vois ceci : Code :
Cela peut sembler anodin, mais sur une application serveur destinée à tourner sans interruption, le fait de ne pas libérer une ressource peut avoir de fâcheuses répercutions... Citation:
Vis à vis de ton premier message, j'étais partis dans l'idée que tu voulais lire un fichier en mémoire (pour le manipuler par exemple). Mais si tu veux faire une copie cela ne s'applique pas. Citation:
En effet 40 Méga c'est 40000000 octets. Si tu augmentes ton buffer par pas de 8192 il va te falloir près 4883 augmentation du buffer. Ce qui signifie que tu va créer 4883 tableau de byte[] pendant ton traitement. Bref tu va passer plus de temps à allouer/désallouer de la mémoire qu'autre chose... Citation:
Ou mieux on peut directement déclarer le buffer à la bonne taille si on la connait (ce qui est le cas avec des fichiers). Bref ceci devrait donner de bien meilleurs résultats : Code :
Citation:
Perso je déconseille d'utiliser ce genre de structure : Code :
Perso je conseille plutôt d'utiliser un try/finally par ressource, avec éventuellement un try/catch qui englobe le tout si on a besoin de traiter les exception : Code :
Code :
Citation:
Mais si tu veux "seulement" faire une copie, alors il est bien plus utile de faire la copie à la volée entre les deux flux : Code :
Code :
a++
__________________
adiGuba [ tutoriels | blog | twitter ] Rédacteur/Modérateur Java |
||||||||||||||||||||||||||
|
30
|
|
|
#6 | |
|
Expert Confirmé Sénior
![]() ![]() |
Citation:
=> D'éviter d'avoir besoin de garder le fichier en mémoire quand tu sais déjà à l'avance qu'il dépassera une taille de quelques Ko. Aujourd'hui c'est 40M et demain ce sera combien? 200M? 1G? 20G? => Si c'est inévitable, d'avoir directement un buffer à la bonne taille. En plus des copies, on triple parfois la mémoire nécessaire avec le principe du doublage de taille. Un agrandissement de tableau se fait pas la création d'un nouveau tableau, plus grand et le transvasement des données. Donc dans le pire des cas, pour lire un fichier de 40Mo, il faudra 120Mo. On crée un tableau de 39.9M, il est plein, donc on en crée un nouveau de 79.8M, on y copie les donnée et on y met enfin l'octet restant. Ensuite seulement on supprime le tableau de 39.9M.
__________________
⥀⥁ Чиз faq java, cours java, javadoc. Pensez à et ![]() Laisse entrer le jour après une nuit sombre. Si tu es toujours là, tu n'es pas faite pour mourir. |
|
|
|
20
|
|
|
#7 | ||
|
Expert Confirmé Sénior
![]() ![]() Développeur Java/Web Inscription : avril 2002 Messages : 12 654 ![]() |
Citation:
Mais après ca dépend aussi de l'objectif de ton application... Citation:
Et dans le cas où on ne la connait pas, il faut passer par ce choix de doubler le buffer. Sinon on risque de consommer encore plus de mémoire... a++
__________________
adiGuba [ tutoriels | blog | twitter ] Rédacteur/Modérateur Java |
||
|
00
|
|
|
#8 |
|
Invité de passage
![]() Étudiant Inscription : mars 2012 Messages : 6 ![]() |
Merci beaucoup à tous les deux et désolé pour mon absence, je ne pouvais pas me connecter pendant tout ce temps. Vos conseils m'ont bien aidé et mon problème est parfaitement résolu
|
|
|
00
|
Copyright © 2000-2013 - www.developpez.com