POSIX 或 Linux API 函数从路径获取文件扩展名
Posted
技术标签:
【中文标题】POSIX 或 Linux API 函数从路径获取文件扩展名【英文标题】:POSIX or Linux API function to get file extension from path 【发布时间】:2013-08-27 13:22:50 【问题描述】:我需要一个 POSIX 或 Linux API 函数,它接受文件路径并返回此文件的扩展名。每个平台都应该有一个,但对于 Linux,我不能。它叫什么?
【问题讨论】:
文件扩展名在 unix 世界中没有什么意义 使用boost::filesystem
的更便携的解决方案不是更可取吗?
@juanchopanza:如果我已经使用了 boost,可能是这样,但我不会只为这个功能包含它。在 Windows 上我有 WinAPI 函数,在 Mac 上我有 Cocoa 函数。
【参考方案1】:
首先使用strrchr
查找路径名中的最后一个'.'
。如果它不存在,则没有“扩展”。
接下来,使用strchr
检查最后一个'.'
之后是否有'/'
。如果是这样,则最后一个 '.'
位于目录组件中,而不是文件名中,因此没有扩展名。
否则,您找到了扩展程序。您可以将指向'.'
之后位置的指针直接用作C 字符串。无需将其复制到新存储中,除非原始字符串在您使用之前会被释放或破坏。
注意:以上假设您将“扩展”定义为仅最后一个'.'
-delimited 组件。如果您想将 .tar.gz
和 .cpp.bak
之类的东西视为扩展,则可以使用稍微不同的方法:
首先,使用strrchr
找到最终的'/'
。如果未找到,则将字符串的开头视为结果。
其次,使用strchr
从刚刚找到的位置开始,找到第一个'.'
。结果就是你的扩展。
【讨论】:
-1 因为std::string::find
存在。无需在 C++ 中使用可能不安全的 C 风格函数。
以只读方式使用的任何函数都没有“不安全”的地方。此外,OP 在 C 和 C++ 中都标记了这个问题,因此在这两种语言中都可以使用的答案是唯一合适的答案。
错过了C
标签。删除了反对票。尽管如此,如果用户想要获得多个扩展名(在.cpp.bak
的情况下)并且文件名以.
开头,这仍然不起作用。此外,如果用户使用的是 C++,那么使用 C 风格的函数是不习惯的。
好的,我为您的扩展定义添加了一个替代版本。
@R..:公平点,C
标签已删除。感谢您指出我的问题标题表述不佳。【参考方案2】:
我认为这没有默认功能。
在我的文件系统库中,我只是应用字符串操作。
首先,我从完整路径中获取带有扩展名的文件名,寻找/
分隔符并提取最后一个之后的所有内容。然后,我抓取第一个 .
点字符之后的所有内容,包括点本身。到目前为止效果很好。
请记住,某些系统文件可以以 .
点字符开头 - 因此在提取扩展名之前检查文件名是否以点字符开头。
算法
-
通过从左侧删除文件夹名称从完整路径获取文件名:
/home/test/.myfile.cpp.bak
->
/test/.myfile.cpp.bak
->
/.myfile.cpp.bak
->
.myfile.cpp.bak
检查文件名是否以.
开头:
如果有,请将其从当前文件名中删除 .myfile.cpp.bak
-> myfile.cpp.bak
现在,从左侧提取您遇到的第一个 .
之后的所有内容(如果您想要多个扩展名) - 否则,从左侧提取最后一个 .
之后的所有内容
myfile.cpp.bak
-> .cpp.bak
(第一种情况)
myfile.cpp.bak
-> .bak
(第二种情况)
【讨论】:
如果它是一个以点开头的系统文件?当然,我可以手动完成,并且它适用于大多数情况。但不是全部。 这太复杂了。 @VittorioRomeo:“查找扩展名”不需要分离目录和文件名组件。这些是完全独立的操作,当您想要的是扩展时,它们不应该发挥作用。 如果你想使用“扩展”的定义(注意:“扩展”没有以任何标准方式定义)你可以strrchr
首先找到最后一个'/'
,然后搜索第一个'.'
。制作多个临时字符串绝对没有任何意义,这既低效又(更糟糕)可能会失败,必须检查正确的代码,这会使您的代码更加复杂和容易出错。跨度>
R..:好点。如果用户想要做的只是获取文件的扩展名,那么您的答案是更合适的。【参考方案3】:
包括文件系统的提升有点太多了。但随着 boost 实现达到 TR2 并在 Visual Studio 中实现,也许是时候开始研究它了。http://cpprocks.com/introduction-to-tr2-filesystem-library-in-vs2012/http://msdn.microsoft.com/en-us/library/hh874694.aspx
【讨论】:
是的,我读过。如果即使 Microsoft 执行文件系统的 TR2 实现,也几乎可以肯定该实现将达到标准化。所以我们今天可以使用它,并且有一种已经是可移植的方式,也许是标准的方式来处理文件和路径。【参考方案4】:在我看来,解决这个问题的最佳方法(在没有 API 函数的情况下,这本身很奇怪)是将 Vittorio 和 R. 的答案与 basename
函数结合起来,该函数采用路径并返回文件名,如果路径指向一个文件:http://linux.die.net/man/3/basename
我还使用mbstowcs
将结果字符串转换为UTF-16,并使用std::wstring
进行所有查找:
std::wstring fileExtFromPath (const char * path)
const char * fileName = basename(filePath);
wchar_t buffer [MAX_PATH] = 0; // Use mblen if you don't like MAX_PATH
const std::wstring fileNameW (buffer);
const size_t pointPosition = fileNameW.rfind(L".");
const std::wstring fileExtW = pointPosition == 0 ? std::wstring() : fileNameW.substr( + 1);
return fileExtW;
【讨论】:
以上是关于POSIX 或 Linux API 函数从路径获取文件扩展名的主要内容,如果未能解决你的问题,请参考以下文章