FAQ C++/CLI et VC++.Net
FAQ C++/CLI et VC++.NetConsultez toutes les FAQ
Nombre d'auteurs : 29, nombre de questions : 248, création le 22 février 2013
- Comment créer, copier, déplacer, supprimer un fichier ?
- Comment obtenir les attributs d'un fichier ou d'un répertoire?
- Comment obtenir la liste des fichiers et des sous-répertoires d'un répertoire ?
- Comment lire et écrire dans un fichier texte ?
- Comment lire et écrire dans un fichier binaire ?
- Comment surveiller les modifications d'un fichier grâce aux notifications système?
- Comment récupérer le nom d'un fichier, lorsque j'ai le chemin complet ?
- Comment afficher ou écrire correctement les caractères accentués dans mes fichiers ?
- Comment tester l'existence d'un fichier ?
- Comment savoir si un fichier est en lecture seule ?
- Comment obtenir le répertoire d'exécution de mon application ?
- Comment obtenir le répertoire courant ?
- Comment obtenir le répertoire système ?
- Comment obtenir les chemins des répertoires spéciaux comme "Mes Documents" ?
- Comment obtenir la liste des lecteurs logiques ?
- Comment obtenir les informations d'un disque ?
- Comment connaître le pourcentage d'espace disque de vos disques durs ?
- Comment détecter si il y a un cd/dvd dans un lecteur ?
- Comment lister toutes les entrées d'un répertoire ?
- Comment concaténer de manière intelligente un path et un nom de fichier ?
- Comment calculer la taille d'un répertoire ?
- Comment récuperer le path de l'application ?
- 5.4.1. Compression (2)
- 5.4.2. XML
(5)
- Comment lire un fichier Xml avec les classes de l'espace de noms System::Xml::Xpath ?
- Comment créer un XmlNamespaceManager en se basant sur un fichier Xml ?
- Comment valider un fichier XML avec un schéma XSD ?
- Comment sérialiser et désérialiser un objet simple en XML ?
- Comment sérialiser un objet en ignorant les références circulaires ?
Pour créer, copier, déplacer ou supprimer un fichier, on utilise la classe System::IO::File
using
namespace
System::
IO;
using
namespace
System;
public
:
static
void
FileTests()
{
try
{
//Création d'un fichier vide.
FileStream ^
fs =
File::
Create("myfile.txt"
);
fs->
Close();
Console::
WriteLine("fichier myfile.txt créé"
);
// Copie de fichier
File::
Copy("myfile.txt"
, "copyofmyfile.txt"
);
Console::
WriteLine("fichier myfile.txt copié vers copyofmyfile.txt"
);
// Déplacement de fichier
File::
Move("copyofmyfile.txt"
, "c:
\\
copyofmyfile.txt"
);
Console::
WriteLine("fichier copyofmyfile.txt déplacé vers c:
\\
copyofmyfile.txt"
);
// Suppression de fichier
File::
Delete("c:
\\
copyofmyfile.txt"
);
Console::
WriteLine("Fichier c:
\\
copyofmyfile.txt supprimé"
);
}
catch
(Exception ^
ex)
{
Console::
WriteLine(ex->
ToString());
Console::
WriteLine(ex->
Message);
}
}
On utilise la méthode GetAttributes de la classe System::IO::File
static
void
GetFileAttributes(String ^
sFilename)
{
FileAttributes flagAttr =
File::
GetAttributes(sFilename);
// Date de création
Console::
WriteLine("Créé le {0} à {1}"
,
File::
GetCreationTime(sFilename).ToShortDateString(),
File::
GetCreationTime(sFilename).ToShortTimeString());
// Date de la dernière modification
Console::
WriteLine("Modifié le {0} à {1}"
,
File::
GetLastWriteTime(sFilename).ToShortDateString(),
File::
GetLastWriteTime(sFilename).ToShortTimeString());
// Date du dernier accès
Console::
WriteLine("Dernier accès le {0} à {1}"
,
File::
GetLastAccessTime(sFilename).ToShortDateString(),
File::
GetLastAccessTime(sFilename).ToShortTimeString());
Console::
WriteLine("Attributs de {0}"
, sFilename);
// Attribut Archive
if
((flagAttr &
FileAttributes::
Archive) ==
FileAttributes::
Archive)
Console::
WriteLine(FileAttributes::
Archive);
// Attribut Compressé
if
((flagAttr &
FileAttributes::
Compressed) ==
FileAttributes::
Compressed)
Console::
WriteLine(FileAttributes::
Compressed);
// Attribut Device
if
((flagAttr &
FileAttributes::
Device) ==
FileAttributes::
Device)
Console::
WriteLine(FileAttributes::
Device);
if
((flagAttr &
FileAttributes::
Directory) ==
FileAttributes::
Directory)
Console::
WriteLine(FileAttributes::
Directory);
if
((flagAttr &
FileAttributes::
Encrypted) ==
FileAttributes::
Encrypted )
Console::
WriteLine(FileAttributes::
Encrypted);
// Attribut caché
if
((flagAttr &
FileAttributes::
Hidden) ==
FileAttributes::
Hidden)
Console::
WriteLine(FileAttributes::
Hidden);
// Attribut Normal
if
((flagAttr &
FileAttributes::
Normal) ==
FileAttributes::
Normal)
Console::
WriteLine(FileAttributes::
Normal);
// Attibut non indexé
if
((flagAttr &
FileAttributes::
NotContentIndexed) ==
FileAttributes::
NotContentIndexed)
Console::
WriteLine(FileAttributes::
NotContentIndexed);
// Attribut Offline
if
((flagAttr &
FileAttributes::
Offline) ==
FileAttributes::
Offline)
Console::
WriteLine(FileAttributes::
Offline);
// Attribut ReadOnly
if
((flagAttr &
FileAttributes::
ReadOnly) ==
FileAttributes::
ReadOnly)
Console::
WriteLine(FileAttributes::
ReadOnly);
// Attribut ReparsePoint
if
((flagAttr &
FileAttributes::
ReparsePoint) ==
FileAttributes::
ReparsePoint)
Console::
WriteLine(FileAttributes::
ReparsePoint);
// Attribut SparseFile
if
((flagAttr &
FileAttributes::
SparseFile) ==
FileAttributes::
SparseFile)
Console::
WriteLine(FileAttributes::
SparseFile);
// Attribut System
if
((flagAttr &
FileAttributes::
System) ==
FileAttributes::
System)
Console::
WriteLine(FileAttributes::
System);
// Attribut Temporary
if
((flagAttr &
FileAttributes::
Temporary) ==
FileAttributes::
Temporary)
Console::
WriteLine(FileAttributes::
Temporary);
}
On utilise la fonction GetFileSystemEntries de la classe System::IO::Directory
static
void
Dir(String ^
directory)
{
array<
String ^>
^
files;
// pour avoir les noms des fichiers et sous-répertoires
files =
Directory::
GetFileSystemEntries(directory);
for
each (String ^
file in files)
Console::
WriteLine(file);
}
Pour avoir juste les noms des fichiers et pas les sous-répertoires d'un répertoire, on utilise System::IO::Directory::GetFiles()
Nous allons ouvrir un fichier texte et le remplir s'il n'existe pas encore.
Nous afficherons ensuite son contenu à l'écran.
On utiliser pour cela les classes System::IO::StreamReader pour la lecture et System::IO::StreamWriter pour l'écriture.
void
FichierTexte(String ^
nomFichier)
{
StreamReader ^
sr;
StreamWriter ^
sw;
String ^
line;
try
{
if
(!
File::
Exists(nomFichier))
{
// Le fichier n'existe pas. On le crée.
sw =
gcnew StreamWriter(nomFichier);
sw->
WriteLine("Bonjour. Nous sommes le {0} et il est {1} "
,
DateTime::
Now.ToLongDateString(),
DateTime::
Now.ToLongTimeString());
sw->
Close();
// Remarque : On peut utiliser sw = File::AppendText(NomFichier) pour ajouter
// du texte à un fichier existant
}
// Ouverture du fichier et écriture du contenu du fichier sur la console
sr =
gcnew StreamReader(nomFichier);
Console::
WriteLine("Début du fichier"
);
line =
sr->
ReadLine();
while
(line !=
nullptr
)
{
Console::
WriteLine(line);
line =
sr->
ReadLine();
}
// Remarque : on peut aussi utiliser ReadToEnd pour lire tout le fichier en une seule fois
Console::
WriteLine("Fin du fichier"
);
}
finally
{
// Fermeture streamreader
if
(sr !=
nullptr
) sr->
Close();
// Fermeture streamwriter
if
(sw !=
nullptr
) sw->
Close();
}
}
Nous allons ouvrir un fichier binaire et le remplir (d'entiers) s'il n'existe pas encore.
Nous afficherons son contenu à l'écran.
On utilise pour cela les classes System::IO::BinaryReader pour la lecture et System::IO::BinaryWriter pour l'écriture.
void
FichierBinaire(String ^
NomFichier)
{
BinaryReader ^
br;
BinaryWriter ^
bw;
FileStream ^
fs;
try
{
if
(!
File::
Exists(NomFichier))
{
// Le fichier n'existe pas. On le crée
bw =
gcnew BinaryWriter(File::
Create(NomFichier));
for
(int
i=
0
; i<
10
; i++
)
bw->
Write(i);
bw->
Close();
}
// Ouverture du contenu du fichier et écriture sur la console
fs =
File::
Open(NomFichier, FileMode::
Open);
br =
gcnew BinaryReader(fs);
while
(fs->
Position <
fs->
Length)
Console::
Write(br->
ReadInt32());
Console::
WriteLine("
\n
Fin du fichier"
);
}
finally
{
if
(br!=
nullptr
) br->
Close();
if
(bw!=
nullptr
) bw->
Close();
}
}
Windows envoie des notifications qui permettent de surveiller les modifications apportées au système de fichier.
Cela se fait de la manière suivante en utilisant la classe System::IO::FileSystemWatcher.
void
OnChanged(Object ^
source, FileSystemEventArgs ^
e)
{
Console::
WriteLine("Fichier {0} {1}"
, e->
FullPath, e->
ChangeType);
}
void
OnRenamed(Object ^
source, RenamedEventArgs ^
e)
{
Console::
WriteLine("Fichier {0} renommé en {1}"
, e->
OldFullPath, e->
FullPath);
}
void
OnError(Object ^
source, ErrorEventArgs ^
e)
{
Exception ^
ex =
e->
GetException();
Console::
WriteLine(ex->
ToString());
}
void
Watch(String ^
path, String ^
filter)
{
// On peut utiliser les '*' avec filter
// Création de l'objet watcher
FileSystemWatcher ^
fw =
gcnew FileSystemWatcher(path, filter);
// On ajoute les handlers pour surveiller les événements qu'on souhaite.
fw->
Changed +=
gcnew FileSystemEventHandler(OnChanged);
fw->
Renamed +=
gcnew RenamedEventHandler(OnRenamed);
fw->
Created +=
gcnew FileSystemEventHandler(OnChanged);
fw->
Deleted +=
gcnew FileSystemEventHandler(OnChanged);
fw->
Error +=
gcnew ErrorEventHandler(OnError);
// On surveillera aussi les sous répertoires
fw->
IncludeSubdirectories =
true
;
// Mettre EnableRaisingEvents à true démarre la surveillance des modifications.
// Mettre à false l'arrête.
fw->
EnableRaisingEvents =
true
;
}
Et voici l'utilisation de la fonction Watch :
// Pour surveiller l'activité du répertoire c:\rep
Watch("c:
\\
rep"
, "*"
);
Vous devez utiliser la méthode GetFileName de la classe System::IO::Path qui vous permet de récupérer le nom du fichier.
String ^
fileName =
"C:
\\
toto.txt"
;
String ^
name =
System::IO::Path::
GetFileName(fileName);
Console::
WriteLine(name);
Les fichiers sont ouverts avec l'encodage unicode par défaut dans .NET.
Il en résulte que les caractères accentués par exemple ne s'affichent pas correctement.
Vous devez spécifier le type d'encodage à utiliser, pour la lecture/écriture de votre fichier. Exemple pour la lecture :
using
namespace
System::
IO;
using
namespace
System::
Text;
StreamReader ^
strReader =
gcnew StreamReader(fileName, Encoding::
Default);
if
(System::IO::File::
Exists("c:
\\
monfichier.txt"
))
//le fichier existe
else
//le fichier n'existe pas
Grâce à la classe File, il est possible de récupérer les attributs (Archive, Lecture seule, ...) d'un fichier :
// Récupération des attributs d'un fichier
FileAttributes Fa =
File::
GetAttributes("C:
\\
text.txt"
);
// Vérification si le fichier est en lecture seule
if
((Fa &
FileAttributes::
ReadOnly) ==
FileAttributes::
ReadOnly)
Console::
WriteLine("Ce fichier est en lecture seule !"
);
else
Console::
WriteLine("Ce fichier n'est pas en lecture seule"
);
Lien : http://msdn.microsoft.com/fr-fr/library/system.io.file(VS.80).aspx
On utilise la fonction GetCommandLineArgs de la classe System::Environment.
// Chemin de l'exécutable
// Pour les WinForms, on peut aussi utiliser Application::ExecutablePath
String ^
exepath =
Environment::
GetCommandLineArgs()[0
];
// Répertoire de l'exécutable
String ^
exedir =
exepath->
Substring(0
, exepath->
LastIndexOf('
\\
'
));
On utilise la propriété CurrentDirectory de la classe Environment.
Console::
WriteLine("Le répertoire courant est : {0}"
, Environment::
CurrentDirectory);
On utilise la propriété SystemDirectory de la classe Environment.
Console::
WriteLine("Le répertoire système est : {0}"
, Environment::
SystemDirectory);
On utilise la fonction GetFolderPath de la classe Environment avec l'énumération Environment::SpecialFolder.
static
void
PrintSpecFolder()
{
// Répertoire spéciaux
Console::
WriteLine("Répertoire spéciaux"
);
System::
Array ^
sfe =
Enum::
GetValues(Environment::SpecialFolder::
typeid
);
for
each (Environment::
SpecialFolder s in sfe)
Console::
WriteLine(Environment::
GetFolderPath(s));
}
On utilise la fonction GetLogicalDrives de la classe Environment.
static
void
PrintLogicalDrives()
{
// Lecteurs logiques
Console::
WriteLine("Lecteurs logiques"
);
array<
String ^>
^
drives =
Environment::
GetLogicalDrives();
for
each (String ^
drive in drives)
Console::
WriteLine(drive);
}
Il faudra tout d'abord importer l'assembly System.Management. Pour récupérer une valeur, il faudra utiliser la méthode GetPropertyValue associée à un nom de propriété.
L'exemple suivant commence par lister toutes les propriétés existantes puis récupère la valeur de la propriété VolumeSerialNumber.
using
namespace
System;
using
namespace
System::
Management;
ManagementObject ^
disque =
gcnew ManagementObject("win32_logicaldisk.deviceid=
\"
c:
\"
"
);
disque->
Get();
//Afficher toutes les propriétés du disque
String ^
strProp;
for
each(PropertyData ^
d in disque->
Properties)
strProp +=
d->
Name +
"
\n
"
;
Console::
WriteLine(strProp);
//Obtenir une propriété en particulier
strProp =
disque->
GetPropertyValue("VolumeSerialNumber"
)->
ToString();
Console::
WriteLine("n° série volume : "
+
strProp);
La classe DriveInfo peut nous donner les informations nécessaires afin de calculer le pourcentage d'espace libre de chaque disque dur :
// Parcours de la liste des disques durs
for
each (DriveInfo ^
CurrentDrive in DriveInfo::
GetDrives())
{
// Vérification qu'on a bien affaire à un disque dur de l'ordinateur
if
(CurrentDrive->
DriveType ==
DriveType::
Fixed)
{
// Calcul du pourcentage d'espace disque libre
Double pourcentageLibre =
safe_cast<
Double>
(safe_cast<
Double>
(CurrentDrive->
AvailableFreeSpace) /
safe_cast<
Double>
(CurrentDrive->
TotalSize) *
100
);
Console::
WriteLine("Espace libre de {0} >> {1}%"
, CurrentDrive->
Name, Convert::
ToInt16(pourcentageLibre));
}
}
On utilise la classe DriveInfo qui fournit des informations concernant entre autres des informations concernant les lecteurs CD/DVD :
String ^
monDrive =
"D:
\\
"
;
try
{
DriveInfo ^
monDriveInfo =
gcnew DriveInfo(monDrive);
// Vérification qu'on a bien affaire à un lecteur CD/DVD
if
(monDriveInfo->
DriveType ==
DriveType::
CDRom)
{
// Vérification si il y a un cd dans le lecteur
if
(monDriveInfo->
IsReady ==
true
)
Console::
WriteLine("Lecteur identifié avec CD : {0}"
, monDriveInfo->
VolumeLabel);
else
Console::
WriteLine("Lecteur identifié sans CD : {0}"
, monDriveInfo->
Name);
}
else
Console::
WriteLine("Ce lecteur n'est pas un lecteur CD/DVD !"
);
}
catch
(Exception ^
e)
{
Console::
WriteLine("Ceci n'est pas un lecteur !"
);
}
Lien : System.IO.DriveInfo
L'intérêt est ici d'implémenter de façon appropriée la récursivité. L'espace de noms privilégié est System::IO, notamment sa classe Directory. Pour l'exemple nous allons explorer le répertoire particulier des "Favoris", ce qui nous permet à ce propos de nous inspirer de la Q/R d'abelman : Comment obtenir les chemins des répertoires spéciaux comme 'Mes Documents' ?.
static
void
WriteFileEntries(String^
folder, int
indent)
{
// Créer une indentation du texte
StringBuilder^
tab =
gcnew StringBuilder(String::
Empty);
for
(int
i =
0
; i <
indent; i++
)
tab->
Append(L" "
);
// Afficher les dossiers présents et leur contenu par récursivité
array<
System::
String ^>^
subdirs =
Directory::
GetDirectories(folder);
// SI le dossier contient des sous-dossiers
if
(subdirs->
Length !=
0
)
{
for
each (String^
s in subdirs)
{
// Afficher le nom du dossier à explorer
Console::
WriteLine(tab->
ToString() +
Path::
GetFileName(s));
//Utiliser la récursivité avec une indentation
WriteFileEntries(s, indent +
3
);
}
}
// Afficher les noms des fichiers présents
array<
System::
String ^>^
files =
Directory::
GetFiles(folder);
// SI le dossier contient des fichiers
if
(files->
Length !=
0
)
{
for
each (String^
s in files)
Console::
WriteLine(tab->
ToString() +
Path::
GetFileName(s));
}
}
Lien : System.Environment
Lien : System.IO.Directory
Lien : System.IO.Path
La méthode statique Combine de la classe Path permet de concaténer de manière intelligente un chemin de répertoire avec un nom de fichier :
String ^
chemin =
"C:
\\
dev"
;
String ^
fichier =
"fichier.txt"
;
String ^
cheminComplet =
System::IO::Path::
Combine(chemin, fichier);
Console::
WriteLine(cheminComplet);
Nous utiliserons la classe DirectoryInfo avec les méthodes GetFiles pour récupérer les fichiers du répertoire et GetDirectories pour les sous répertoires, le tout de manière récursive :
using
namespace
System::
IO;
static
Int64 TailleRepertoire(DirectoryInfo ^
rep)
{
Int64 Size =
0
;
// liste tous les fichiers du répertoire rep
array<
FileInfo ^>
^
fichiers =
rep->
GetFiles();
for
each (FileInfo ^
fich in fichiers)
Size +=
fich->
Length;
// liste tous les sous-répertoires.
array<
DirectoryInfo^>^
sousrep =
rep->
GetDirectories();
for
each (DirectoryInfo ^
repert in sousrep)
Size +=
TailleRepertoire(repert); //appelle la méthode TailleRepertoire pour calculer la taille de chaque sous répertoire
return
(Size);
}
int
main(array<
System::
String ^>
^
args)
{
String ^
path =
"E:
\\
temp"
;
Int64 TailleOctet =
TailleRepertoire(gcnew DirectoryInfo(path));
Int64 TailleKiloOctet =
TailleOctet /
1024
;
Console::
WriteLine("Taille du répertoire {0} : {1} ko"
, path, TailleKiloOctet);
return
0
;
}
On utilise :
String ^
pathModule =
System::IO::Path::
GetDirectoryName(System::Reflection::Assembly::
GetEntryAssembly()->
Location);
Attention à ne pas confondre avec :
System::IO::Directory::
GetCurrentDirectory()
qui donne le répertoire courant, qui n'est pas forcément le répertoire de l'exécutable.