perlwin32faq8 - Programmation Générale |
perlwin32faq8 - Programmation Générale
Questions de programmation générale à propos de Perl pour Win32
Plusieurs fonctions de registre Win32 sont fournies par ActivePerl. Consultez le document win32mod accompagnant ActivePerl.
[Voir les docs des modules Win32::TieRegistry et Win32API::Registry -NdT]
Si vous ne comprenez pas comment fonctionne le registre, pensez qu'une clef de registre est un répertoire, une valeur du registre un fichier. Il y a plusieurs clefs de haut niveau, voyez-les comme des disques.
Si vous ne comprenez pas le Registre correctement, il est probablement dans votre intérêt de ne pas y toucher.
Les pipes de noms sont des mécanismes de communications interprocessus, surtout utilisés avec les systèmes Microsoft (comme les plates-formes Win32). Un pipe de nom peut est adressé comme un fichier.
Le nom d'un pipe nommé est un nom UNC (Universal Naming
Convention), et ressemble à \\servername\pipe\pipename.
servername
est le nom du serveur où vous vous connectez, ou
pour l'ordinateur courant. pipe
est une constante et pipename
est
le nom du pipe, comme sql pour Microsoft SQL Server.
Vous pouvez utiliser open()
, close()
, read()
, et print()
sur un pipe, comme sur un fichier. Cependant, vous ne pouvez utiliser
sysread()
ou syswrite()
car ce ne sont pas réellement des
fichiers.
Un programme nommé Win32Pipe se trouve sur l'archive CPAN, il peut être utilisé pour créer des pipes nommés.
Si vous démarrez de zéro, et que vous avez une architecture TCP/IP, considérez l'option d'utiliser des sockets plutôt que des pipes nommés pour vos mécanismes IPC.
Plusieurs exemples de scripts avec des sockets sont distribués avec ActivePerl. Ils sont dans le sous-répertoire eg [eg = exempli gratia en latin = par exemple -NdT] de votre répertoire perl.
Voir Comment écrire un serveur de socket avec ActivePerl ? pour des informations sur les serveurs de sockets.
Les versions précédentes d'ActivePerl ne permettaient pas de lire ou écrire sur un socket comme si c'était un descripteur de fichier. La version courante supporte pleinement cela, et vous n'avez plus à vous en soucier. Si votre version ne supporte pas cette fonction, récupérez la dernière version d'ActiveState (voir Où est disponible l'interpréteur ActivePerl ?).
Vous n'avez pas à spécifier
USE_SOCKETS_AS_FILEHANDLES
quand vous construisez ActivePerl
pour avoir le fonctionnement des sockets en descripteurs de fichiers.
Cela ne gêne pas, mais ce n'est pas nécessaire.
Un exemple de serveurs de sockets, TCP-SERVER, se trouve dans le répertoire eg de votre répertoire perl. En général, les informations pour la programmation de sockets UNIX sont applicables à ActivePerl. Voir tout spécialement la documentation perlipc.
Si vous avez besoin de développer un serveur qui puisse servir plusieurs clients simultanément, regardez le module IO::Select. Ce module vous permet d'écrire un serveur qui gère plusieurs connexions ouvertes par plusieurs clients. Les requêtes individuelles d'une connexion sont placées en file d'attente, donc si votre serveur peut fournir des réponses rapides, cette approche peut très bien fonctionner pour vous. Voici un exemple, adapté de «Programming with Perl Modules» par Erik Olson (un des volumes du Kit de Ressource Perl pour Win32) :
use IO::Socket; use IO::Select;
# Créer un socket pour écouter. # my $listener = IO::Socket::INET->new( LocalPort => 8008, Listen => 5, Reuse => 1 );
die "Can't create socket for listening: $!" unless $listener; print "Listening for connections on port 8008\n";
my $readable = IO::Select->new; # Créer un nouvel objet IO::Select $readable->add($listener); # Ajouter l'écoute
while(1) {
# Obtenir la liste des sockets qui veulent parler avec nous. # my ($ready) = IO::Select->select($readable, undef, undef, undef); foreach my $s (@$ready) {
# Nouvelle connexion ? # if($s == $listener) {
# Accepter la connexion et l'ajouter à la liste de lecture. # my $new_sock = $listener->accept; $readable->add($new_sock) if $new_sock;
print $new_sock "Welcome!\r\n";
} else { # It's an established connection
my $buf = <$s>; # Try to read a line
# Quelqu'un à l'autre bout ? # if( defined $buf ) {
# S'il dit au revoir, fermer le socket. Sinon, # afficher ce qu'il dit. # if ($buf =~ /goodbye/i) { print $s "See you later!\n"; $readable->remove($s); $s->close; } else { print $s "You said: $buf\n"; }
} else { # Le client est déconnecté.
$readable->remove($s); $s->close; print STDERR "Client Connection closed\n";
} } } }
Pour plus d'information, voir la documentation IO::Socket et IO::Select. Il est aussi possible d'écrire un serveur multi-processus avec ActivePerl, si votre version autorise les threads. Cependant le multitâches est encore un peu expérimental avec Perl 5.005, donc utilisez-le avec précaution. [Avec ActivePerl 5.8.0 les threads sont disponibles en standard contrairement aux versions antérieures où il fallait compiler perl avec une option spéciale. Voir la doc du pragma threads. -NdT]
Voir le module Net::FTP. Net::FTP est dans le paquetage libnet, disponible sur le CPAN, et peut être installé avec le Gestionnaire de Paquetage Perl (PPM). [libnet est inclus en standard depuis la version 5.6.1 d'ActivePerl -NdT]
Aldo Calpini a développé une extension Win32::Internet
pour faire du FTP et HTTP
avec la librairie WININET. Voir sa page web à http://dada.perl.it/
Le package libwww-perl (LWP) est une collection de modules pour les accès WWW en Perl. LWP est disponible sur le CPAN en source, ou avec le Gestionnaire de Package Perl (PPM). [libwww-perl est inclus en standard depuis la version 5.6.1 d'ActivePerl -NdT]
Aldo Calpini a développé une extension Win32::Internet
pour faire du FTP et HTTP
avec la librairie WININET. Voir sa page web à http://dada.perl.it/
Une extension nommée Win32::NetAdmin
est distribuée avec ActivePerl.
L'interface est plutôt de bas niveau, mais il est très possible de gérer
les utilisateurs et les groupes avec ce module.
Les ports série peuvent être ouverts comme des fichiers avec ActivePerl. Pour ouvrir COM1, il suffit de faire :
open( PORT, "+>COM1" ) or die "Impossible d'ouvrir COM1: $!";
Vous devriez pouvoir lire et écrire sur le descripteur de
fichier en utilisant les fonctions standards d'Entrée/Sortie
(read()
et print()
), mais pas les fonctions systèmes
(sysread()
et syswrite()).
Il a été noté (mais pas testé) que les
modems utilisant les commandes Hayes demandent un retour chariot (\r
)
plutôt qu'une fin de ligne (\n
) en fin de commande.
[Voir aussi le module Win32-SerialPort
-NdT]
En fait, il marche. Cependant, la plupart des gens l'utilisent mal, et obtiennent des résultats erronés. Pour trouver tous les sous répertoires d'un répertoire, essayez :
$path = shift; $path = "." unless $path;
opendir( DIR, $path ) or die "Can't open $path: $!";
while ( $entry = readdir( DIR ) ) { $type = ( -d "$path\\$entry" ) ? "dir" : "file"; # $path is crucial! print "$type\t$entry\n"; }
closedir( DIR );
C'est une erreur fréquente d'ignorer $path
dans le test
-d
. Si vous le faites, perl pense que vous parlez des fichiers du
répertoire courant. Comme les répertoires ne sont pas
-e
dans votre répertoire courant, ils ne sont
définitivement pas -d
. Exception faite de .
et ..
, qui
existent dans tous les répertoires.
Sur les plates-formes Win32, il y a une grande différence entre
les fichiers textes et binaires. Pour les fichiers textes, les
caractères \r\n
sont traduits en \n
pendant la lecture depuis
le disque, et le caractère ^Z
est lu comme le marqueur
fin-de-fichier. Pour les fichiers binaires, cette traduction n'est pas
utilisée.
Bien que cela fonctionne avec les fichiers textes, cela pose
problème quand vous essayez de lire ou d'écrire un
fichier binaire. Si la lecture ou l'écriture ne s'arrêtent
pas prématurément à cause d'un caractère
^Z
, vous aurez la plupart du temps un nombre d'octets incorrects dans
le fichier à cause de la traduction \n
-> \r\n
.
Le problème est que le Perl pour Win32, et la librairie C utilisée, ouvrent
le fichiers en mode texte par défaut. Pour chaque descripteur de fichiers
que vous utilisez en Perl pour des données binaires, vous devez préciser
que ce descripteur est en mode binaire. Heureusement, il y a une fonction,
binmode
, qui est faite pour ça. Voir binmode
pour les détails.
Ce script copie un fichier binaire vers un autre. Notez l'utilisation de binmode pour passer au format binaire.
open( INFILE, "<$infile" ); open( OUTFILE, ">$outfile" );
binmode( INFILE ); binmode( OUTFILE ); # Vital pour les fichiers binaires !
while ( read( INFILE, $buffer, 1024 ) ) { print OUTFILE $buffer; }
close( INFILE ); close( OUTFILE );
Les plates-formes Win32 utilisent le caractère '\' comme
délimiteur de chemin dans le nom de fichier (C:\comme\ceci
).
Cependant, le Perl utilise '\' comme code d'échappement, pour
symboliser un caractère spécial comme fin de ligne (\n
)
ou tabulation (\t
).
Donc, si vous essayez d'ouvrir un fichier comme ceci :
open( MYFILE, "C:\temp\newfile.txt" );
vous aurez une erreur. Une solution est de remplacer chaque '\' par un double-'\', pour montrer que vous voulez réellement utiliser ce caractère et pas un échappement :
open( MYFILE, "C:\\temp\\newfile.txt" );
Une autre solution est d'utiliser un chaîne non interpolée entre simple quote, qui fait savoir à Perl qu'il ne doit pas utiliser de caractères spéciaux :
open( MYFILE, 'C:\temp\newfile.txt' );
Enfin, vous pouvez aussi utiliser le caractère / pour séparer les composants des répertoires dans les chemins. Vous devez absolument éviter de l'utiliser dans les appels systèmes à des programmes externes, parce que certains programmes ont tendance à traiter / comme un préfixe d'options plutôt qu'en séparateur de répertoire. Toutefois, ActivePerl (et en fait, toutes les API Win32) interprète / comme un séparateur de répertoires, et cela permet un portage plus facile entre UNIX et Win32:
open( MYFILE, '/temp/newfile.txt' );
Voir la page de documentation perlop pour plus d'informations sur les différences entre simple quote (') et double quotes (``).
C'est une erreur étrange qui arrive quand votre terminateur de chaîne de caractères est sur la dernière ligne du script. Avec un script comme :
print <<"END"; The snake is old, and his skin is cold. (*) END
[(*) «The End» - Jim Morrison -NdT]
perl cherche le mot END seul sur une ligne, suivi du caractère
fin-de-ligne (\n
). Si END est sur la dernière ligne du script,
pensez à appuyer sur <Enter> après le mot END,
pour que perl l'identifie comme un caractère de terminaison de
chaîne.
La plupart des éditeurs textes UNIX le font automatiquement. La plupart des éditeurs Windows ne le font pas. C'est le problème.
Cela peut aussi être dû aux formats Perl, puisqu'ils sont terminés par un . seul sur une ligne. Toutefois, c'est plus rare, puisque les programmeurs spécifient souvent le format de sortie en début de fichier plutôt qu'en fin.
[Voir aussi : Pourquoi est-ce que mes documents <<HERE ne marchent pas ? -NdT]
Cette FAQ a été à l'origine assemblée et maintenue par Evangelo Prodromou. Elle a été révisée et mise à jour par Brian Jepson de O'Reilly and Associates, et David Grove et David Dmytryshyn d'ActiveState.
Cette FAQ est dans le domaine public. Si vous l'utilisez, cependant, vérifiez, s'il vous plaît, que vous donniez le crédit aux auteurs originaux.
Cette traduction française correspond à la version anglaise distribuée avec perl 5.8.0. Pour en savoir plus concernant ces traductions, consultez http://www.enstimac.fr/Perl/ .
Fabien Martinet <ho.fmartinet@cma-cgm.com>
Jean-Louis Morel <jl_morel@bribes.org> (mise à jour perl 5.8.0)
perlwin32faq8 - Programmation Générale |