I need a POSIX or Linux API function that takes file path and returns this file's extension. Every platform should have one, but I can't it for Linux. What's it called?
问题:
回答1:
First use strrchr
to find the last '.'
in the pathname. If it doesn't exist, there's no "extension".
Next, use strchr
to check whether there's any '/'
after the last '.'
. If so, the last '.'
is in a directory component, not the filename, so there's no extension.
Otherwise, you found the extension. You can use the pointer to the position one past the '.'
directly as a C string. No need to copy it to new storage unless the original string will be freed or clobbered before you use it.
Note: The above is assuming you define "extension" as only the final '.'
-delimited component. If you want to consider things like .tar.gz
and .cpp.bak
as extensions, a slightly different approach works:
First, use strrchr
to find the final '/'
. If not found, treat the start of the string as your result.
Second, use strchr
to find the first '.'
starting from the position you just found. The result is your extension.
回答2:
I don't think there's a default function for this.
In my filesystem library, I just apply string operations.
First, I get the filename with extension from the full path, looking for /
separators and extracting everything after the last one. Then, I grab everything after the first .
dot character, including the dot itself. It worked well so far.
Remember that some system files can start with a .
dot character - so check if the filename begins with the dot character before extracting the extension.
Algorithm
- Get file name from full path by removing folder names from the left:
/home/test/.myfile.cpp.bak
->/test/.myfile.cpp.bak
->/.myfile.cpp.bak
->.myfile.cpp.bak
- Check if the file name begins with
.
:- If it does, remove it from current file name
.myfile.cpp.bak
->myfile.cpp.bak
- If it does, remove it from current file name
- Now, extract everything after the first
.
you encounter from the left (if you want multiple extensions) - otherwise, extract everything after the last.
from the leftmyfile.cpp.bak
->.cpp.bak
(first case)myfile.cpp.bak
->.bak
(second case)
回答3:
Including boost for filesystem is a bit too much. But as boost implementation reach TR2 and is implemented in visual studio it's maybe time to start looking at it.
http://cpprocks.com/introduction-to-tr2-filesystem-library-in-vs2012/
http://msdn.microsoft.com/en-us/library/hh874694.aspx
回答4:
What seems to me the best way to solve this problem (in absence of API function, which itself is weird) is to combine Vittorio's and R.'s answers with basename
function that takes a path and returns the file name, if the path points to a file: http://linux.die.net/man/3/basename
I also convert the resulting string to UTF-16 with mbstowcs
and do all the finding with 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;
}