Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Obtenir un non de fichier temporaire

13 réponses
Avatar
Frédéric LAMBOUR
Comment obtenir (facilement) un nom de fichier unique (pour un stockage
temporaire) ?

3 réponses

1 2
Avatar
Zazar
Bonjour,

Il peut effectivement y avoir un probleme si deux instances du programmes
trouvent en même temps que le fichier est inexistant, et veulent le créer
toutes les deux.



Je me demande si le même probleme arrive lorsqu'on demande
un nom de fichier temporaire avec le framework (mais ca doit etre assez
compliqué à tester, parceque s'il utilise aussi des nombres aléatoire (ce
qui me semble assez probable), le probleme ne doit pas apparaitre souvent.
Pour etre sur il faudrait avoir acces au code source de la fonction
Path.GetTempFileName())


Path.GetTempFileName fait un appel à l'API win32 de même nom. Cette API
utilise l'heure système pour génèrer un nombre, et tant qu'un fichier de
même nom existe, l'API incrémente le nombre généré de 1. De plus,
l'opération consistant à tester l'existence du fichier puis à le créer est
une opération atomique du point de vue du système de fichiers. Bref on a
presque toutes les garanties qu'on veut (presque car une application
pourrait thèoriquement ouvrir le fichier nouvellement créé en verrouillant
les droits de lecture et écriture avant l'application faisant l'appel à
l'API)

Dans ce cas, il faudrait remplacer par (désolé, pas le temps de regarder


le
nom de la vraie exception)

bool createNomFichier(String fichier)
{
try
{
//creation et remplissage du fichier
return true;
} catch(FichierDejaExistant) {
return false;
}
}



Le problème est que sous .NET, il n'y a pas de méthode permettant de créer
un fichier et levant une exception si ce fichier existe déjà.


Random rnd = new Random();
String nomFichier;
do
{
nomFichier = rnd.Next().ToString() + ".tmp";
} while(!create(nomFichier));


> un fichier portant malancontreusement le nom trouvé par la fonction RND


?

Dans ce cas, File.Exists(nomFichier) retourne true, et on redemande un


autre
nombre à RND




Si vous faîtes quelque chose du genre :
while (File.Exists( nomFichier))
GenérerNouveauNom();
CreerLeFichier();

Vous ne faîtes pas d'opération atomique : entre le moment où vous testez
l'existence du fichier et le moment où vous le créez, il peut se passer
beaucoup de choses.

Cependant, votre méthode est utilisable en la modifiant légèrement : au lieu
d'utiliser la classe Random, vous utilisez la classe
RNGCryptoServiceProvider, vous génèrez une bonne quantité de bits
aléatoirement (128 devrait être suffisant), vous encodez le résultat de la
génèration dans une string ne contenant que des caractères acceptés par le
système de fichier (une manipulation utilisant un codage base64 par exemple)
et vous avez un nom de fichier presque garanti unique. Cependant la
probabilité que le fichier existe déjà ou qu'une autre application génère le
même nombre est quasiment nulle.
Cette méthode a quelques petits avantages par rapport à GetTempFileName :
elle est réutilisable dans toutes les situations où on a besoin d'une chaîne
de caractères unique, et dans le cas où plusieurs applications demanderaient
un ou plusieurs nom de fichier quasiment en même temps, les accés disques
seront moins nombreux (1 accés disque pour la génération aléatoire par
demande de fichier (n accés au total); au moins 1 accés disque pour
GetTempFileName par demande de fichier et si les demandes "simultanées" sont
nombreuses ça sera plus de l'ordre de 1 + 2 + 3 + ... + n donc de l'ordre de
n^2 au total).
Mais dans la pratique, si on veut juste un nom de fichier temporaire,
l'appel à GetTempFileName répond parfaitement aux besoins.

--
Zazar
Avatar
Vincent Lascaux
> > Dans ce cas, il faudrait remplacer par (désolé, pas le temps de regarder
le
> nom de la vraie exception)
>
> bool createNomFichier(String fichier)
> {
> try
> {
> //creation et remplissage du fichier
> return true;
> } catch(FichierDejaExistant) {
> return false;
> }
> }

Le problème est que sous .NET, il n'y a pas de méthode permettant de créer
un fichier et levant une exception si ce fichier existe déjà.



IOException An I/O error occurs, such as specifying FileMode.CreateNew
and the file specified by path already exists.


> Random rnd = new Random();
> String nomFichier;
> do
> {
> nomFichier = rnd.Next().ToString() + ".tmp";
> } while(!create(nomFichier));
>
>
> > un fichier portant malancontreusement le nom trouvé par la fonction


RND
?
>
> Dans ce cas, File.Exists(nomFichier) retourne true, et on redemande un
autre
> nombre à RND


Si vous faîtes quelque chose du genre :
while (File.Exists( nomFichier))
GenérerNouveauNom();
CreerLeFichier();

Vous ne faîtes pas d'opération atomique : entre le moment où vous testez
l'existence du fichier et le moment où vous le créez, il peut se passer
beaucoup de choses.



C'est pour ca que je proposais la deuxieme solution avec l'exception...

Cependant, votre méthode est utilisable en la modifiant légèrement : au


lieu
d'utiliser la classe Random, vous utilisez la classe
RNGCryptoServiceProvider, vous génèrez une bonne quantité de bits
aléatoirement (128 devrait être suffisant), vous encodez le résultat de la
génèration dans une string ne contenant que des caractères acceptés par le
système de fichier (une manipulation utilisant un codage base64 par


exemple)
et vous avez un nom de fichier presque garanti unique. Cependant la
probabilité que le fichier existe déjà ou qu'une autre application génère


le
même nombre est quasiment nulle.



Je vois pas en quoi l'utilisation d'un truc de crypto garantie plus
l'unicité qu'un random. Si c'est parceque ca fait des clés plus longue, il
suffit de mettre deux nombres aléatoires dans le "GénérerNouveauNom". Encore
une fois, je trouve ca compliqué et lourd d'utiliser des trucs de
cryptographie, et je vois pas l'apport par rapport à Random.

--
Vincent
Avatar
Zazar
Bonjour,

> Le problème est que sous .NET, il n'y a pas de méthode permettant de


créer
> un fichier et levant une exception si ce fichier existe déjà.

IOException An I/O error occurs, such as specifying


FileMode.CreateNew
and the file specified by path already exists.




Ho! J'avais passé je ne sais plus combien de temps à chercher une méthode
qui fasse ça, sans succés. Je m'étais focusé sur les méthodes Create sans
penser à regarder du coté de Open et j'avais fini par me créer ma propre
méthode :).
Merci!




Je vois pas en quoi l'utilisation d'un truc de crypto garantie plus
l'unicité qu'un random.



Le premier problème du Random, c'est que sa graine n'est pas aléatoire (par
défaut, elle est calculée à partir de l'heure courante). Donc si 2 programme
créent leurs objets Random en même temps, les méthodes next renverront les
mêmes valeurs.
Exemple :

Random ran1 = new Random();
Random ran2 = new Random();
Double d1, d2;
d1 = ran1.NextDouble();
d2 = ran2.NextDouble();
Console.WriteLine(d1);
Console.WriteLine(d2);

C'est sûr que ça n'arrive pas tous les jours, mais ça peut arriver, et c'est
difficile de déterminer quelle est la probabilité que ça fonctionne (en gros
vous avez une méthode dont vous savez qu'elle fonctionne "souvent", mais
vous êtes dans l'incapacité de dire quelle est sa fiabilité).

Le deuxième problème de l'utilisation de Random est que si vous connaissez
l'état de la classe à un moment donné, vous pouvez connaître toutes les
prochaines valeurs qui vont être générées. Et sur des applications où la
sécurité est critique ou bien tournant avec des privilèges un peu élevés, ça
peut poser des problèmes si on arrive à savoir quels sont les noms des
fichiers que l'application va utiliser (si elle ne les utilise pas en
faisant des opérations atomiques) si ces fichiers sont stockés dans un
dossier accessible à tout le monde (cas de %windir%temp par exemple ou /tmp
sous linux) . Il est possible de modifier le fichier temporaire si on arrive
à y accéder pendant les cours laps de temps où l'application n'a pas d'accés
exlusif dessus. Avec un nom de fichier totalement aléatoire + une
configuration adéquate du système cible (interdire de lister le contenu des
dossiers temporaires par exemple) prévient ce genre d'attaques.
Le mieux restant de ne faire que des opérations atomiques sur le fichier,
mais ce n'est pas toujours possible ou d'utiliser un dossier temporaire qui
n'est pas accessible au premier venu.

--
Zazar
1 2