有没有办法验证文件名?

问题描述 投票:7回答:10

我认为这必须在RTL的某个地方,但我看了,我找不到它。

function IsValidFilename(filename: string): boolean;
//returns True if it would be possible to create or open a file with
//this name, without modifying the current directory structure

换句话说,它必须指向有效本地或网络驱动器上的现有文件夹,并且不包含任何无效字符。我们有类似的东西吗? (如果它检查当前用户的访问权限以确保您可以访问相关文件夹,则会获得奖励。)

delphi filenames
10个回答
11
投票

所以,这个问题有点陈旧但是如果你正在寻找:使用XE和更新版本,你可以在TPath中使用System.IOUtils类。

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

0
投票

这是我的版本:

function MExtractFileName(const Name: String): String;
var I: Integer;
begin
 I:= Length(Name);
 while (I > 0) and (Name[I] <> '.') do Dec(I);
 if I = 0 then Result:= Name else Result:= Copy(Name, 1, I-1);
end;

function MValidFileName(AFileName: String): Boolean;
const InvalidChar: array[0..8] of Char = ('\', '/', ':', '*', '?', '"', '<', '>', '|');
      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, J, L: 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 begin
  if (AFileName[I] < ' ') then Exit;
  for J:= 0 to 8 do
   if AFileName[I] = InvalidChar[J] then Exit;
 end;
 AFileName:= UpperCase(TrimRight(MExtractFileName(AFileName)));
 for I:= 0 to 21 do if AFileName = InvalidWords[I] then Exit;
 Result:= True;
end;

10
投票

据我所知,没有RTL或Windows API函数来验证文件名,因此您必须按照Windows File Naming Conventions编写自己的函数:

以下基本规则使应用程序能够创建和处理文件和目录的有效名称,而不管文件系统如何:

  • 使用句点将基本文件名与目录或文件名称中的扩展名分开。
  • 使用反斜杠()分隔路径的组件。反斜杠将文件名与其路径分开,并从路径中的另一个目录名中分隔一个目录名。您不能在实际文件或目录的名称中使用反斜杠,因为它是将名称分隔为组件的保留字符。
  • 根据需要使用反斜杠作为卷名称的一部分,例如,“C:\ path \ file”中的“C:\”或“\ server \ share \ path \ file”中的“\ server \ share”命名公约(UNC)的名称。有关UNC名称的更多信息,请参阅最大路径长度限制部分。
  • 不要假设区分大小写。例如,考虑名称OSCAR,Oscar和oscar是相同的,即使某些文件系统(例如符合POSIX的文件系统)可能认为它们不同。请注意,NTFS支持区分大小写的POSIX语义,但这不是默认行为。有关更多信息,请参阅CreateFile。
  • 卷指示符(驱动器号)同样不区分大小写。例如,“D:\”和“d:\”表示相同的卷。
  • 使用当前代码页中的任何字符作为名称,包括扩展字符集(128-255)中的Unicode字符和字符,但以下情况除外: 以下保留字符: <(小于) >(大于) :(冒号) “(双引号) /(正斜杠) \(反斜杠) | (竖杆或管) ? (问号) *(星号) 整数值为零,有时也称为ASCII NUL字符。 整数表示形式在1到31范围内的字符,但允许使用这些字符的备用流除外。有关文件流的更多信息,请参阅文件流。 目标文件系统不允许的任何其他字符。
  • 在句点中使用句点作为目录组件来表示当前目录,例如“。\ temp.txt”。有关更多信息,请参阅路径。
  • 使用两个连续句点(..)作为路径中的目录组件来表示当前目录的父目录,例如“.. \ temp.txt”。有关更多信息,请参阅路径。
  • 不要将以下保留的设备名称用于文件名: CON,PRN,AUX,NUL,COM1,COM2,COM3,COM4,COM5,COM6,COM7,COM8,COM9,LPT1,LPT2,LPT3,LPT4,LPT5,LPT6,LPT7,LPT8和LPT9。同时避免使用这些名称后立即进行扩展;例如,不建议使用NUL.txt。有关更多信息,请参阅命名空间。
  • 不要使用空格或句点结束文件或目录名称。虽然底层文件系统可能支持此类名称,但Windows shell和用户界面却不支持。但是,可以将句点指定为名称的第一个字符。例如,“。temp”。

你可以查看这篇C ++文章Validating file names,获取一个完整的示例函数来验证windows文件名。


5
投票

这太粗糙了,梅森?

function CanCreateFile(const FileName: string): Boolean;
var
  H: THandle;
begin
  H := CreateFile(PChar(FileName), GENERIC_READ or GENERIC_WRITE, 0, nil,
       CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY or FILE_FLAG_DELETE_ON_CLOSE, 0);

  Result := H <> INVALID_HANDLE_VALUE;

  DeleteFile(FileName);
end;

4
投票

我现在无法访问Delphi编译器,但您可以尝试

function IsValidFilename(const FileName: string): boolean;
begin
  result := DirectoryExists(ExtractFilePath(FileName)) and TPath.HasValidFileNameChars(ExtractFileName(FileName), false);
end;

3
投票

要查看它是否存在,请使用DirectoryExists()FileExists()。要查看是否可以创建/编辑文件,请将FileOpen()与ReadWrite一起使用,看看是否成功。


3
投票

试试这段代码(取自delphi faq

const
  { for short 8.3 file names }
  ShortForbiddenChars : set of Char = [';', '=', '+', '<', '>', '|',
                                       '"', '[', ']', '\', '/', ''''];
  { for long file names }
  LongForbiddenChars  : set of Char = ['<', '>', '|', '"', '\', '/', ':', '*', '?'];

function TestFilename(Filename: String; islong: Boolean) : Boolean;
var
  I: integer;
begin
  Result := Filename <> '';
  if islong then
  begin
    for I := 1 to Length(Filename) do
      Result := Result and not (Filename[I] in LongForbiddenChars);
  end
  else
  begin
    for I := 1 to Length(Filename) do
      Result := Result and not (Filename[I] in ShortForbiddenChars);
  end;
end;

2
投票

检查目录是否存在:

在SysUtils中,您有:DirectoryExists

检查文件名:

无效的文件名字符是:\ / : * ? " < > |所以您可以像这样检查文件名:

for c in AFileName do
begin
  OK := NOT (C in ['\', '/', ':', '*', '?', '"', '<', '>', '|']);
  if not OK then Break;
end;

检查文件夹是否可写:

重复:How can I use Delphi to test if a Directory is writeable?


1
投票

您还可以使用SysUtils.CharInSet函数:

function isFileNameValid(fileNameToCheck : String) : Boolean;
var
  invalidChars : Boolean;
  ch : Char;
begin
  invalidChars := False;
  for ch in fileNameToCheck do begin
    invalidChars := SysUtils.CharInSet(ch, ['\', '/', ':', '*', '?', '"', '<', '>', '|']);
    if invalidChars then
      Break;
  end;
  Result := not invalidChars;
end;

0
投票

这是我的解决方案:

function ValidFileName(const FileName: String): Boolean;
const InvalidChar: array[0..8] of Char = ('\', '/', ':', '*', '?', '"', '<', '>', '|');
var I, J, L: Integer;
begin
 Result:= False;
 L:= Length(FileName);
 if (FileName = '') or (FileName[L] = '.') or (FileName[L] = ' ') then Exit;
 for I:= 1 to L do begin
  if (FileName[I] < ' ') then Exit;
  for J:= 0 to 8 do
   if FileName[I] = InvalidChar[J] then Exit;
 end;
 Result:= True;
end;
© www.soinside.com 2019 - 2024. All rights reserved.