在Delphi中,如何根据MIME类型获得标准的文件扩展名?

4
有没有内置的方法可以在Delphi(XE7)中获取给定MIME类型的标准扩展名?
我正在寻找最简单和最通用的实现方式,以实现像这样调用的函数:
fileExt := GetExtension('text/xml');

我不知道,但是快速谷歌搜索可以找到这个链接:https://www.thoughtco.com/file-extensions-and-mime-types-3469109 - Tuncay Göncüoğlu
谢谢您提供的链接,但我希望能够使用系统函数,因为 MIME 类型集合随着时间的推移而发生变化。例如,在您提供的表格中,没有列出 docx(application/vnd.openxmlformats-officedocument.wordprocessingml.document)这种类型。 - Helmut D
4个回答

5

看起来Indy已经有一个内置的函数可以处理这个问题,它在TIdThreadSafeMimeTable中:

Uses
  IdCustomHTTPServer;


function GetMIMETypeDefaultExtension(const aMIMEType: String): String;
var
  mimetable: TIdThreadSafeMimeTable;
Begin
  if not(aMIMEType.Trim.IsEmpty) then
  Begin
    mimetable := TIdThreadSafeMimeTable.Create(true);
    try
      result := mimetable.GetDefaultFileExt(aMIMEType);
    finally
      mimetable.Free;
    end
  End
  else
      result := '';
End;

编辑:函数已修复,直接使用TIdThreadSafeMimeTable而无需自定义http服务器。


1
您也可以直接在同一单元中使用TIdThreadSafeMimeTable(无需创建服务器)。 - mjn42
根据您的建议,我已将答案更改为使用该类。 - Tuncay Göncüoğlu
2
TIdThreadSafeMimeTable 旨在与 TIdHTTPServer 一起使用,因为它是一个多线程服务器,其工作线程经常需要访问缓存的 MIME 信息。在 IdGlobalProtocols 单元中有一个非线程安全的 TIdMimeTable,它还具有独立的 GetMIMETypeFromFile()GetMIMEDefaultFileExt() 函数(它们在内部使用 TIdMimeTable)。在上面的示例中,由于每次调用时都会创建和销毁表格,因此使用 TIdThreadSafeMimeTable 是过度的,只需使用 TIdMimeTable 或甚至 GetMIMEDefaultFileExt() 即可。 - Remy Lebeau
真的,但在上面的函数中,您仍然必须创建和销毁实例,无论是直接还是间接地调用buildcache,因此,使用非线程安全版本不会带来任何好处。而且当这种情况发生时,我更喜欢拥有一个通用函数,我不必担心它是否线程安全。 - Tuncay Göncüoğlu

5

Indy的IndyProtocols包中有一个TIdMimeTable类和独立的GetMIMETypeFromFile()GetMIMEDefaultFileExt()包装函数,它们位于IdGlobalProtocols单元中。

uses
  ..., IdGlobalProtocols;

function GetExtension(const AMIMEType: string);
begin
  Result := GetMIMEDefaultFileExt(AMIMEType);
end

请注意,GetMIMEDefaultFileExt() 内部创建并销毁了一个TIdMimeTable对象,该对象每次创建时都会重新构建已知扩展名和MIME类型的列表。如果您经常查询MIME扩展名,则值得创建自己的TIdMimeTable对象(或TIdThreadSafeMimeTable如果需要在多个线程之间共享表格)并在每次重复使用它:
uses
  ..., IdGlobalProtocols;

var
  MimeTable: TIdMimeTable = nil;

function GetExtension(const AMIMEType: string);
begin
  if MimeTable = nil then
    MimeTable := TIdMimeTable.Create;
  Result := MimeTable.GetDefaultFileExt(AMIMEType);
end;

initialization
finalization
  MimeTable.Free;

uses
  ..., IdGlobalProtocols, IdCustomHTTPServer;

var
  MimeTable: TIdThreadSafeMimeTable = nil;

function GetExtension(const AMIMEType: string);
begin
  if MimeTable = nil then
    MimeTable := TIdThreadSafeMimeTable.Create;
  Result := MimeTable.GetDefaultFileExt(AMIMEType);
end;

initialization
finalization
  MimeTable.Free;

3

HKEY_CLASSES_ROOT\MIME\Database\Content Type\text/html 的 Extension 值。


肯定有API或某种标准的封装方法。如果没有文档说明这是稳定的,那么看起来就像是脆弱的注册表黑客攻击。 - David Heffernan
@DavidHeffernan Indy 也使用了这个注册表键,所以我们可以认为这是“官方”的方式。 - Denis Anisimov
2
没有Win32 API可以查询Windows的MIME数据库,但它的注册表键在MSDN的多个位置都有记录,因此其位置已知且不太可能在Windows版本之间发生变化。此外,Indy并不仅仅依赖于注册表。它有一个长列表的默认值,然后使用注册表来覆盖/填补任何缺失的部分。 - Remy Lebeau

1

对于更高版本的Delphi,您可以使用System.Net.Mime单元中的TMimeTypes类。

有两种方法可以用来填充内部字典以执行查找。第一个AddDefTypes将添加标准类型,方法AddOSTypes将添加主机操作系统定义的任何类型(对于Windows,它会进行注册表扫描)。如果调用TMimeTypes.GetDefault,它将在首次调用时使用这两种方法构造一个TMimeTypes实例(单例)。


1
这是在Delphi 10.2.3中添加的。 https://blog.marcocantu.com/blog/2018-march-rtl-10-2-3.html - Darian Miller

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接