10
votes

Y a-t-il un moyen de valider un nom de fichier?

Je pensais que cela doit être dans le RTL quelque part, mais j'ai regardé et je ne peux pas le trouver. XXX

En d'autres termes, il doit indiquer un dossier existant sur un lecteur local ou réseau valide, et ne contient pas de caractères non valides. Avons-nous quelque chose comme ça? (Points bonus Si cela vérifie les droits d'accès actuels de l'utilisateur pour vous assurer de pouvoir obtenir au dossier en question.)


5 commentaires

Je suis un peu pédant, je sais, mais s'il vous plaît utiliser const fichier nom: chaîne !


Au fait, votre question est vraiment trop vague. Je suppose que répertoire (ExtractFilePath (nom de fichier)) est une exigence nécessaire, comme c'est le fait que extractfilename (nom de fichier) ne contient que des caractères valides. Mais cela ne signifie pas que vous pouvez créer ou même lire un fichier dans ce répertoire. Il est probable que le répertoire est en lecture seule (par exemple les fichiers de programme ou Windows), de sorte que vous puissiez ouvrir des fichiers, mais ne pas créer de fichiers. Il est également possible que vous ne puissiez même pas lire (par exemple, le répertoire d'un autre utilisateur). De plus, si le fichier existe mais vous êtes autorisé à le réécrire? Devrions-nous retourner vrai ou faux?


Encore mieux: Const FileName: Tfilename .


@ Andreasrejbrand - il va faire des opérations IO (lire / écrire un fichier). Sur un disque dur, cela prendra au moins 12 ms (temps moyen pour mettre la tête sur le bon secteur). En réalité, cela prendra des centièmes de SP. Je ne pense pas que le gain (ns) ajouté par const fera une différence dans ce cas :) PS: Je ne suis pas contre l'utilisation de Const. Ce que je dis, c'est que dans ce cas, cela ne fera pas une différence.


Bonne question. Dommage, il n'y a pas de bonnes réponses!


9 Réponses :


5
votes

Est-ce trop brut, maçon? XXX


4 commentaires

Je suppose que cela pourrait fonctionner si j'ai appelé que ou fileeexistes (nom de fichier) .


Pour la discussion complète: Stackoverflow.com/Questtions/3599256/...


@ Mason Wheeler: Si le fichier existe, alors Canccreeefile (nom de fichier) ou FileExists (nom de fichier) supprimera le fichier existant (!) Et renvoyer false. Si vous utilisez des FileExists (nom de fichier) ou CANCreatefile (nom de fichier), le fichier existant sera toujours autour et le résultat sera vrai. Je recommanderais de ne jamais dépendre des expressions booléennes paresseuses (c'est-à-dire non cochée "complète Boolean eval" dans les options du projet), utilisez un supplément si ... alors à la place.


Vous avez une erreur dans le code, BTW. Vous ne pouvez pas définir le nom de fichier comme une variable, car il s'agit déjà du nom du paramètre. Supprimez la variable et utilisez PCHAR (nom de fichier) à la place.



2
votes

Vérification si répertoire existe:

dans Sysutils, vous avez: DirectoryExists

Vérification du nom de fichier:

Les caractères de nom de fichier non valides sont: \ /: *? "<> | Vous pouvez donc vérifier le nom de fichier comme ceci: xxx

Vérification si le dossier est écritable:

Dupliquer de: Comment puis-je utiliser Delphi pour tester si Un répertoire est écrit?


0 commentaires

10
votes

Autant que je sache, il n'y a pas une fonction API RTL ou Windows pour valider un nom de fichier, vous devez donc écrire votre propre fonction après le Conventions de nom de fichier Windows :

Les règles fondamentales suivantes permettent Applications pour créer et traiter Noms valides pour les fichiers et les répertoires, Indépendamment du système de fichiers:

  • Utilisez une période pour séparer le nom du fichier de base de l'extension dans le nom d'un répertoire ou d'un fichier.
  • Utilisez une barre oblique inverse () pour séparer les composants d'un chemin. La barre oblique inverse divise le nom du fichier du chemin d'accès et un nom de répertoire d'un autre nom de répertoire dans un chemin. Vous ne pouvez pas utiliser une barre oblique inverse dans le nom du fichier ou répertoire réel, car il s'agit d'un caractère réservé qui sépare les noms en composants.
  • Utilisez une barre oblique inverse comme partie des noms de volume, par exemple, le "C: \" dans "C: \ Path \ Fichier" ou "\ Server \ Share" dans "\ Server \ Share \ Path \ Fichier "Pour les noms de convention de dénomination universelle (UNC). Pour plus d'informations sur les noms UNC, voir la section de limitation de la longueur maximale du chemin.
  • Ne supposez pas la sensibilité au cas. Par exemple, considérons que les noms Oscar, Oscar et Oscar sont identiques, même si certains systèmes de fichiers (tels qu'un système de fichiers conforme à POSIX) peuvent les considérer comme différents. Notez que NTFS prend en charge Posix Semantics pour la sensibilité des cas, mais ce n'est pas le comportement par défaut. Pour plus d'informations, voir Createefile.
  • Les concepteurs de volume (lettres d'entraînement) sont également insensibles à la casse. Par exemple, "D: \" et "D: \" se réfèrent au même volume.
  • Utilisez n'importe quel caractère de la page Code actuel d'un nom, y compris des caractères Unicode et des caractères dans le jeu de caractères étendu (128-255), à l'exception des éléments suivants:

    • Les caractères réservés suivants:
      • <(moins de)
      • > (supérieur à)
      • : (côlon)
      • "(double citation)
      • / (slash avant)
      • \ \ (backslash)
      • | (barre verticale ou tuyau)
      • ? (point d'interrogation)
      • * (astérisque)
      • Valeur entière zéro, parfois appelée caractère de Nul ASCII.
      • Les caractères dont les représentations entier sont comprises entre 1 et 31, à l'exception des flux alternatifs où ces caractères sont autorisés. Pour plus d'informations sur les flux de fichiers, voir Flux de fichiers.
      • Tout autre caractère que le système de fichiers cible ne permet pas.
      • Utilisez une période de composant répertoire dans un chemin de chemin pour représenter le répertoire actuel, par exemple ". \ temp.txt". Pour plus d'informations, voir Chemins.
      • Utilisez deux périodes consécutives (..) En tant que composant de répertoire dans un chemin de chemin pour représenter le parent de l'annuaire actuel, par exemple ".. \ temp.txt". Pour plus d'informations, voir Chemins.
      • N'utilisez pas les noms de périphérique réservés suivants pour le nom d'un fichier:

        CON, PRN, AUX, COM2, COM2, COM3, COM4, ​​COM5, COM6, COM7, COM8, COM8, COM8, COM8, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8 et LPT9. Évitez également ces noms suivis immédiatement par une extension; Par exemple, Nul.txt n'est pas recommandé. Pour plus d'informations, voir Espaces de noms.

      • Ne mettez pas de nom de fichier ou de répertoire avec un espace ou une période. Bien que le système de fichiers sous-jacent puisse prendre en charge ces noms, l'interface Windows Shell et l'interface utilisateur ne le font pas. Cependant, il est acceptable de spécifier une période de premier caractère d'un nom. Par exemple, ".temp".

        Vous pouvez vérifier cet article C ++ Validation des noms de fichiers pour un exemple complet fonction pour valider les noms de fichier Windows.


0 commentaires

3
votes

Pour voir s'il existe, utilisez DirectoryExists () et FileExists () . Pour voir si vous pouvez créer / éditer le fichier, utilisez FileOpen () avec READWRITE et voyez si cela réussit.


0 commentaires

3
votes

Essayez ce code (extrait de Delphi FAQ ) Xxx


4 commentaires

Le commence ... fin est superflu. De plus, vous devriez faire islong: boolean = true (ou supprimez complètement le code 8.3).


Le code ne teste pas pour les noms de fichiers interdits tels que CON, PRN, AUX


Il devrait venir avec une vérification d'annuaire


Le code ne teste également pas ".. 'dans les noms de fichiers



4
votes

Je n'ai pas accès à un compilateur Delphi en ce moment, mais vous pouvez essayer xxx


1 commentaires

Peut-être que vous souhaitez créer le fichier dans un dossier qui n'a pas encore été créé. Donc, les analysistes échoueront.



14
votes

Donc, cette question est un peu ancienne mais au cas où vous cherchez: avec XE et plus récente, vous pouvez utiliser la classe TPATH ​​ code> classe dans system.ioutils code>.

Result := TPath.HasValidFileNameChars(AFileName, UseWildcards); 


5 commentaires

Système.ioutils n'est pas fiable. Je ne sais pas sur hasvalidfilenamecharn mais HasValidPathches ne fonctionne pas - ou du moins ne suffit pas à vérifier si le chemin est valide. Si vous passez ' etc ' en tant que paramètre sur HASVALIDPATHARNS, il retournera true. Donc, vous devez également utiliser quelque chose comme TPATH.HASPATHVALIDCOLON (qui n'est malheureusement pas public mais privé).


Tpath.hasvalidfilenamecharrs ('c: \ ioutils_sucks.txt', false) échouera !!!!!!!!!!!!!!!!


Selon l'analyse de David Heffernan ( Stackoverflow.com/a/45347107/133516 ), tpath.hasvalidfilenamecharg < / code> n'est pas fiable


@ Z80 Il échoue car ce n'est pas un nom de fichier valide. C'est un nom d'un chemin. Cette fonction attend uniquement la partie du nom du fichier.


@Marusnebunu - Je vois. Je m'attendais à pouvoir utiliser cette fonction sur les noms de fichiers "vrais vie" (nom de fichier véritable + son chemin). Ainsi, l'utilisation doit diviser le nom de fichier complet dans le nom de fichier et le chemin et utiliser hasvalidPathlars + hasvalidfilenamecharn



1
votes

Vous pouvez également utiliser la fonction sysutils.charinset : xxx


0 commentaires

1
votes

Ceci est ma version:

function MValidFileName(AFileName: String): Boolean;
const InvalidChars: set of AnsiChar = [#0..#31, '\', '/', ':', '*', '?', '"', '<', '>', '|'];
      InvalidWords: array[0..21] of String = ('CON', 'PRN', 'AUX', 'NUL', 'COM1',
       'COM2', 'COM3', 'COM4', 'COM5', 'COM6', 'COM7', 'COM8', 'COM9', 'LPT1', 'LPT2',
       'LPT3', 'LPT4', 'LPT5', 'LPT6', 'LPT7', 'LPT8', 'LPT9');
var I, L, Lw: Integer;
begin
 Result:= False;
 L:= Length(AFileName);
 if (L = 0) or (L > 255) or (AFileName[L] = '.') or (AFileName[L] = ' ') then Exit;
 for I:= 1 to L do 
  if (Ord(AFileName[I]) <= 255) and (AnsiChar(AFileName[I]) in InvalidFileNameChars) then Exit;
 AFileName:= UpperCase(AFileName);
 for I:= 0 to 21 do begin
  Lw:= Length(InvalidWords[I]);
  if (Pos(InvalidWords[I], AFileName) = 1) and
   ((Lw = Length(AFileName)) or (AFileName[Lw+1] = '.')) then Exit;
 end;
 Result:= True;
end;


1 commentaires

C'était un bon code, j'ai utilisé ceci. Merci