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
Sommaire→Intéraction du C++/CLI avec le framework .Net→Fichiers, Répertoires, Disques- 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("\nFin 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.



