Delphi7、TFileStream打不开特殊字符文件

Delphi 7, TFileStream cant open files with special characters

这一行:

TFileStream.Create(fileName, fmOpenRead or fmShareDenyNone);

如果文件名包含类似 ñ

的内容则抛出异常

您最终调用 CreateFileA,ANSI API,并且您使用的字符没有 ANSI 编码。 唯一 方法是使用 CreateFileW、Unicode API 打开文件。

您可能没有意识到您调用了 CreateFileA,但这就是 Delphi 7 文件流的实现方式。

解决问题的一个简单方法是升级到最新的 Delphi,它对本机 Windows Unicode API 有很好的支持。

如果您受困于 ANSI Delphi,那么您仍然需要调用 CreateFileW。您可以这样做来创建文件句柄。您需要将 UTF-16 字符串传递给 API。使用WideString来存储它。您还需要以 UTF-16 格式从用户处获取文件名。这意味着调用 GetOpenFileNameWIFileDialog。通过将文件句柄传递给 THandleStream 创建一个流。

要使这一切成为可能,您需要使用 TNT Unicode 库。他们工作得很好,但会给你强加一个很大的端口。

坦率地说,正确的前进方向是使用支持 Unicode 的现代工具。

您可以使用 TntUnicode 单元在 Delphi 7 下获得 UTF8 支持。 将 TntClasses 添加到您的 Use 中并像这样进行调用:

TTntFileStream.Create(fileName, fmOpenRead or fmShareDenyNone);

确保文件名是宽字符串。

在这里您可以获得一份 TntUnicode: https://github.com/rofl0r/TntUnicode

UTF16 可以被认为是一个代码页,就像所有可能的 ANSI 代码页一样。

正如雷米在他的评论中提到的那样,假设您的 ANSI 代码页支持 Unicode 字符串中所需的字符,您只需将该字符串的 Unicode 版本转换为等效的 ANSI 代码页版本。

Delphi 编译器可以自动为您进行简单的转换,您只需将 WIDEString (UTF16) 转换为 (ANSI)字符串:

const
  WIDE_FILENAME : WIDEString = 'fuññy.txt';
var
  sFilename: String;
  strm: TFileStream;
begin
  sFilename := String(WIDE_FILENAME);

  strm := TFileStream.Create(sFilename, fmOpenRead);
  // etc
end;      

即使在(例如)Delphi 7 上也能很好地工作。唯一需要注意的是,涉及的代码页(系统默认)必须支持 Unicode 字符串中的扩展字符。

注意: 上面的代码使用了 String 类型而不是显式的 ANSIString。在 StringANSIString 的 Delphi 版本上,这具有所需的效果,但也可移植到 String 的版本UnicodeString (以后要不要升级版本)。

如果在这种情况下显式使用 ANSIString,结果将是 double 转换 if/when 您升级:

// Unicode compiler using ANSIString type....
var
  sFilename: ANSIString;
begin
  sFilename := ANSIString(WIDE_FILENAME);            // Codepage conversion from UTF16 to ANSI
  strm := TFileStream.Create(sFilename, fmOpenRead); // Will implicitly convert *back* from ANSI to WIDE

对比

// Unicode compiler using String type....
var
  sFilename: String;
begin
  sFilename := String(WIDE_FILENAME);                // String type conversion from WideString to UnicodeString
  strm := TFileStream.Create(sFilename, fmOpenRead); // No further conversion necessary

最好的解决方案是使用 Unicode,但如果这不是一个选项,您仍然可以解决问题。

在 Windows 中,您可以设置非 Unicode 程序使用的代码页。只需更改它以支持正确的语言(西班牙语?)。然后代码应该可以工作。

  • Windows 7:控制面板 > 区域和语言 > 管理 > 非 Unicode 程序的语言

  • Windows XP:控制面板 > 区域和语言 > 高级 > 非 Unicode 程序的语言