Get a file name from a path
What is the simplest way to get the file name that from a path?
string filename = "C:\MyDirectory\MyFile.bat"
In this example, I should get "MyFile". without extension.
c++ visual-c++
add a comment |
What is the simplest way to get the file name that from a path?
string filename = "C:\MyDirectory\MyFile.bat"
In this example, I should get "MyFile". without extension.
c++ visual-c++
1
Search from the back until you hit a backspace?
– Kerrek SB
Dec 15 '11 at 13:13
2
@KerrekSB, you mean backslash ;)
– Nim
Dec 15 '11 at 13:14
i have an std::string that contains a path of a file "c:\MyDirectory\Myfile.pdf" i need to rename this file to myfile_md.pdf so i need to get the file name from the path.
– nidhal
Dec 15 '11 at 13:20
1
If you need to do a lot of work with file paths consider using Boost FileSystem boost.org/doc/libs/release/libs/filesystem/v3/doc/index.htm
– edA-qa mort-ora-y
Dec 15 '11 at 13:26
2
@Nim: Yes! I must have been spacing out...
– Kerrek SB
Dec 15 '11 at 13:42
add a comment |
What is the simplest way to get the file name that from a path?
string filename = "C:\MyDirectory\MyFile.bat"
In this example, I should get "MyFile". without extension.
c++ visual-c++
What is the simplest way to get the file name that from a path?
string filename = "C:\MyDirectory\MyFile.bat"
In this example, I should get "MyFile". without extension.
c++ visual-c++
c++ visual-c++
edited Oct 18 '13 at 0:20
Prashant Kumar
11.2k134059
11.2k134059
asked Dec 15 '11 at 13:05
nidhalnidhal
4743814
4743814
1
Search from the back until you hit a backspace?
– Kerrek SB
Dec 15 '11 at 13:13
2
@KerrekSB, you mean backslash ;)
– Nim
Dec 15 '11 at 13:14
i have an std::string that contains a path of a file "c:\MyDirectory\Myfile.pdf" i need to rename this file to myfile_md.pdf so i need to get the file name from the path.
– nidhal
Dec 15 '11 at 13:20
1
If you need to do a lot of work with file paths consider using Boost FileSystem boost.org/doc/libs/release/libs/filesystem/v3/doc/index.htm
– edA-qa mort-ora-y
Dec 15 '11 at 13:26
2
@Nim: Yes! I must have been spacing out...
– Kerrek SB
Dec 15 '11 at 13:42
add a comment |
1
Search from the back until you hit a backspace?
– Kerrek SB
Dec 15 '11 at 13:13
2
@KerrekSB, you mean backslash ;)
– Nim
Dec 15 '11 at 13:14
i have an std::string that contains a path of a file "c:\MyDirectory\Myfile.pdf" i need to rename this file to myfile_md.pdf so i need to get the file name from the path.
– nidhal
Dec 15 '11 at 13:20
1
If you need to do a lot of work with file paths consider using Boost FileSystem boost.org/doc/libs/release/libs/filesystem/v3/doc/index.htm
– edA-qa mort-ora-y
Dec 15 '11 at 13:26
2
@Nim: Yes! I must have been spacing out...
– Kerrek SB
Dec 15 '11 at 13:42
1
1
Search from the back until you hit a backspace?
– Kerrek SB
Dec 15 '11 at 13:13
Search from the back until you hit a backspace?
– Kerrek SB
Dec 15 '11 at 13:13
2
2
@KerrekSB, you mean backslash ;)
– Nim
Dec 15 '11 at 13:14
@KerrekSB, you mean backslash ;)
– Nim
Dec 15 '11 at 13:14
i have an std::string that contains a path of a file "c:\MyDirectory\Myfile.pdf" i need to rename this file to myfile_md.pdf so i need to get the file name from the path.
– nidhal
Dec 15 '11 at 13:20
i have an std::string that contains a path of a file "c:\MyDirectory\Myfile.pdf" i need to rename this file to myfile_md.pdf so i need to get the file name from the path.
– nidhal
Dec 15 '11 at 13:20
1
1
If you need to do a lot of work with file paths consider using Boost FileSystem boost.org/doc/libs/release/libs/filesystem/v3/doc/index.htm
– edA-qa mort-ora-y
Dec 15 '11 at 13:26
If you need to do a lot of work with file paths consider using Boost FileSystem boost.org/doc/libs/release/libs/filesystem/v3/doc/index.htm
– edA-qa mort-ora-y
Dec 15 '11 at 13:26
2
2
@Nim: Yes! I must have been spacing out...
– Kerrek SB
Dec 15 '11 at 13:42
@Nim: Yes! I must have been spacing out...
– Kerrek SB
Dec 15 '11 at 13:42
add a comment |
18 Answers
18
active
oldest
votes
_splitpath should do what you need. You could of course do it manually but _splitpath
handles all special cases as well.
EDIT:
As BillHoag mentioned it is recommended to use the more safe version of _splitpath
called _splitpath_s when available.
Or if you want something portable you could just do something like this
std::vector<std::string> splitpath(
const std::string& str
, const std::set<char> delimiters)
{
std::vector<std::string> result;
char const* pch = str.c_str();
char const* start = pch;
for(; *pch; ++pch)
{
if (delimiters.find(*pch) != delimiters.end())
{
if (start != pch)
{
std::string str(start, pch);
result.push_back(str);
}
else
{
result.push_back("");
}
start = pch + 1;
}
}
result.push_back(start);
return result;
}
...
std::set<char> delims{'\'};
std::vector<std::string> path = splitpath("C:\MyDirectory\MyFile.bat", delims);
cout << path.back() << endl;
2
There's no_splitpath
in any of the includes on my machine.
– James Kanze
Dec 15 '11 at 13:22
6
I have Visual Studio, and g++, and Sun CC. Why should I use something non-standard when there are perfectly good portable solutions.
– James Kanze
Dec 15 '11 at 13:49
1
@James, the page linked to says it is in<stdlib.h>
. As for portability, perhaps you can list some examples of “perfectly good portable solutions”?
– Synetech
Apr 4 '12 at 3:35
1
@Synetech The page linked to describes a Microsoft extension, not<stdlib.h>
. And the mot obvious portable solution isboost::filesystem
.
– James Kanze
Apr 4 '12 at 7:19
3
@James, you don’t have_splitpath
in thestdlib.h
of your copy of VS? Then you may want to do a repair install of VS.
– Synetech
Apr 4 '12 at 19:05
|
show 5 more comments
A possible solution:
string filename = "C:\MyDirectory\MyFile.bat";
// Remove directory if present.
// Do this before extension removal incase directory has a period character.
const size_t last_slash_idx = filename.find_last_of("\/");
if (std::string::npos != last_slash_idx)
{
filename.erase(0, last_slash_idx + 1);
}
// Remove extension if present.
const size_t period_idx = filename.rfind('.');
if (std::string::npos != period_idx)
{
filename.erase(period_idx);
}
the simplest is always the best!
– Jean-François Fabre
Apr 4 '18 at 15:12
add a comment |
The simplest solution is to use something like boost::filesystem
. If
for some reason this isn't an option...
Doing this correctly will require some system dependent code: under
Windows, either '\'
or '/'
can be a path separator; under Unix,
only '/'
works, and under other systems, who knows. The obvious
solution would be something like:
std::string
basename( std::string const& pathname )
{
return std::string(
std::find_if( pathname.rbegin(), pathname.rend(),
MatchPathSeparator() ).base(),
pathname.end() );
}
, with MatchPathSeparator
being defined in a system dependent header
as either:
struct MatchPathSeparator
{
bool operator()( char ch ) const
{
return ch == '/';
}
};
for Unix, or:
struct MatchPathSeparator
{
bool operator()( char ch ) const
{
return ch == '\' || ch == '/';
}
};
for Windows (or something still different for some other unknown
system).
EDIT: I missed the fact that he also wanted to suppress the extention.
For that, more of the same:
std::string
removeExtension( std::string const& filename )
{
std::string::const_reverse_iterator
pivot
= std::find( filename.rbegin(), filename.rend(), '.' );
return pivot == filename.rend()
? filename
: std::string( filename.begin(), pivot.base() - 1 );
}
The code is a little bit more complex, because in this case, the base of
the reverse iterator is on the wrong side of where we want to cut.
(Remember that the base of a reverse iterator is one behind the
character the iterator points to.) And even this is a little dubious: I
don't like the fact that it can return an empty string, for example.
(If the only '.'
is the first character of the filename, I'd argue
that you should return the full filename. This would require a little
bit of extra code to catch the special case.)
}
8
How about usingstring::find_last_of
instead of manipulating reverse iterators?
– Luc Touraille
Dec 15 '11 at 14:04
@LucTouraille Why learn two ways of doing things when one will do? You'd need the reverse iterators for any container exceptstring
, so you have to learn them anyway. And having learned them, there's no reason to bother learning all of the bloated interface tostd::string
.
– James Kanze
Dec 15 '11 at 15:35
Note: The <filesystem> header ships with Visual Studio 2015 and above, so you don't have to add a dependency on boost to use it.
– IInspectable
May 2 '17 at 10:39
add a comment |
The task is fairly simple as the base filename is just the part of the string starting at the last delimeter for folders:
std::string base_filename = path.substr(path.find_last_of("/\") + 1)
If the extension is to be removed as well the only thing to do is find the last .
and take a substr
to this point
std::string::size_type const p(base_filename.find_last_of('.'));
std::string file_without_extension = base_filename.substr(0, p);
Perhaps there should be a check to cope with files solely consisting of extensions (ie .bashrc
...)
If you split this up into seperate functions you're flexible to reuse the single tasks:
template<class T>
T base_name(T const & path, T const & delims = "/\")
{
return path.substr(path.find_last_of(delims) + 1);
}
template<class T>
T remove_extension(T const & filename)
{
typename T::size_type const p(filename.find_last_of('.'));
return p > 0 && p != T::npos ? filename.substr(0, p) : filename;
}
The code is templated to be able to use it with different std::basic_string
instances (i.e. std::string
& std::wstring
...)
The downside of the templation is the requirement to specify the template parameter if a const char *
is passed to the functions.
So you could either:
A) Use only std::string
instead of templating the code
std::string base_name(std::string const & path)
{
return path.substr(path.find_last_of("/\") + 1);
}
B) Provide wrapping function using std::string
(as intermediates which will likely be inlined / optimized away)
inline std::string string_base_name(std::string const & path)
{
return base_name(path);
}
C) Specify the template parameter when calling with const char *
.
std::string base = base_name<std::string>("some/path/file.ext");
Result
std::string filepath = "C:\MyDirectory\MyFile.bat";
std::cout << remove_extension(base_name(filepath)) << std::endl;
Prints
MyFile
In this use case everything is OK (and original question is answered), but your extension remover is not perfect - it will fail if we pass there something like "/home/user/my.dir/myfile"
– avtomaton
Aug 27 '15 at 8:03
@avtomaton The extension removing function should be used on a file name not a path. (Just applybase_name
first.)
– Pixelchemist
Aug 27 '15 at 9:14
I understand it (that's why I wrote that original question is answered and in this use-case everything is OK). Just wanted to point out to this issue for somebody who will try to use these snippets.
– avtomaton
Aug 27 '15 at 10:14
Very nice explanation. It enhances the structural understanding of the problem. Thanks
– hell_ical_vortex
May 18 '16 at 7:15
add a comment |
You can also use the shell Path APIs PathFindFileName, PathRemoveExtension. Probably worse than _splitpath for this particular problem, but those APIs are very useful for all kinds of path parsing jobs and they take UNC paths, forward slashes and other weird stuff into account.
wstring filename = L"C:\MyDirectory\MyFile.bat";
wchar_t* filepart = PathFindFileName(filename.c_str());
PathRemoveExtension(filepart);
http://msdn.microsoft.com/en-us/library/windows/desktop/bb773589(v=vs.85).aspx
The drawback is that you have to link to shlwapi.lib, but I'm not really sure why that's a drawback.
My preferred solution for getting a filename from a path.
– mrt
May 12 '17 at 6:32
add a comment |
If you can use boost,
#include <boost/filesystem.hpp>
path p("C:\MyDirectory\MyFile.bat");
string basename = p.filename().string();
//or
//string basename = path("C:\MyDirectory\MyFile.bat").filename().string();
This is all.
I recommend you to use boost library. Boost gives you a lot of conveniences when you work with C++. It supports almost all platforms.
If you use Ubuntu, you can install boost library by only one line sudo apt-get install libboost-all-dev
(ref. How to Install boost on Ubuntu?)
add a comment |
Function:
#include <string>
std::string
basename(const std::string &filename)
{
if (filename.empty()) {
return {};
}
auto len = filename.length();
auto index = filename.find_last_of("/\");
if (index == std::string::npos) {
return filename;
}
if (index + 1 >= len) {
len--;
index = filename.substr(0, len).find_last_of("/\");
if (len == 0) {
return filename;
}
if (index == 0) {
return filename.substr(1, len - 1);
}
if (index == std::string::npos) {
return filename.substr(0, len);
}
return filename.substr(index + 1, len - index - 1);
}
return filename.substr(index + 1, len - index);
}
Tests:
#define CATCH_CONFIG_MAIN
#include <catch/catch.hpp>
TEST_CASE("basename")
{
CHECK(basename("") == "");
CHECK(basename("no_path") == "no_path");
CHECK(basename("with.ext") == "with.ext");
CHECK(basename("/no_filename/") == "no_filename");
CHECK(basename("no_filename/") == "no_filename");
CHECK(basename("/no/filename/") == "filename");
CHECK(basename("/absolute/file.ext") == "file.ext");
CHECK(basename("../relative/file.ext") == "file.ext");
CHECK(basename("/") == "/");
CHECK(basename("c:\windows\path.ext") == "path.ext");
CHECK(basename("c:\windows\no_filename\") == "no_filename");
}
add a comment |
From C++ Docs - string::find_last_of
#include <iostream> // std::cout
#include <string> // std::string
void SplitFilename (const std::string& str) {
std::cout << "Splitting: " << str << 'n';
unsigned found = str.find_last_of("/\");
std::cout << " path: " << str.substr(0,found) << 'n';
std::cout << " file: " << str.substr(found+1) << 'n';
}
int main () {
std::string str1 ("/usr/bin/man");
std::string str2 ("c:\windows\winhelp.exe");
SplitFilename (str1);
SplitFilename (str2);
return 0;
}
Outputs:
Splitting: /usr/bin/man
path: /usr/bin
file: man
Splitting: c:windowswinhelp.exe
path: c:windows
file: winhelp.exe
Don't forget (and to handle) thatfind_last_of
returnsstring::npos
if nothing was found.
– congusbongus
Mar 14 '16 at 23:53
@congusbongus True, but there is no sense of splitting the file path when it is just a file name (without path) :)
– jave.web
Mar 15 '16 at 11:05
@jave.web It does make sense and MUST handle returns 'string::npos'. Implementing a function for this should be able to handle different inputs including "just filename". Otherwise, it will be useless if its buggy in actual implementation.
– winux
Sep 22 '16 at 8:09
@winux This considers already valid PATHS... If you don't trust the input, you should, of course, validate the path first.
– jave.web
Sep 23 '16 at 13:07
@winux Anyway the check forstring::npos
does not need to be done because of the way how this andstring::substr
are implemented. a)string::npos
is passed as "length" =>substr
has documented behaviour of reading all until end. b)substr
is given "string::npos + 1
" and no length:string::npos
is documented to have a value of-1
, so that evaluates to0
=> start of the string and lengths' default value forsubstr
is thenpos
=> works on "just filename" too cplusplus.com/reference/string/string/substr cplusplus.com/reference/string/string/npos
– jave.web
Sep 23 '16 at 13:07
add a comment |
The Simplest way in cpp17 is:
use the #include experimental/filesystem and filename() for filename with extension and stem() without extension.
#include <iostream>
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
int main()
{
string filename = "C:\MyDirectory\MyFile.bat";
std::cout << fs::path(filename).filename() << 'n'
<< fs::path(filename).stem() << 'n'
<< fs::path("/foo/bar.txt").filename() << 'n'
<< fs::path("/foo/bar.txt").stem() << 'n'
<< fs::path("/foo/.bar").filename() << 'n'
<< fs::path("/foo/bar/").filename() << 'n'
<< fs::path("/foo/.").filename() << 'n'
<< fs::path("/foo/..").filename() << 'n'
<< fs::path(".").filename() << 'n'
<< fs::path("..").filename() << 'n'
<< fs::path("/").filename() << 'n';
}
output:
MyFile.bat
MyFile
"bar.txt"
".bar"
"."
"."
".."
"."
".."
"/"
Ref: cppreference
add a comment |
C++11 variant (inspired by James Kanze's version) with uniform initialization and anonymous inline lambda.
std::string basename(const std::string& pathname)
{
return {std::find_if(pathname.rbegin(), pathname.rend(),
(char c) { return c == '/'; }).base(),
pathname.end()};
}
It does not remove the file extension though.
Short and sweet, although it only works with non-Windows paths.
– Volomike
Mar 5 '16 at 18:33
you can always change lambda return toreturn c == '/' || c == '\';
to make it works on windows
– ziomq1991
Apr 19 '16 at 9:57
To handle paths such as "", "///", and "dir1/dir2/", add the following code before the return statement above (cf. POSIX basename()):if (pathname.size() == 0) return "."; auto iter = pathname.rbegin(); auto rend = pathname.rend(); while (iter != rend && *iter == '/') ++iter; if (iter == rend) /* pathname has only path separators */ return "/"; pathname = std::string(pathname.begin(), iter.base());
– Gidfiddle
Oct 27 '17 at 6:14
add a comment |
this is the only thing that actually finally worked for me:
#include "Shlwapi.h"
CString some_string = "c:\path\hello.txt";
LPCSTR file_path = some_string.GetString();
LPCSTR filepart_c = PathFindFileName(file_path);
LPSTR filepart = LPSTR(filepart_c);
PathRemoveExtension(filepart);
pretty much what Skrymsli suggested but doesn't work with wchar_t*,
VS Enterprise 2015
_splitpath worked as well, but I don't like having to guess at how many char[?] characters I'm going to need; some people probably need this control, i guess.
CString c_model_name = "c:\path\hello.txt";
char drive[200];
char dir[200];
char name[200];
char ext[200];
_splitpath(c_model_name, drive, dir, name, ext);
I don't believe any includes were needed for _splitpath. No external libraries (like boost) were needed for either of these solutions.
add a comment |
I would do it by...
Search backwards from the end of the string until you find the first backslash/forward slash.
Then search backwards again from the end of the string until you find the first dot (.)
You then have the start and end of the file name.
Simples...
Which doesn't work for any system I know. (The one system which accepts'\'
as a path separator also uses'/'
, so you need to match either.) And I'm not sure what you'd be looking forward for.
– James Kanze
Dec 15 '11 at 13:32
Okay so modify it to match either, no biggy. And looking forward for the first dot (.)
– TomP89
Dec 15 '11 at 13:48
You still have to find the last dot, not the first. (Reverse iterators are your friend!)
– James Kanze
Dec 15 '11 at 13:56
Ah yes, good point. So for a file.ext.ext then you would want to extract file.ext wouldn't you. :)
– TomP89
Dec 15 '11 at 13:57
Presumably. That's the usual convention, in any case:my.source.cpp
gets compiled tomy.source.obj
, for example (with the extension.cpp
replaced with.obj
).
– James Kanze
Dec 15 '11 at 14:02
add a comment |
The boost
filesystem
library is also available as the experimental/filesystem
library and was merged into ISO C++ for C++17. You can use it like this:
#include <iostream>
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
int main () {
std::cout << fs::path("/foo/bar.txt").filename() << 'n'
}
Output:
"bar.txt"
It also works for std::string
objects.
Note that the later answer of @eliastem is the same...
– Adam Erickson
Jul 4 '18 at 1:25
add a comment |
m_szFilePath.MakeLower();
CFileFind finder;
DWORD buffSize = MAX_PATH;
char longPath[MAX_PATH];
DWORD result = GetLongPathName(m_szFilePath, longPath, MAX_PATH );
if( result == 0)
{
m_bExists = FALSE;
return;
}
m_szFilePath = CString(longPath);
m_szFilePath.Replace("/","\");
m_szFilePath.Trim();
//check if it does not ends in => remove it
int length = m_szFilePath.GetLength();
if( length > 0 && m_szFilePath[length - 1] == '\' )
{
m_szFilePath.Truncate( length - 1 );
}
BOOL bWorking = finder.FindFile(this->m_szFilePath);
if(bWorking){
bWorking = finder.FindNextFile();
finder.GetCreationTime(this->m_CreationTime);
m_szFilePath = finder.GetFilePath();
m_szFileName = finder.GetFileName();
this->m_szFileExtension = this->GetExtension( m_szFileName );
m_szFileTitle = finder.GetFileTitle();
m_szFileURL = finder.GetFileURL();
finder.GetLastAccessTime(this->m_LastAccesTime);
finder.GetLastWriteTime(this->m_LastWriteTime);
m_ulFileSize = static_cast<unsigned long>(finder.GetLength());
m_szRootDirectory = finder.GetRoot();
m_bIsArchive = finder.IsArchived();
m_bIsCompressed = finder.IsCompressed();
m_bIsDirectory = finder.IsDirectory();
m_bIsHidden = finder.IsHidden();
m_bIsNormal = finder.IsNormal();
m_bIsReadOnly = finder.IsReadOnly();
m_bIsSystem = finder.IsSystem();
m_bIsTemporary = finder.IsTemporary();
m_bExists = TRUE;
finder.Close();
}else{
m_bExists = FALSE;
}
The variable m_szFileName contains the fileName.
3
wow - that's a lot of code for "get file name" from path... :)
– Nim
Dec 15 '11 at 13:15
4
@Nim My impression as well. In my own code, I use a one-liner:boost::filesystem::path( path ).filename()
.
– James Kanze
Dec 15 '11 at 13:36
I have a CFileInfo class that has that code. I just dumped the code here because it is tested and I did not want to risk anything... You could just use about 5 lines of code from this example.
– Lucian
Dec 15 '11 at 13:42
add a comment |
Dont use _splitpath()
and _wsplitpath()
. They are not safe, and they are obsolete!
Instead, use their safe versions, namely _splitpath_s()
and _wsplitpath_s()
add a comment |
This should work too :
// strPath = "C:\Dir\File.bat" for example
std::string getFileName(const std::string& strPath)
{
size_t iLastSeparator = 0;
return strPath.substr((iLastSeparator = strPath.find_last_of("\")) != std::string::npos ? iLastSeparator + 1 : 0, strPath.size() - strPath.find_last_of("."));
}
If you can use it, Qt provide QString (with split, trim etc), QFile, QPath, QFileInfo etc to manipulate files, filenames and directories. And of course it's also cross plaftorm.
4
For the sake of the future readers of your code, please use temporary variables with meaningful names instead of stuffing everything into a single line of code (and while you're at it, please encapsulate all this into a functiongetFilename
or something like that).
– Luc Touraille
Dec 15 '11 at 14:07
edited. But the point was to make it short, as several working answers already have been given.
– typedef
Dec 15 '11 at 14:32
1
I think it is WRONG. Should not you replace the last part: "strPath.size() - strPath.find_last_of(".")" by "strPath.find_last_of(".") - iLastSeparator"
– taktak004
Jan 22 '14 at 12:35
@taktak004 you are right, it should be ` return strPath.substr( (iLastSeparator = strPath.find_last_of("/")) != std::string::npos ? iLastSeparator + 1 : 0, strPath.find_last_of(".") - iLastSeparator );`
– phenmod
Dec 8 '15 at 10:08
add a comment |
For long time I was looking for a function able to properly decompose file path. For me this code is working perfectly for both Linux and Windows.
void decomposePath(const char *filePath, char *fileDir, char *fileName, char *fileExt)
{
#if defined _WIN32
const char *lastSeparator = strrchr(filePath, '\');
#else
const char *lastSeparator = strrchr(filePath, '/');
#endif
const char *lastDot = strrchr(filePath, '.');
const char *endOfPath = filePath + strlen(filePath);
const char *startOfName = lastSeparator ? lastSeparator + 1 : filePath;
const char *startOfExt = lastDot > startOfName ? lastDot : endOfPath;
if(fileDir)
_snprintf(fileDir, MAX_PATH, "%.*s", startOfName - filePath, filePath);
if(fileName)
_snprintf(fileName, MAX_PATH, "%.*s", startOfExt - startOfName, startOfName);
if(fileExt)
_snprintf(fileExt, MAX_PATH, "%s", startOfExt);
}
Example results are:
fileDir: ''
fileName: ''
fileExt: ''
[.htaccess]
fileDir: ''
fileName: '.htaccess'
fileExt: ''
[a.exe]
fileDir: ''
fileName: 'a'
fileExt: '.exe'
[ab.c]
fileDir: 'a'
fileName: 'b'
fileExt: '.c'
[git-archive]
fileDir: ''
fileName: 'git-archive'
fileExt: ''
[git-archive.exe]
fileDir: ''
fileName: 'git-archive'
fileExt: '.exe'
[D:Gitmingw64libexecgit-core.htaccess]
fileDir: 'D:Gitmingw64libexecgit-core'
fileName: '.htaccess'
fileExt: ''
[D:Gitmingw64libexecgit-corea.exe]
fileDir: 'D:Gitmingw64libexecgit-core'
fileName: 'a'
fileExt: '.exe'
[D:Gitmingw64libexecgit-coregit-archive.exe]
fileDir: 'D:Gitmingw64libexecgit-core'
fileName: 'git-archive'
fileExt: '.exe'
[D:Gitmingw64libexecgit.coregit-archive.exe]
fileDir: 'D:Gitmingw64libexecgit.core'
fileName: 'git-archive'
fileExt: '.exe'
[D:Gitmingw64libexecgit-coregit-archiveexe]
fileDir: 'D:Gitmingw64libexecgit-core'
fileName: 'git-archiveexe'
fileExt: ''
[D:Gitmingw64libexecgit.coregit-archiveexe]
fileDir: 'D:Gitmingw64libexecgit.core'
fileName: 'git-archiveexe'
fileExt: ''
I hope this helps you also :)
add a comment |
shlwapi.lib/dll
uses the HKCU
registry hive internally.
It's best not to link to shlwapi.lib
if you're creating a library or the product does not have a UI. If you're writing a lib then your code can be used in any project including those that don't have UIs.
If you're writing code that runs when a user is not logged in (e.g. service [or other] set to start at boot or startup) then there's no HKCU
. Lastly, shlwapi are settlement functions; and as a result high on the list to deprecate in later versions of Windows.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f8520560%2fget-a-file-name-from-a-path%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
18 Answers
18
active
oldest
votes
18 Answers
18
active
oldest
votes
active
oldest
votes
active
oldest
votes
_splitpath should do what you need. You could of course do it manually but _splitpath
handles all special cases as well.
EDIT:
As BillHoag mentioned it is recommended to use the more safe version of _splitpath
called _splitpath_s when available.
Or if you want something portable you could just do something like this
std::vector<std::string> splitpath(
const std::string& str
, const std::set<char> delimiters)
{
std::vector<std::string> result;
char const* pch = str.c_str();
char const* start = pch;
for(; *pch; ++pch)
{
if (delimiters.find(*pch) != delimiters.end())
{
if (start != pch)
{
std::string str(start, pch);
result.push_back(str);
}
else
{
result.push_back("");
}
start = pch + 1;
}
}
result.push_back(start);
return result;
}
...
std::set<char> delims{'\'};
std::vector<std::string> path = splitpath("C:\MyDirectory\MyFile.bat", delims);
cout << path.back() << endl;
2
There's no_splitpath
in any of the includes on my machine.
– James Kanze
Dec 15 '11 at 13:22
6
I have Visual Studio, and g++, and Sun CC. Why should I use something non-standard when there are perfectly good portable solutions.
– James Kanze
Dec 15 '11 at 13:49
1
@James, the page linked to says it is in<stdlib.h>
. As for portability, perhaps you can list some examples of “perfectly good portable solutions”?
– Synetech
Apr 4 '12 at 3:35
1
@Synetech The page linked to describes a Microsoft extension, not<stdlib.h>
. And the mot obvious portable solution isboost::filesystem
.
– James Kanze
Apr 4 '12 at 7:19
3
@James, you don’t have_splitpath
in thestdlib.h
of your copy of VS? Then you may want to do a repair install of VS.
– Synetech
Apr 4 '12 at 19:05
|
show 5 more comments
_splitpath should do what you need. You could of course do it manually but _splitpath
handles all special cases as well.
EDIT:
As BillHoag mentioned it is recommended to use the more safe version of _splitpath
called _splitpath_s when available.
Or if you want something portable you could just do something like this
std::vector<std::string> splitpath(
const std::string& str
, const std::set<char> delimiters)
{
std::vector<std::string> result;
char const* pch = str.c_str();
char const* start = pch;
for(; *pch; ++pch)
{
if (delimiters.find(*pch) != delimiters.end())
{
if (start != pch)
{
std::string str(start, pch);
result.push_back(str);
}
else
{
result.push_back("");
}
start = pch + 1;
}
}
result.push_back(start);
return result;
}
...
std::set<char> delims{'\'};
std::vector<std::string> path = splitpath("C:\MyDirectory\MyFile.bat", delims);
cout << path.back() << endl;
2
There's no_splitpath
in any of the includes on my machine.
– James Kanze
Dec 15 '11 at 13:22
6
I have Visual Studio, and g++, and Sun CC. Why should I use something non-standard when there are perfectly good portable solutions.
– James Kanze
Dec 15 '11 at 13:49
1
@James, the page linked to says it is in<stdlib.h>
. As for portability, perhaps you can list some examples of “perfectly good portable solutions”?
– Synetech
Apr 4 '12 at 3:35
1
@Synetech The page linked to describes a Microsoft extension, not<stdlib.h>
. And the mot obvious portable solution isboost::filesystem
.
– James Kanze
Apr 4 '12 at 7:19
3
@James, you don’t have_splitpath
in thestdlib.h
of your copy of VS? Then you may want to do a repair install of VS.
– Synetech
Apr 4 '12 at 19:05
|
show 5 more comments
_splitpath should do what you need. You could of course do it manually but _splitpath
handles all special cases as well.
EDIT:
As BillHoag mentioned it is recommended to use the more safe version of _splitpath
called _splitpath_s when available.
Or if you want something portable you could just do something like this
std::vector<std::string> splitpath(
const std::string& str
, const std::set<char> delimiters)
{
std::vector<std::string> result;
char const* pch = str.c_str();
char const* start = pch;
for(; *pch; ++pch)
{
if (delimiters.find(*pch) != delimiters.end())
{
if (start != pch)
{
std::string str(start, pch);
result.push_back(str);
}
else
{
result.push_back("");
}
start = pch + 1;
}
}
result.push_back(start);
return result;
}
...
std::set<char> delims{'\'};
std::vector<std::string> path = splitpath("C:\MyDirectory\MyFile.bat", delims);
cout << path.back() << endl;
_splitpath should do what you need. You could of course do it manually but _splitpath
handles all special cases as well.
EDIT:
As BillHoag mentioned it is recommended to use the more safe version of _splitpath
called _splitpath_s when available.
Or if you want something portable you could just do something like this
std::vector<std::string> splitpath(
const std::string& str
, const std::set<char> delimiters)
{
std::vector<std::string> result;
char const* pch = str.c_str();
char const* start = pch;
for(; *pch; ++pch)
{
if (delimiters.find(*pch) != delimiters.end())
{
if (start != pch)
{
std::string str(start, pch);
result.push_back(str);
}
else
{
result.push_back("");
}
start = pch + 1;
}
}
result.push_back(start);
return result;
}
...
std::set<char> delims{'\'};
std::vector<std::string> path = splitpath("C:\MyDirectory\MyFile.bat", delims);
cout << path.back() << endl;
edited Apr 30 '16 at 13:44
answered Dec 15 '11 at 13:14
AndersAnders
30.1k64772
30.1k64772
2
There's no_splitpath
in any of the includes on my machine.
– James Kanze
Dec 15 '11 at 13:22
6
I have Visual Studio, and g++, and Sun CC. Why should I use something non-standard when there are perfectly good portable solutions.
– James Kanze
Dec 15 '11 at 13:49
1
@James, the page linked to says it is in<stdlib.h>
. As for portability, perhaps you can list some examples of “perfectly good portable solutions”?
– Synetech
Apr 4 '12 at 3:35
1
@Synetech The page linked to describes a Microsoft extension, not<stdlib.h>
. And the mot obvious portable solution isboost::filesystem
.
– James Kanze
Apr 4 '12 at 7:19
3
@James, you don’t have_splitpath
in thestdlib.h
of your copy of VS? Then you may want to do a repair install of VS.
– Synetech
Apr 4 '12 at 19:05
|
show 5 more comments
2
There's no_splitpath
in any of the includes on my machine.
– James Kanze
Dec 15 '11 at 13:22
6
I have Visual Studio, and g++, and Sun CC. Why should I use something non-standard when there are perfectly good portable solutions.
– James Kanze
Dec 15 '11 at 13:49
1
@James, the page linked to says it is in<stdlib.h>
. As for portability, perhaps you can list some examples of “perfectly good portable solutions”?
– Synetech
Apr 4 '12 at 3:35
1
@Synetech The page linked to describes a Microsoft extension, not<stdlib.h>
. And the mot obvious portable solution isboost::filesystem
.
– James Kanze
Apr 4 '12 at 7:19
3
@James, you don’t have_splitpath
in thestdlib.h
of your copy of VS? Then you may want to do a repair install of VS.
– Synetech
Apr 4 '12 at 19:05
2
2
There's no
_splitpath
in any of the includes on my machine.– James Kanze
Dec 15 '11 at 13:22
There's no
_splitpath
in any of the includes on my machine.– James Kanze
Dec 15 '11 at 13:22
6
6
I have Visual Studio, and g++, and Sun CC. Why should I use something non-standard when there are perfectly good portable solutions.
– James Kanze
Dec 15 '11 at 13:49
I have Visual Studio, and g++, and Sun CC. Why should I use something non-standard when there are perfectly good portable solutions.
– James Kanze
Dec 15 '11 at 13:49
1
1
@James, the page linked to says it is in
<stdlib.h>
. As for portability, perhaps you can list some examples of “perfectly good portable solutions”?– Synetech
Apr 4 '12 at 3:35
@James, the page linked to says it is in
<stdlib.h>
. As for portability, perhaps you can list some examples of “perfectly good portable solutions”?– Synetech
Apr 4 '12 at 3:35
1
1
@Synetech The page linked to describes a Microsoft extension, not
<stdlib.h>
. And the mot obvious portable solution is boost::filesystem
.– James Kanze
Apr 4 '12 at 7:19
@Synetech The page linked to describes a Microsoft extension, not
<stdlib.h>
. And the mot obvious portable solution is boost::filesystem
.– James Kanze
Apr 4 '12 at 7:19
3
3
@James, you don’t have
_splitpath
in the stdlib.h
of your copy of VS? Then you may want to do a repair install of VS.– Synetech
Apr 4 '12 at 19:05
@James, you don’t have
_splitpath
in the stdlib.h
of your copy of VS? Then you may want to do a repair install of VS.– Synetech
Apr 4 '12 at 19:05
|
show 5 more comments
A possible solution:
string filename = "C:\MyDirectory\MyFile.bat";
// Remove directory if present.
// Do this before extension removal incase directory has a period character.
const size_t last_slash_idx = filename.find_last_of("\/");
if (std::string::npos != last_slash_idx)
{
filename.erase(0, last_slash_idx + 1);
}
// Remove extension if present.
const size_t period_idx = filename.rfind('.');
if (std::string::npos != period_idx)
{
filename.erase(period_idx);
}
the simplest is always the best!
– Jean-François Fabre
Apr 4 '18 at 15:12
add a comment |
A possible solution:
string filename = "C:\MyDirectory\MyFile.bat";
// Remove directory if present.
// Do this before extension removal incase directory has a period character.
const size_t last_slash_idx = filename.find_last_of("\/");
if (std::string::npos != last_slash_idx)
{
filename.erase(0, last_slash_idx + 1);
}
// Remove extension if present.
const size_t period_idx = filename.rfind('.');
if (std::string::npos != period_idx)
{
filename.erase(period_idx);
}
the simplest is always the best!
– Jean-François Fabre
Apr 4 '18 at 15:12
add a comment |
A possible solution:
string filename = "C:\MyDirectory\MyFile.bat";
// Remove directory if present.
// Do this before extension removal incase directory has a period character.
const size_t last_slash_idx = filename.find_last_of("\/");
if (std::string::npos != last_slash_idx)
{
filename.erase(0, last_slash_idx + 1);
}
// Remove extension if present.
const size_t period_idx = filename.rfind('.');
if (std::string::npos != period_idx)
{
filename.erase(period_idx);
}
A possible solution:
string filename = "C:\MyDirectory\MyFile.bat";
// Remove directory if present.
// Do this before extension removal incase directory has a period character.
const size_t last_slash_idx = filename.find_last_of("\/");
if (std::string::npos != last_slash_idx)
{
filename.erase(0, last_slash_idx + 1);
}
// Remove extension if present.
const size_t period_idx = filename.rfind('.');
if (std::string::npos != period_idx)
{
filename.erase(period_idx);
}
edited Dec 15 '11 at 13:46
answered Dec 15 '11 at 13:25
hmjdhmjd
102k13160217
102k13160217
the simplest is always the best!
– Jean-François Fabre
Apr 4 '18 at 15:12
add a comment |
the simplest is always the best!
– Jean-François Fabre
Apr 4 '18 at 15:12
the simplest is always the best!
– Jean-François Fabre
Apr 4 '18 at 15:12
the simplest is always the best!
– Jean-François Fabre
Apr 4 '18 at 15:12
add a comment |
The simplest solution is to use something like boost::filesystem
. If
for some reason this isn't an option...
Doing this correctly will require some system dependent code: under
Windows, either '\'
or '/'
can be a path separator; under Unix,
only '/'
works, and under other systems, who knows. The obvious
solution would be something like:
std::string
basename( std::string const& pathname )
{
return std::string(
std::find_if( pathname.rbegin(), pathname.rend(),
MatchPathSeparator() ).base(),
pathname.end() );
}
, with MatchPathSeparator
being defined in a system dependent header
as either:
struct MatchPathSeparator
{
bool operator()( char ch ) const
{
return ch == '/';
}
};
for Unix, or:
struct MatchPathSeparator
{
bool operator()( char ch ) const
{
return ch == '\' || ch == '/';
}
};
for Windows (or something still different for some other unknown
system).
EDIT: I missed the fact that he also wanted to suppress the extention.
For that, more of the same:
std::string
removeExtension( std::string const& filename )
{
std::string::const_reverse_iterator
pivot
= std::find( filename.rbegin(), filename.rend(), '.' );
return pivot == filename.rend()
? filename
: std::string( filename.begin(), pivot.base() - 1 );
}
The code is a little bit more complex, because in this case, the base of
the reverse iterator is on the wrong side of where we want to cut.
(Remember that the base of a reverse iterator is one behind the
character the iterator points to.) And even this is a little dubious: I
don't like the fact that it can return an empty string, for example.
(If the only '.'
is the first character of the filename, I'd argue
that you should return the full filename. This would require a little
bit of extra code to catch the special case.)
}
8
How about usingstring::find_last_of
instead of manipulating reverse iterators?
– Luc Touraille
Dec 15 '11 at 14:04
@LucTouraille Why learn two ways of doing things when one will do? You'd need the reverse iterators for any container exceptstring
, so you have to learn them anyway. And having learned them, there's no reason to bother learning all of the bloated interface tostd::string
.
– James Kanze
Dec 15 '11 at 15:35
Note: The <filesystem> header ships with Visual Studio 2015 and above, so you don't have to add a dependency on boost to use it.
– IInspectable
May 2 '17 at 10:39
add a comment |
The simplest solution is to use something like boost::filesystem
. If
for some reason this isn't an option...
Doing this correctly will require some system dependent code: under
Windows, either '\'
or '/'
can be a path separator; under Unix,
only '/'
works, and under other systems, who knows. The obvious
solution would be something like:
std::string
basename( std::string const& pathname )
{
return std::string(
std::find_if( pathname.rbegin(), pathname.rend(),
MatchPathSeparator() ).base(),
pathname.end() );
}
, with MatchPathSeparator
being defined in a system dependent header
as either:
struct MatchPathSeparator
{
bool operator()( char ch ) const
{
return ch == '/';
}
};
for Unix, or:
struct MatchPathSeparator
{
bool operator()( char ch ) const
{
return ch == '\' || ch == '/';
}
};
for Windows (or something still different for some other unknown
system).
EDIT: I missed the fact that he also wanted to suppress the extention.
For that, more of the same:
std::string
removeExtension( std::string const& filename )
{
std::string::const_reverse_iterator
pivot
= std::find( filename.rbegin(), filename.rend(), '.' );
return pivot == filename.rend()
? filename
: std::string( filename.begin(), pivot.base() - 1 );
}
The code is a little bit more complex, because in this case, the base of
the reverse iterator is on the wrong side of where we want to cut.
(Remember that the base of a reverse iterator is one behind the
character the iterator points to.) And even this is a little dubious: I
don't like the fact that it can return an empty string, for example.
(If the only '.'
is the first character of the filename, I'd argue
that you should return the full filename. This would require a little
bit of extra code to catch the special case.)
}
8
How about usingstring::find_last_of
instead of manipulating reverse iterators?
– Luc Touraille
Dec 15 '11 at 14:04
@LucTouraille Why learn two ways of doing things when one will do? You'd need the reverse iterators for any container exceptstring
, so you have to learn them anyway. And having learned them, there's no reason to bother learning all of the bloated interface tostd::string
.
– James Kanze
Dec 15 '11 at 15:35
Note: The <filesystem> header ships with Visual Studio 2015 and above, so you don't have to add a dependency on boost to use it.
– IInspectable
May 2 '17 at 10:39
add a comment |
The simplest solution is to use something like boost::filesystem
. If
for some reason this isn't an option...
Doing this correctly will require some system dependent code: under
Windows, either '\'
or '/'
can be a path separator; under Unix,
only '/'
works, and under other systems, who knows. The obvious
solution would be something like:
std::string
basename( std::string const& pathname )
{
return std::string(
std::find_if( pathname.rbegin(), pathname.rend(),
MatchPathSeparator() ).base(),
pathname.end() );
}
, with MatchPathSeparator
being defined in a system dependent header
as either:
struct MatchPathSeparator
{
bool operator()( char ch ) const
{
return ch == '/';
}
};
for Unix, or:
struct MatchPathSeparator
{
bool operator()( char ch ) const
{
return ch == '\' || ch == '/';
}
};
for Windows (or something still different for some other unknown
system).
EDIT: I missed the fact that he also wanted to suppress the extention.
For that, more of the same:
std::string
removeExtension( std::string const& filename )
{
std::string::const_reverse_iterator
pivot
= std::find( filename.rbegin(), filename.rend(), '.' );
return pivot == filename.rend()
? filename
: std::string( filename.begin(), pivot.base() - 1 );
}
The code is a little bit more complex, because in this case, the base of
the reverse iterator is on the wrong side of where we want to cut.
(Remember that the base of a reverse iterator is one behind the
character the iterator points to.) And even this is a little dubious: I
don't like the fact that it can return an empty string, for example.
(If the only '.'
is the first character of the filename, I'd argue
that you should return the full filename. This would require a little
bit of extra code to catch the special case.)
}
The simplest solution is to use something like boost::filesystem
. If
for some reason this isn't an option...
Doing this correctly will require some system dependent code: under
Windows, either '\'
or '/'
can be a path separator; under Unix,
only '/'
works, and under other systems, who knows. The obvious
solution would be something like:
std::string
basename( std::string const& pathname )
{
return std::string(
std::find_if( pathname.rbegin(), pathname.rend(),
MatchPathSeparator() ).base(),
pathname.end() );
}
, with MatchPathSeparator
being defined in a system dependent header
as either:
struct MatchPathSeparator
{
bool operator()( char ch ) const
{
return ch == '/';
}
};
for Unix, or:
struct MatchPathSeparator
{
bool operator()( char ch ) const
{
return ch == '\' || ch == '/';
}
};
for Windows (or something still different for some other unknown
system).
EDIT: I missed the fact that he also wanted to suppress the extention.
For that, more of the same:
std::string
removeExtension( std::string const& filename )
{
std::string::const_reverse_iterator
pivot
= std::find( filename.rbegin(), filename.rend(), '.' );
return pivot == filename.rend()
? filename
: std::string( filename.begin(), pivot.base() - 1 );
}
The code is a little bit more complex, because in this case, the base of
the reverse iterator is on the wrong side of where we want to cut.
(Remember that the base of a reverse iterator is one behind the
character the iterator points to.) And even this is a little dubious: I
don't like the fact that it can return an empty string, for example.
(If the only '.'
is the first character of the filename, I'd argue
that you should return the full filename. This would require a little
bit of extra code to catch the special case.)
}
edited Dec 15 '11 at 13:44
answered Dec 15 '11 at 13:30
James KanzeJames Kanze
129k9137278
129k9137278
8
How about usingstring::find_last_of
instead of manipulating reverse iterators?
– Luc Touraille
Dec 15 '11 at 14:04
@LucTouraille Why learn two ways of doing things when one will do? You'd need the reverse iterators for any container exceptstring
, so you have to learn them anyway. And having learned them, there's no reason to bother learning all of the bloated interface tostd::string
.
– James Kanze
Dec 15 '11 at 15:35
Note: The <filesystem> header ships with Visual Studio 2015 and above, so you don't have to add a dependency on boost to use it.
– IInspectable
May 2 '17 at 10:39
add a comment |
8
How about usingstring::find_last_of
instead of manipulating reverse iterators?
– Luc Touraille
Dec 15 '11 at 14:04
@LucTouraille Why learn two ways of doing things when one will do? You'd need the reverse iterators for any container exceptstring
, so you have to learn them anyway. And having learned them, there's no reason to bother learning all of the bloated interface tostd::string
.
– James Kanze
Dec 15 '11 at 15:35
Note: The <filesystem> header ships with Visual Studio 2015 and above, so you don't have to add a dependency on boost to use it.
– IInspectable
May 2 '17 at 10:39
8
8
How about using
string::find_last_of
instead of manipulating reverse iterators?– Luc Touraille
Dec 15 '11 at 14:04
How about using
string::find_last_of
instead of manipulating reverse iterators?– Luc Touraille
Dec 15 '11 at 14:04
@LucTouraille Why learn two ways of doing things when one will do? You'd need the reverse iterators for any container except
string
, so you have to learn them anyway. And having learned them, there's no reason to bother learning all of the bloated interface to std::string
.– James Kanze
Dec 15 '11 at 15:35
@LucTouraille Why learn two ways of doing things when one will do? You'd need the reverse iterators for any container except
string
, so you have to learn them anyway. And having learned them, there's no reason to bother learning all of the bloated interface to std::string
.– James Kanze
Dec 15 '11 at 15:35
Note: The <filesystem> header ships with Visual Studio 2015 and above, so you don't have to add a dependency on boost to use it.
– IInspectable
May 2 '17 at 10:39
Note: The <filesystem> header ships with Visual Studio 2015 and above, so you don't have to add a dependency on boost to use it.
– IInspectable
May 2 '17 at 10:39
add a comment |
The task is fairly simple as the base filename is just the part of the string starting at the last delimeter for folders:
std::string base_filename = path.substr(path.find_last_of("/\") + 1)
If the extension is to be removed as well the only thing to do is find the last .
and take a substr
to this point
std::string::size_type const p(base_filename.find_last_of('.'));
std::string file_without_extension = base_filename.substr(0, p);
Perhaps there should be a check to cope with files solely consisting of extensions (ie .bashrc
...)
If you split this up into seperate functions you're flexible to reuse the single tasks:
template<class T>
T base_name(T const & path, T const & delims = "/\")
{
return path.substr(path.find_last_of(delims) + 1);
}
template<class T>
T remove_extension(T const & filename)
{
typename T::size_type const p(filename.find_last_of('.'));
return p > 0 && p != T::npos ? filename.substr(0, p) : filename;
}
The code is templated to be able to use it with different std::basic_string
instances (i.e. std::string
& std::wstring
...)
The downside of the templation is the requirement to specify the template parameter if a const char *
is passed to the functions.
So you could either:
A) Use only std::string
instead of templating the code
std::string base_name(std::string const & path)
{
return path.substr(path.find_last_of("/\") + 1);
}
B) Provide wrapping function using std::string
(as intermediates which will likely be inlined / optimized away)
inline std::string string_base_name(std::string const & path)
{
return base_name(path);
}
C) Specify the template parameter when calling with const char *
.
std::string base = base_name<std::string>("some/path/file.ext");
Result
std::string filepath = "C:\MyDirectory\MyFile.bat";
std::cout << remove_extension(base_name(filepath)) << std::endl;
Prints
MyFile
In this use case everything is OK (and original question is answered), but your extension remover is not perfect - it will fail if we pass there something like "/home/user/my.dir/myfile"
– avtomaton
Aug 27 '15 at 8:03
@avtomaton The extension removing function should be used on a file name not a path. (Just applybase_name
first.)
– Pixelchemist
Aug 27 '15 at 9:14
I understand it (that's why I wrote that original question is answered and in this use-case everything is OK). Just wanted to point out to this issue for somebody who will try to use these snippets.
– avtomaton
Aug 27 '15 at 10:14
Very nice explanation. It enhances the structural understanding of the problem. Thanks
– hell_ical_vortex
May 18 '16 at 7:15
add a comment |
The task is fairly simple as the base filename is just the part of the string starting at the last delimeter for folders:
std::string base_filename = path.substr(path.find_last_of("/\") + 1)
If the extension is to be removed as well the only thing to do is find the last .
and take a substr
to this point
std::string::size_type const p(base_filename.find_last_of('.'));
std::string file_without_extension = base_filename.substr(0, p);
Perhaps there should be a check to cope with files solely consisting of extensions (ie .bashrc
...)
If you split this up into seperate functions you're flexible to reuse the single tasks:
template<class T>
T base_name(T const & path, T const & delims = "/\")
{
return path.substr(path.find_last_of(delims) + 1);
}
template<class T>
T remove_extension(T const & filename)
{
typename T::size_type const p(filename.find_last_of('.'));
return p > 0 && p != T::npos ? filename.substr(0, p) : filename;
}
The code is templated to be able to use it with different std::basic_string
instances (i.e. std::string
& std::wstring
...)
The downside of the templation is the requirement to specify the template parameter if a const char *
is passed to the functions.
So you could either:
A) Use only std::string
instead of templating the code
std::string base_name(std::string const & path)
{
return path.substr(path.find_last_of("/\") + 1);
}
B) Provide wrapping function using std::string
(as intermediates which will likely be inlined / optimized away)
inline std::string string_base_name(std::string const & path)
{
return base_name(path);
}
C) Specify the template parameter when calling with const char *
.
std::string base = base_name<std::string>("some/path/file.ext");
Result
std::string filepath = "C:\MyDirectory\MyFile.bat";
std::cout << remove_extension(base_name(filepath)) << std::endl;
Prints
MyFile
In this use case everything is OK (and original question is answered), but your extension remover is not perfect - it will fail if we pass there something like "/home/user/my.dir/myfile"
– avtomaton
Aug 27 '15 at 8:03
@avtomaton The extension removing function should be used on a file name not a path. (Just applybase_name
first.)
– Pixelchemist
Aug 27 '15 at 9:14
I understand it (that's why I wrote that original question is answered and in this use-case everything is OK). Just wanted to point out to this issue for somebody who will try to use these snippets.
– avtomaton
Aug 27 '15 at 10:14
Very nice explanation. It enhances the structural understanding of the problem. Thanks
– hell_ical_vortex
May 18 '16 at 7:15
add a comment |
The task is fairly simple as the base filename is just the part of the string starting at the last delimeter for folders:
std::string base_filename = path.substr(path.find_last_of("/\") + 1)
If the extension is to be removed as well the only thing to do is find the last .
and take a substr
to this point
std::string::size_type const p(base_filename.find_last_of('.'));
std::string file_without_extension = base_filename.substr(0, p);
Perhaps there should be a check to cope with files solely consisting of extensions (ie .bashrc
...)
If you split this up into seperate functions you're flexible to reuse the single tasks:
template<class T>
T base_name(T const & path, T const & delims = "/\")
{
return path.substr(path.find_last_of(delims) + 1);
}
template<class T>
T remove_extension(T const & filename)
{
typename T::size_type const p(filename.find_last_of('.'));
return p > 0 && p != T::npos ? filename.substr(0, p) : filename;
}
The code is templated to be able to use it with different std::basic_string
instances (i.e. std::string
& std::wstring
...)
The downside of the templation is the requirement to specify the template parameter if a const char *
is passed to the functions.
So you could either:
A) Use only std::string
instead of templating the code
std::string base_name(std::string const & path)
{
return path.substr(path.find_last_of("/\") + 1);
}
B) Provide wrapping function using std::string
(as intermediates which will likely be inlined / optimized away)
inline std::string string_base_name(std::string const & path)
{
return base_name(path);
}
C) Specify the template parameter when calling with const char *
.
std::string base = base_name<std::string>("some/path/file.ext");
Result
std::string filepath = "C:\MyDirectory\MyFile.bat";
std::cout << remove_extension(base_name(filepath)) << std::endl;
Prints
MyFile
The task is fairly simple as the base filename is just the part of the string starting at the last delimeter for folders:
std::string base_filename = path.substr(path.find_last_of("/\") + 1)
If the extension is to be removed as well the only thing to do is find the last .
and take a substr
to this point
std::string::size_type const p(base_filename.find_last_of('.'));
std::string file_without_extension = base_filename.substr(0, p);
Perhaps there should be a check to cope with files solely consisting of extensions (ie .bashrc
...)
If you split this up into seperate functions you're flexible to reuse the single tasks:
template<class T>
T base_name(T const & path, T const & delims = "/\")
{
return path.substr(path.find_last_of(delims) + 1);
}
template<class T>
T remove_extension(T const & filename)
{
typename T::size_type const p(filename.find_last_of('.'));
return p > 0 && p != T::npos ? filename.substr(0, p) : filename;
}
The code is templated to be able to use it with different std::basic_string
instances (i.e. std::string
& std::wstring
...)
The downside of the templation is the requirement to specify the template parameter if a const char *
is passed to the functions.
So you could either:
A) Use only std::string
instead of templating the code
std::string base_name(std::string const & path)
{
return path.substr(path.find_last_of("/\") + 1);
}
B) Provide wrapping function using std::string
(as intermediates which will likely be inlined / optimized away)
inline std::string string_base_name(std::string const & path)
{
return base_name(path);
}
C) Specify the template parameter when calling with const char *
.
std::string base = base_name<std::string>("some/path/file.ext");
Result
std::string filepath = "C:\MyDirectory\MyFile.bat";
std::cout << remove_extension(base_name(filepath)) << std::endl;
Prints
MyFile
answered Jun 24 '14 at 12:44
PixelchemistPixelchemist
16.2k43162
16.2k43162
In this use case everything is OK (and original question is answered), but your extension remover is not perfect - it will fail if we pass there something like "/home/user/my.dir/myfile"
– avtomaton
Aug 27 '15 at 8:03
@avtomaton The extension removing function should be used on a file name not a path. (Just applybase_name
first.)
– Pixelchemist
Aug 27 '15 at 9:14
I understand it (that's why I wrote that original question is answered and in this use-case everything is OK). Just wanted to point out to this issue for somebody who will try to use these snippets.
– avtomaton
Aug 27 '15 at 10:14
Very nice explanation. It enhances the structural understanding of the problem. Thanks
– hell_ical_vortex
May 18 '16 at 7:15
add a comment |
In this use case everything is OK (and original question is answered), but your extension remover is not perfect - it will fail if we pass there something like "/home/user/my.dir/myfile"
– avtomaton
Aug 27 '15 at 8:03
@avtomaton The extension removing function should be used on a file name not a path. (Just applybase_name
first.)
– Pixelchemist
Aug 27 '15 at 9:14
I understand it (that's why I wrote that original question is answered and in this use-case everything is OK). Just wanted to point out to this issue for somebody who will try to use these snippets.
– avtomaton
Aug 27 '15 at 10:14
Very nice explanation. It enhances the structural understanding of the problem. Thanks
– hell_ical_vortex
May 18 '16 at 7:15
In this use case everything is OK (and original question is answered), but your extension remover is not perfect - it will fail if we pass there something like "/home/user/my.dir/myfile"
– avtomaton
Aug 27 '15 at 8:03
In this use case everything is OK (and original question is answered), but your extension remover is not perfect - it will fail if we pass there something like "/home/user/my.dir/myfile"
– avtomaton
Aug 27 '15 at 8:03
@avtomaton The extension removing function should be used on a file name not a path. (Just apply
base_name
first.)– Pixelchemist
Aug 27 '15 at 9:14
@avtomaton The extension removing function should be used on a file name not a path. (Just apply
base_name
first.)– Pixelchemist
Aug 27 '15 at 9:14
I understand it (that's why I wrote that original question is answered and in this use-case everything is OK). Just wanted to point out to this issue for somebody who will try to use these snippets.
– avtomaton
Aug 27 '15 at 10:14
I understand it (that's why I wrote that original question is answered and in this use-case everything is OK). Just wanted to point out to this issue for somebody who will try to use these snippets.
– avtomaton
Aug 27 '15 at 10:14
Very nice explanation. It enhances the structural understanding of the problem. Thanks
– hell_ical_vortex
May 18 '16 at 7:15
Very nice explanation. It enhances the structural understanding of the problem. Thanks
– hell_ical_vortex
May 18 '16 at 7:15
add a comment |
You can also use the shell Path APIs PathFindFileName, PathRemoveExtension. Probably worse than _splitpath for this particular problem, but those APIs are very useful for all kinds of path parsing jobs and they take UNC paths, forward slashes and other weird stuff into account.
wstring filename = L"C:\MyDirectory\MyFile.bat";
wchar_t* filepart = PathFindFileName(filename.c_str());
PathRemoveExtension(filepart);
http://msdn.microsoft.com/en-us/library/windows/desktop/bb773589(v=vs.85).aspx
The drawback is that you have to link to shlwapi.lib, but I'm not really sure why that's a drawback.
My preferred solution for getting a filename from a path.
– mrt
May 12 '17 at 6:32
add a comment |
You can also use the shell Path APIs PathFindFileName, PathRemoveExtension. Probably worse than _splitpath for this particular problem, but those APIs are very useful for all kinds of path parsing jobs and they take UNC paths, forward slashes and other weird stuff into account.
wstring filename = L"C:\MyDirectory\MyFile.bat";
wchar_t* filepart = PathFindFileName(filename.c_str());
PathRemoveExtension(filepart);
http://msdn.microsoft.com/en-us/library/windows/desktop/bb773589(v=vs.85).aspx
The drawback is that you have to link to shlwapi.lib, but I'm not really sure why that's a drawback.
My preferred solution for getting a filename from a path.
– mrt
May 12 '17 at 6:32
add a comment |
You can also use the shell Path APIs PathFindFileName, PathRemoveExtension. Probably worse than _splitpath for this particular problem, but those APIs are very useful for all kinds of path parsing jobs and they take UNC paths, forward slashes and other weird stuff into account.
wstring filename = L"C:\MyDirectory\MyFile.bat";
wchar_t* filepart = PathFindFileName(filename.c_str());
PathRemoveExtension(filepart);
http://msdn.microsoft.com/en-us/library/windows/desktop/bb773589(v=vs.85).aspx
The drawback is that you have to link to shlwapi.lib, but I'm not really sure why that's a drawback.
You can also use the shell Path APIs PathFindFileName, PathRemoveExtension. Probably worse than _splitpath for this particular problem, but those APIs are very useful for all kinds of path parsing jobs and they take UNC paths, forward slashes and other weird stuff into account.
wstring filename = L"C:\MyDirectory\MyFile.bat";
wchar_t* filepart = PathFindFileName(filename.c_str());
PathRemoveExtension(filepart);
http://msdn.microsoft.com/en-us/library/windows/desktop/bb773589(v=vs.85).aspx
The drawback is that you have to link to shlwapi.lib, but I'm not really sure why that's a drawback.
answered Sep 13 '12 at 1:07
SkrymsliSkrymsli
2,70342332
2,70342332
My preferred solution for getting a filename from a path.
– mrt
May 12 '17 at 6:32
add a comment |
My preferred solution for getting a filename from a path.
– mrt
May 12 '17 at 6:32
My preferred solution for getting a filename from a path.
– mrt
May 12 '17 at 6:32
My preferred solution for getting a filename from a path.
– mrt
May 12 '17 at 6:32
add a comment |
If you can use boost,
#include <boost/filesystem.hpp>
path p("C:\MyDirectory\MyFile.bat");
string basename = p.filename().string();
//or
//string basename = path("C:\MyDirectory\MyFile.bat").filename().string();
This is all.
I recommend you to use boost library. Boost gives you a lot of conveniences when you work with C++. It supports almost all platforms.
If you use Ubuntu, you can install boost library by only one line sudo apt-get install libboost-all-dev
(ref. How to Install boost on Ubuntu?)
add a comment |
If you can use boost,
#include <boost/filesystem.hpp>
path p("C:\MyDirectory\MyFile.bat");
string basename = p.filename().string();
//or
//string basename = path("C:\MyDirectory\MyFile.bat").filename().string();
This is all.
I recommend you to use boost library. Boost gives you a lot of conveniences when you work with C++. It supports almost all platforms.
If you use Ubuntu, you can install boost library by only one line sudo apt-get install libboost-all-dev
(ref. How to Install boost on Ubuntu?)
add a comment |
If you can use boost,
#include <boost/filesystem.hpp>
path p("C:\MyDirectory\MyFile.bat");
string basename = p.filename().string();
//or
//string basename = path("C:\MyDirectory\MyFile.bat").filename().string();
This is all.
I recommend you to use boost library. Boost gives you a lot of conveniences when you work with C++. It supports almost all platforms.
If you use Ubuntu, you can install boost library by only one line sudo apt-get install libboost-all-dev
(ref. How to Install boost on Ubuntu?)
If you can use boost,
#include <boost/filesystem.hpp>
path p("C:\MyDirectory\MyFile.bat");
string basename = p.filename().string();
//or
//string basename = path("C:\MyDirectory\MyFile.bat").filename().string();
This is all.
I recommend you to use boost library. Boost gives you a lot of conveniences when you work with C++. It supports almost all platforms.
If you use Ubuntu, you can install boost library by only one line sudo apt-get install libboost-all-dev
(ref. How to Install boost on Ubuntu?)
edited May 23 '17 at 12:26
Community♦
11
11
answered Jul 22 '15 at 7:22
plhnplhn
2,46242435
2,46242435
add a comment |
add a comment |
Function:
#include <string>
std::string
basename(const std::string &filename)
{
if (filename.empty()) {
return {};
}
auto len = filename.length();
auto index = filename.find_last_of("/\");
if (index == std::string::npos) {
return filename;
}
if (index + 1 >= len) {
len--;
index = filename.substr(0, len).find_last_of("/\");
if (len == 0) {
return filename;
}
if (index == 0) {
return filename.substr(1, len - 1);
}
if (index == std::string::npos) {
return filename.substr(0, len);
}
return filename.substr(index + 1, len - index - 1);
}
return filename.substr(index + 1, len - index);
}
Tests:
#define CATCH_CONFIG_MAIN
#include <catch/catch.hpp>
TEST_CASE("basename")
{
CHECK(basename("") == "");
CHECK(basename("no_path") == "no_path");
CHECK(basename("with.ext") == "with.ext");
CHECK(basename("/no_filename/") == "no_filename");
CHECK(basename("no_filename/") == "no_filename");
CHECK(basename("/no/filename/") == "filename");
CHECK(basename("/absolute/file.ext") == "file.ext");
CHECK(basename("../relative/file.ext") == "file.ext");
CHECK(basename("/") == "/");
CHECK(basename("c:\windows\path.ext") == "path.ext");
CHECK(basename("c:\windows\no_filename\") == "no_filename");
}
add a comment |
Function:
#include <string>
std::string
basename(const std::string &filename)
{
if (filename.empty()) {
return {};
}
auto len = filename.length();
auto index = filename.find_last_of("/\");
if (index == std::string::npos) {
return filename;
}
if (index + 1 >= len) {
len--;
index = filename.substr(0, len).find_last_of("/\");
if (len == 0) {
return filename;
}
if (index == 0) {
return filename.substr(1, len - 1);
}
if (index == std::string::npos) {
return filename.substr(0, len);
}
return filename.substr(index + 1, len - index - 1);
}
return filename.substr(index + 1, len - index);
}
Tests:
#define CATCH_CONFIG_MAIN
#include <catch/catch.hpp>
TEST_CASE("basename")
{
CHECK(basename("") == "");
CHECK(basename("no_path") == "no_path");
CHECK(basename("with.ext") == "with.ext");
CHECK(basename("/no_filename/") == "no_filename");
CHECK(basename("no_filename/") == "no_filename");
CHECK(basename("/no/filename/") == "filename");
CHECK(basename("/absolute/file.ext") == "file.ext");
CHECK(basename("../relative/file.ext") == "file.ext");
CHECK(basename("/") == "/");
CHECK(basename("c:\windows\path.ext") == "path.ext");
CHECK(basename("c:\windows\no_filename\") == "no_filename");
}
add a comment |
Function:
#include <string>
std::string
basename(const std::string &filename)
{
if (filename.empty()) {
return {};
}
auto len = filename.length();
auto index = filename.find_last_of("/\");
if (index == std::string::npos) {
return filename;
}
if (index + 1 >= len) {
len--;
index = filename.substr(0, len).find_last_of("/\");
if (len == 0) {
return filename;
}
if (index == 0) {
return filename.substr(1, len - 1);
}
if (index == std::string::npos) {
return filename.substr(0, len);
}
return filename.substr(index + 1, len - index - 1);
}
return filename.substr(index + 1, len - index);
}
Tests:
#define CATCH_CONFIG_MAIN
#include <catch/catch.hpp>
TEST_CASE("basename")
{
CHECK(basename("") == "");
CHECK(basename("no_path") == "no_path");
CHECK(basename("with.ext") == "with.ext");
CHECK(basename("/no_filename/") == "no_filename");
CHECK(basename("no_filename/") == "no_filename");
CHECK(basename("/no/filename/") == "filename");
CHECK(basename("/absolute/file.ext") == "file.ext");
CHECK(basename("../relative/file.ext") == "file.ext");
CHECK(basename("/") == "/");
CHECK(basename("c:\windows\path.ext") == "path.ext");
CHECK(basename("c:\windows\no_filename\") == "no_filename");
}
Function:
#include <string>
std::string
basename(const std::string &filename)
{
if (filename.empty()) {
return {};
}
auto len = filename.length();
auto index = filename.find_last_of("/\");
if (index == std::string::npos) {
return filename;
}
if (index + 1 >= len) {
len--;
index = filename.substr(0, len).find_last_of("/\");
if (len == 0) {
return filename;
}
if (index == 0) {
return filename.substr(1, len - 1);
}
if (index == std::string::npos) {
return filename.substr(0, len);
}
return filename.substr(index + 1, len - index - 1);
}
return filename.substr(index + 1, len - index);
}
Tests:
#define CATCH_CONFIG_MAIN
#include <catch/catch.hpp>
TEST_CASE("basename")
{
CHECK(basename("") == "");
CHECK(basename("no_path") == "no_path");
CHECK(basename("with.ext") == "with.ext");
CHECK(basename("/no_filename/") == "no_filename");
CHECK(basename("no_filename/") == "no_filename");
CHECK(basename("/no/filename/") == "filename");
CHECK(basename("/absolute/file.ext") == "file.ext");
CHECK(basename("../relative/file.ext") == "file.ext");
CHECK(basename("/") == "/");
CHECK(basename("c:\windows\path.ext") == "path.ext");
CHECK(basename("c:\windows\no_filename\") == "no_filename");
}
edited Apr 7 '17 at 17:41
answered Apr 7 '17 at 17:25
Rian QuinnRian Quinn
35537
35537
add a comment |
add a comment |
From C++ Docs - string::find_last_of
#include <iostream> // std::cout
#include <string> // std::string
void SplitFilename (const std::string& str) {
std::cout << "Splitting: " << str << 'n';
unsigned found = str.find_last_of("/\");
std::cout << " path: " << str.substr(0,found) << 'n';
std::cout << " file: " << str.substr(found+1) << 'n';
}
int main () {
std::string str1 ("/usr/bin/man");
std::string str2 ("c:\windows\winhelp.exe");
SplitFilename (str1);
SplitFilename (str2);
return 0;
}
Outputs:
Splitting: /usr/bin/man
path: /usr/bin
file: man
Splitting: c:windowswinhelp.exe
path: c:windows
file: winhelp.exe
Don't forget (and to handle) thatfind_last_of
returnsstring::npos
if nothing was found.
– congusbongus
Mar 14 '16 at 23:53
@congusbongus True, but there is no sense of splitting the file path when it is just a file name (without path) :)
– jave.web
Mar 15 '16 at 11:05
@jave.web It does make sense and MUST handle returns 'string::npos'. Implementing a function for this should be able to handle different inputs including "just filename". Otherwise, it will be useless if its buggy in actual implementation.
– winux
Sep 22 '16 at 8:09
@winux This considers already valid PATHS... If you don't trust the input, you should, of course, validate the path first.
– jave.web
Sep 23 '16 at 13:07
@winux Anyway the check forstring::npos
does not need to be done because of the way how this andstring::substr
are implemented. a)string::npos
is passed as "length" =>substr
has documented behaviour of reading all until end. b)substr
is given "string::npos + 1
" and no length:string::npos
is documented to have a value of-1
, so that evaluates to0
=> start of the string and lengths' default value forsubstr
is thenpos
=> works on "just filename" too cplusplus.com/reference/string/string/substr cplusplus.com/reference/string/string/npos
– jave.web
Sep 23 '16 at 13:07
add a comment |
From C++ Docs - string::find_last_of
#include <iostream> // std::cout
#include <string> // std::string
void SplitFilename (const std::string& str) {
std::cout << "Splitting: " << str << 'n';
unsigned found = str.find_last_of("/\");
std::cout << " path: " << str.substr(0,found) << 'n';
std::cout << " file: " << str.substr(found+1) << 'n';
}
int main () {
std::string str1 ("/usr/bin/man");
std::string str2 ("c:\windows\winhelp.exe");
SplitFilename (str1);
SplitFilename (str2);
return 0;
}
Outputs:
Splitting: /usr/bin/man
path: /usr/bin
file: man
Splitting: c:windowswinhelp.exe
path: c:windows
file: winhelp.exe
Don't forget (and to handle) thatfind_last_of
returnsstring::npos
if nothing was found.
– congusbongus
Mar 14 '16 at 23:53
@congusbongus True, but there is no sense of splitting the file path when it is just a file name (without path) :)
– jave.web
Mar 15 '16 at 11:05
@jave.web It does make sense and MUST handle returns 'string::npos'. Implementing a function for this should be able to handle different inputs including "just filename". Otherwise, it will be useless if its buggy in actual implementation.
– winux
Sep 22 '16 at 8:09
@winux This considers already valid PATHS... If you don't trust the input, you should, of course, validate the path first.
– jave.web
Sep 23 '16 at 13:07
@winux Anyway the check forstring::npos
does not need to be done because of the way how this andstring::substr
are implemented. a)string::npos
is passed as "length" =>substr
has documented behaviour of reading all until end. b)substr
is given "string::npos + 1
" and no length:string::npos
is documented to have a value of-1
, so that evaluates to0
=> start of the string and lengths' default value forsubstr
is thenpos
=> works on "just filename" too cplusplus.com/reference/string/string/substr cplusplus.com/reference/string/string/npos
– jave.web
Sep 23 '16 at 13:07
add a comment |
From C++ Docs - string::find_last_of
#include <iostream> // std::cout
#include <string> // std::string
void SplitFilename (const std::string& str) {
std::cout << "Splitting: " << str << 'n';
unsigned found = str.find_last_of("/\");
std::cout << " path: " << str.substr(0,found) << 'n';
std::cout << " file: " << str.substr(found+1) << 'n';
}
int main () {
std::string str1 ("/usr/bin/man");
std::string str2 ("c:\windows\winhelp.exe");
SplitFilename (str1);
SplitFilename (str2);
return 0;
}
Outputs:
Splitting: /usr/bin/man
path: /usr/bin
file: man
Splitting: c:windowswinhelp.exe
path: c:windows
file: winhelp.exe
From C++ Docs - string::find_last_of
#include <iostream> // std::cout
#include <string> // std::string
void SplitFilename (const std::string& str) {
std::cout << "Splitting: " << str << 'n';
unsigned found = str.find_last_of("/\");
std::cout << " path: " << str.substr(0,found) << 'n';
std::cout << " file: " << str.substr(found+1) << 'n';
}
int main () {
std::string str1 ("/usr/bin/man");
std::string str2 ("c:\windows\winhelp.exe");
SplitFilename (str1);
SplitFilename (str2);
return 0;
}
Outputs:
Splitting: /usr/bin/man
path: /usr/bin
file: man
Splitting: c:windowswinhelp.exe
path: c:windows
file: winhelp.exe
answered Apr 2 '15 at 3:42
jave.webjave.web
6,38895376
6,38895376
Don't forget (and to handle) thatfind_last_of
returnsstring::npos
if nothing was found.
– congusbongus
Mar 14 '16 at 23:53
@congusbongus True, but there is no sense of splitting the file path when it is just a file name (without path) :)
– jave.web
Mar 15 '16 at 11:05
@jave.web It does make sense and MUST handle returns 'string::npos'. Implementing a function for this should be able to handle different inputs including "just filename". Otherwise, it will be useless if its buggy in actual implementation.
– winux
Sep 22 '16 at 8:09
@winux This considers already valid PATHS... If you don't trust the input, you should, of course, validate the path first.
– jave.web
Sep 23 '16 at 13:07
@winux Anyway the check forstring::npos
does not need to be done because of the way how this andstring::substr
are implemented. a)string::npos
is passed as "length" =>substr
has documented behaviour of reading all until end. b)substr
is given "string::npos + 1
" and no length:string::npos
is documented to have a value of-1
, so that evaluates to0
=> start of the string and lengths' default value forsubstr
is thenpos
=> works on "just filename" too cplusplus.com/reference/string/string/substr cplusplus.com/reference/string/string/npos
– jave.web
Sep 23 '16 at 13:07
add a comment |
Don't forget (and to handle) thatfind_last_of
returnsstring::npos
if nothing was found.
– congusbongus
Mar 14 '16 at 23:53
@congusbongus True, but there is no sense of splitting the file path when it is just a file name (without path) :)
– jave.web
Mar 15 '16 at 11:05
@jave.web It does make sense and MUST handle returns 'string::npos'. Implementing a function for this should be able to handle different inputs including "just filename". Otherwise, it will be useless if its buggy in actual implementation.
– winux
Sep 22 '16 at 8:09
@winux This considers already valid PATHS... If you don't trust the input, you should, of course, validate the path first.
– jave.web
Sep 23 '16 at 13:07
@winux Anyway the check forstring::npos
does not need to be done because of the way how this andstring::substr
are implemented. a)string::npos
is passed as "length" =>substr
has documented behaviour of reading all until end. b)substr
is given "string::npos + 1
" and no length:string::npos
is documented to have a value of-1
, so that evaluates to0
=> start of the string and lengths' default value forsubstr
is thenpos
=> works on "just filename" too cplusplus.com/reference/string/string/substr cplusplus.com/reference/string/string/npos
– jave.web
Sep 23 '16 at 13:07
Don't forget (and to handle) that
find_last_of
returns string::npos
if nothing was found.– congusbongus
Mar 14 '16 at 23:53
Don't forget (and to handle) that
find_last_of
returns string::npos
if nothing was found.– congusbongus
Mar 14 '16 at 23:53
@congusbongus True, but there is no sense of splitting the file path when it is just a file name (without path) :)
– jave.web
Mar 15 '16 at 11:05
@congusbongus True, but there is no sense of splitting the file path when it is just a file name (without path) :)
– jave.web
Mar 15 '16 at 11:05
@jave.web It does make sense and MUST handle returns 'string::npos'. Implementing a function for this should be able to handle different inputs including "just filename". Otherwise, it will be useless if its buggy in actual implementation.
– winux
Sep 22 '16 at 8:09
@jave.web It does make sense and MUST handle returns 'string::npos'. Implementing a function for this should be able to handle different inputs including "just filename". Otherwise, it will be useless if its buggy in actual implementation.
– winux
Sep 22 '16 at 8:09
@winux This considers already valid PATHS... If you don't trust the input, you should, of course, validate the path first.
– jave.web
Sep 23 '16 at 13:07
@winux This considers already valid PATHS... If you don't trust the input, you should, of course, validate the path first.
– jave.web
Sep 23 '16 at 13:07
@winux Anyway the check for
string::npos
does not need to be done because of the way how this and string::substr
are implemented. a) string::npos
is passed as "length" => substr
has documented behaviour of reading all until end. b) substr
is given "string::npos + 1
" and no length: string::npos
is documented to have a value of -1
, so that evaluates to 0
=> start of the string and lengths' default value for substr
is the npos
=> works on "just filename" too cplusplus.com/reference/string/string/substr cplusplus.com/reference/string/string/npos– jave.web
Sep 23 '16 at 13:07
@winux Anyway the check for
string::npos
does not need to be done because of the way how this and string::substr
are implemented. a) string::npos
is passed as "length" => substr
has documented behaviour of reading all until end. b) substr
is given "string::npos + 1
" and no length: string::npos
is documented to have a value of -1
, so that evaluates to 0
=> start of the string and lengths' default value for substr
is the npos
=> works on "just filename" too cplusplus.com/reference/string/string/substr cplusplus.com/reference/string/string/npos– jave.web
Sep 23 '16 at 13:07
add a comment |
The Simplest way in cpp17 is:
use the #include experimental/filesystem and filename() for filename with extension and stem() without extension.
#include <iostream>
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
int main()
{
string filename = "C:\MyDirectory\MyFile.bat";
std::cout << fs::path(filename).filename() << 'n'
<< fs::path(filename).stem() << 'n'
<< fs::path("/foo/bar.txt").filename() << 'n'
<< fs::path("/foo/bar.txt").stem() << 'n'
<< fs::path("/foo/.bar").filename() << 'n'
<< fs::path("/foo/bar/").filename() << 'n'
<< fs::path("/foo/.").filename() << 'n'
<< fs::path("/foo/..").filename() << 'n'
<< fs::path(".").filename() << 'n'
<< fs::path("..").filename() << 'n'
<< fs::path("/").filename() << 'n';
}
output:
MyFile.bat
MyFile
"bar.txt"
".bar"
"."
"."
".."
"."
".."
"/"
Ref: cppreference
add a comment |
The Simplest way in cpp17 is:
use the #include experimental/filesystem and filename() for filename with extension and stem() without extension.
#include <iostream>
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
int main()
{
string filename = "C:\MyDirectory\MyFile.bat";
std::cout << fs::path(filename).filename() << 'n'
<< fs::path(filename).stem() << 'n'
<< fs::path("/foo/bar.txt").filename() << 'n'
<< fs::path("/foo/bar.txt").stem() << 'n'
<< fs::path("/foo/.bar").filename() << 'n'
<< fs::path("/foo/bar/").filename() << 'n'
<< fs::path("/foo/.").filename() << 'n'
<< fs::path("/foo/..").filename() << 'n'
<< fs::path(".").filename() << 'n'
<< fs::path("..").filename() << 'n'
<< fs::path("/").filename() << 'n';
}
output:
MyFile.bat
MyFile
"bar.txt"
".bar"
"."
"."
".."
"."
".."
"/"
Ref: cppreference
add a comment |
The Simplest way in cpp17 is:
use the #include experimental/filesystem and filename() for filename with extension and stem() without extension.
#include <iostream>
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
int main()
{
string filename = "C:\MyDirectory\MyFile.bat";
std::cout << fs::path(filename).filename() << 'n'
<< fs::path(filename).stem() << 'n'
<< fs::path("/foo/bar.txt").filename() << 'n'
<< fs::path("/foo/bar.txt").stem() << 'n'
<< fs::path("/foo/.bar").filename() << 'n'
<< fs::path("/foo/bar/").filename() << 'n'
<< fs::path("/foo/.").filename() << 'n'
<< fs::path("/foo/..").filename() << 'n'
<< fs::path(".").filename() << 'n'
<< fs::path("..").filename() << 'n'
<< fs::path("/").filename() << 'n';
}
output:
MyFile.bat
MyFile
"bar.txt"
".bar"
"."
"."
".."
"."
".."
"/"
Ref: cppreference
The Simplest way in cpp17 is:
use the #include experimental/filesystem and filename() for filename with extension and stem() without extension.
#include <iostream>
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
int main()
{
string filename = "C:\MyDirectory\MyFile.bat";
std::cout << fs::path(filename).filename() << 'n'
<< fs::path(filename).stem() << 'n'
<< fs::path("/foo/bar.txt").filename() << 'n'
<< fs::path("/foo/bar.txt").stem() << 'n'
<< fs::path("/foo/.bar").filename() << 'n'
<< fs::path("/foo/bar/").filename() << 'n'
<< fs::path("/foo/.").filename() << 'n'
<< fs::path("/foo/..").filename() << 'n'
<< fs::path(".").filename() << 'n'
<< fs::path("..").filename() << 'n'
<< fs::path("/").filename() << 'n';
}
output:
MyFile.bat
MyFile
"bar.txt"
".bar"
"."
"."
".."
"."
".."
"/"
Ref: cppreference
edited Jan 30 '18 at 10:11
answered Jan 30 '18 at 9:37
eliasetmeliasetm
33227
33227
add a comment |
add a comment |
C++11 variant (inspired by James Kanze's version) with uniform initialization and anonymous inline lambda.
std::string basename(const std::string& pathname)
{
return {std::find_if(pathname.rbegin(), pathname.rend(),
(char c) { return c == '/'; }).base(),
pathname.end()};
}
It does not remove the file extension though.
Short and sweet, although it only works with non-Windows paths.
– Volomike
Mar 5 '16 at 18:33
you can always change lambda return toreturn c == '/' || c == '\';
to make it works on windows
– ziomq1991
Apr 19 '16 at 9:57
To handle paths such as "", "///", and "dir1/dir2/", add the following code before the return statement above (cf. POSIX basename()):if (pathname.size() == 0) return "."; auto iter = pathname.rbegin(); auto rend = pathname.rend(); while (iter != rend && *iter == '/') ++iter; if (iter == rend) /* pathname has only path separators */ return "/"; pathname = std::string(pathname.begin(), iter.base());
– Gidfiddle
Oct 27 '17 at 6:14
add a comment |
C++11 variant (inspired by James Kanze's version) with uniform initialization and anonymous inline lambda.
std::string basename(const std::string& pathname)
{
return {std::find_if(pathname.rbegin(), pathname.rend(),
(char c) { return c == '/'; }).base(),
pathname.end()};
}
It does not remove the file extension though.
Short and sweet, although it only works with non-Windows paths.
– Volomike
Mar 5 '16 at 18:33
you can always change lambda return toreturn c == '/' || c == '\';
to make it works on windows
– ziomq1991
Apr 19 '16 at 9:57
To handle paths such as "", "///", and "dir1/dir2/", add the following code before the return statement above (cf. POSIX basename()):if (pathname.size() == 0) return "."; auto iter = pathname.rbegin(); auto rend = pathname.rend(); while (iter != rend && *iter == '/') ++iter; if (iter == rend) /* pathname has only path separators */ return "/"; pathname = std::string(pathname.begin(), iter.base());
– Gidfiddle
Oct 27 '17 at 6:14
add a comment |
C++11 variant (inspired by James Kanze's version) with uniform initialization and anonymous inline lambda.
std::string basename(const std::string& pathname)
{
return {std::find_if(pathname.rbegin(), pathname.rend(),
(char c) { return c == '/'; }).base(),
pathname.end()};
}
It does not remove the file extension though.
C++11 variant (inspired by James Kanze's version) with uniform initialization and anonymous inline lambda.
std::string basename(const std::string& pathname)
{
return {std::find_if(pathname.rbegin(), pathname.rend(),
(char c) { return c == '/'; }).base(),
pathname.end()};
}
It does not remove the file extension though.
edited Mar 5 '16 at 18:34
Volomike
13.7k1881153
13.7k1881153
answered Oct 17 '13 at 23:41
alvekoalveko
95621115
95621115
Short and sweet, although it only works with non-Windows paths.
– Volomike
Mar 5 '16 at 18:33
you can always change lambda return toreturn c == '/' || c == '\';
to make it works on windows
– ziomq1991
Apr 19 '16 at 9:57
To handle paths such as "", "///", and "dir1/dir2/", add the following code before the return statement above (cf. POSIX basename()):if (pathname.size() == 0) return "."; auto iter = pathname.rbegin(); auto rend = pathname.rend(); while (iter != rend && *iter == '/') ++iter; if (iter == rend) /* pathname has only path separators */ return "/"; pathname = std::string(pathname.begin(), iter.base());
– Gidfiddle
Oct 27 '17 at 6:14
add a comment |
Short and sweet, although it only works with non-Windows paths.
– Volomike
Mar 5 '16 at 18:33
you can always change lambda return toreturn c == '/' || c == '\';
to make it works on windows
– ziomq1991
Apr 19 '16 at 9:57
To handle paths such as "", "///", and "dir1/dir2/", add the following code before the return statement above (cf. POSIX basename()):if (pathname.size() == 0) return "."; auto iter = pathname.rbegin(); auto rend = pathname.rend(); while (iter != rend && *iter == '/') ++iter; if (iter == rend) /* pathname has only path separators */ return "/"; pathname = std::string(pathname.begin(), iter.base());
– Gidfiddle
Oct 27 '17 at 6:14
Short and sweet, although it only works with non-Windows paths.
– Volomike
Mar 5 '16 at 18:33
Short and sweet, although it only works with non-Windows paths.
– Volomike
Mar 5 '16 at 18:33
you can always change lambda return to
return c == '/' || c == '\';
to make it works on windows– ziomq1991
Apr 19 '16 at 9:57
you can always change lambda return to
return c == '/' || c == '\';
to make it works on windows– ziomq1991
Apr 19 '16 at 9:57
To handle paths such as "", "///", and "dir1/dir2/", add the following code before the return statement above (cf. POSIX basename()):
if (pathname.size() == 0) return "."; auto iter = pathname.rbegin(); auto rend = pathname.rend(); while (iter != rend && *iter == '/') ++iter; if (iter == rend) /* pathname has only path separators */ return "/"; pathname = std::string(pathname.begin(), iter.base());
– Gidfiddle
Oct 27 '17 at 6:14
To handle paths such as "", "///", and "dir1/dir2/", add the following code before the return statement above (cf. POSIX basename()):
if (pathname.size() == 0) return "."; auto iter = pathname.rbegin(); auto rend = pathname.rend(); while (iter != rend && *iter == '/') ++iter; if (iter == rend) /* pathname has only path separators */ return "/"; pathname = std::string(pathname.begin(), iter.base());
– Gidfiddle
Oct 27 '17 at 6:14
add a comment |
this is the only thing that actually finally worked for me:
#include "Shlwapi.h"
CString some_string = "c:\path\hello.txt";
LPCSTR file_path = some_string.GetString();
LPCSTR filepart_c = PathFindFileName(file_path);
LPSTR filepart = LPSTR(filepart_c);
PathRemoveExtension(filepart);
pretty much what Skrymsli suggested but doesn't work with wchar_t*,
VS Enterprise 2015
_splitpath worked as well, but I don't like having to guess at how many char[?] characters I'm going to need; some people probably need this control, i guess.
CString c_model_name = "c:\path\hello.txt";
char drive[200];
char dir[200];
char name[200];
char ext[200];
_splitpath(c_model_name, drive, dir, name, ext);
I don't believe any includes were needed for _splitpath. No external libraries (like boost) were needed for either of these solutions.
add a comment |
this is the only thing that actually finally worked for me:
#include "Shlwapi.h"
CString some_string = "c:\path\hello.txt";
LPCSTR file_path = some_string.GetString();
LPCSTR filepart_c = PathFindFileName(file_path);
LPSTR filepart = LPSTR(filepart_c);
PathRemoveExtension(filepart);
pretty much what Skrymsli suggested but doesn't work with wchar_t*,
VS Enterprise 2015
_splitpath worked as well, but I don't like having to guess at how many char[?] characters I'm going to need; some people probably need this control, i guess.
CString c_model_name = "c:\path\hello.txt";
char drive[200];
char dir[200];
char name[200];
char ext[200];
_splitpath(c_model_name, drive, dir, name, ext);
I don't believe any includes were needed for _splitpath. No external libraries (like boost) were needed for either of these solutions.
add a comment |
this is the only thing that actually finally worked for me:
#include "Shlwapi.h"
CString some_string = "c:\path\hello.txt";
LPCSTR file_path = some_string.GetString();
LPCSTR filepart_c = PathFindFileName(file_path);
LPSTR filepart = LPSTR(filepart_c);
PathRemoveExtension(filepart);
pretty much what Skrymsli suggested but doesn't work with wchar_t*,
VS Enterprise 2015
_splitpath worked as well, but I don't like having to guess at how many char[?] characters I'm going to need; some people probably need this control, i guess.
CString c_model_name = "c:\path\hello.txt";
char drive[200];
char dir[200];
char name[200];
char ext[200];
_splitpath(c_model_name, drive, dir, name, ext);
I don't believe any includes were needed for _splitpath. No external libraries (like boost) were needed for either of these solutions.
this is the only thing that actually finally worked for me:
#include "Shlwapi.h"
CString some_string = "c:\path\hello.txt";
LPCSTR file_path = some_string.GetString();
LPCSTR filepart_c = PathFindFileName(file_path);
LPSTR filepart = LPSTR(filepart_c);
PathRemoveExtension(filepart);
pretty much what Skrymsli suggested but doesn't work with wchar_t*,
VS Enterprise 2015
_splitpath worked as well, but I don't like having to guess at how many char[?] characters I'm going to need; some people probably need this control, i guess.
CString c_model_name = "c:\path\hello.txt";
char drive[200];
char dir[200];
char name[200];
char ext[200];
_splitpath(c_model_name, drive, dir, name, ext);
I don't believe any includes were needed for _splitpath. No external libraries (like boost) were needed for either of these solutions.
answered Mar 24 '16 at 16:44
FractalFractal
5012823
5012823
add a comment |
add a comment |
I would do it by...
Search backwards from the end of the string until you find the first backslash/forward slash.
Then search backwards again from the end of the string until you find the first dot (.)
You then have the start and end of the file name.
Simples...
Which doesn't work for any system I know. (The one system which accepts'\'
as a path separator also uses'/'
, so you need to match either.) And I'm not sure what you'd be looking forward for.
– James Kanze
Dec 15 '11 at 13:32
Okay so modify it to match either, no biggy. And looking forward for the first dot (.)
– TomP89
Dec 15 '11 at 13:48
You still have to find the last dot, not the first. (Reverse iterators are your friend!)
– James Kanze
Dec 15 '11 at 13:56
Ah yes, good point. So for a file.ext.ext then you would want to extract file.ext wouldn't you. :)
– TomP89
Dec 15 '11 at 13:57
Presumably. That's the usual convention, in any case:my.source.cpp
gets compiled tomy.source.obj
, for example (with the extension.cpp
replaced with.obj
).
– James Kanze
Dec 15 '11 at 14:02
add a comment |
I would do it by...
Search backwards from the end of the string until you find the first backslash/forward slash.
Then search backwards again from the end of the string until you find the first dot (.)
You then have the start and end of the file name.
Simples...
Which doesn't work for any system I know. (The one system which accepts'\'
as a path separator also uses'/'
, so you need to match either.) And I'm not sure what you'd be looking forward for.
– James Kanze
Dec 15 '11 at 13:32
Okay so modify it to match either, no biggy. And looking forward for the first dot (.)
– TomP89
Dec 15 '11 at 13:48
You still have to find the last dot, not the first. (Reverse iterators are your friend!)
– James Kanze
Dec 15 '11 at 13:56
Ah yes, good point. So for a file.ext.ext then you would want to extract file.ext wouldn't you. :)
– TomP89
Dec 15 '11 at 13:57
Presumably. That's the usual convention, in any case:my.source.cpp
gets compiled tomy.source.obj
, for example (with the extension.cpp
replaced with.obj
).
– James Kanze
Dec 15 '11 at 14:02
add a comment |
I would do it by...
Search backwards from the end of the string until you find the first backslash/forward slash.
Then search backwards again from the end of the string until you find the first dot (.)
You then have the start and end of the file name.
Simples...
I would do it by...
Search backwards from the end of the string until you find the first backslash/forward slash.
Then search backwards again from the end of the string until you find the first dot (.)
You then have the start and end of the file name.
Simples...
edited Dec 15 '11 at 13:58
answered Dec 15 '11 at 13:23
TomP89TomP89
1,0421926
1,0421926
Which doesn't work for any system I know. (The one system which accepts'\'
as a path separator also uses'/'
, so you need to match either.) And I'm not sure what you'd be looking forward for.
– James Kanze
Dec 15 '11 at 13:32
Okay so modify it to match either, no biggy. And looking forward for the first dot (.)
– TomP89
Dec 15 '11 at 13:48
You still have to find the last dot, not the first. (Reverse iterators are your friend!)
– James Kanze
Dec 15 '11 at 13:56
Ah yes, good point. So for a file.ext.ext then you would want to extract file.ext wouldn't you. :)
– TomP89
Dec 15 '11 at 13:57
Presumably. That's the usual convention, in any case:my.source.cpp
gets compiled tomy.source.obj
, for example (with the extension.cpp
replaced with.obj
).
– James Kanze
Dec 15 '11 at 14:02
add a comment |
Which doesn't work for any system I know. (The one system which accepts'\'
as a path separator also uses'/'
, so you need to match either.) And I'm not sure what you'd be looking forward for.
– James Kanze
Dec 15 '11 at 13:32
Okay so modify it to match either, no biggy. And looking forward for the first dot (.)
– TomP89
Dec 15 '11 at 13:48
You still have to find the last dot, not the first. (Reverse iterators are your friend!)
– James Kanze
Dec 15 '11 at 13:56
Ah yes, good point. So for a file.ext.ext then you would want to extract file.ext wouldn't you. :)
– TomP89
Dec 15 '11 at 13:57
Presumably. That's the usual convention, in any case:my.source.cpp
gets compiled tomy.source.obj
, for example (with the extension.cpp
replaced with.obj
).
– James Kanze
Dec 15 '11 at 14:02
Which doesn't work for any system I know. (The one system which accepts
'\'
as a path separator also uses '/'
, so you need to match either.) And I'm not sure what you'd be looking forward for.– James Kanze
Dec 15 '11 at 13:32
Which doesn't work for any system I know. (The one system which accepts
'\'
as a path separator also uses '/'
, so you need to match either.) And I'm not sure what you'd be looking forward for.– James Kanze
Dec 15 '11 at 13:32
Okay so modify it to match either, no biggy. And looking forward for the first dot (.)
– TomP89
Dec 15 '11 at 13:48
Okay so modify it to match either, no biggy. And looking forward for the first dot (.)
– TomP89
Dec 15 '11 at 13:48
You still have to find the last dot, not the first. (Reverse iterators are your friend!)
– James Kanze
Dec 15 '11 at 13:56
You still have to find the last dot, not the first. (Reverse iterators are your friend!)
– James Kanze
Dec 15 '11 at 13:56
Ah yes, good point. So for a file.ext.ext then you would want to extract file.ext wouldn't you. :)
– TomP89
Dec 15 '11 at 13:57
Ah yes, good point. So for a file.ext.ext then you would want to extract file.ext wouldn't you. :)
– TomP89
Dec 15 '11 at 13:57
Presumably. That's the usual convention, in any case:
my.source.cpp
gets compiled to my.source.obj
, for example (with the extension .cpp
replaced with .obj
).– James Kanze
Dec 15 '11 at 14:02
Presumably. That's the usual convention, in any case:
my.source.cpp
gets compiled to my.source.obj
, for example (with the extension .cpp
replaced with .obj
).– James Kanze
Dec 15 '11 at 14:02
add a comment |
The boost
filesystem
library is also available as the experimental/filesystem
library and was merged into ISO C++ for C++17. You can use it like this:
#include <iostream>
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
int main () {
std::cout << fs::path("/foo/bar.txt").filename() << 'n'
}
Output:
"bar.txt"
It also works for std::string
objects.
Note that the later answer of @eliastem is the same...
– Adam Erickson
Jul 4 '18 at 1:25
add a comment |
The boost
filesystem
library is also available as the experimental/filesystem
library and was merged into ISO C++ for C++17. You can use it like this:
#include <iostream>
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
int main () {
std::cout << fs::path("/foo/bar.txt").filename() << 'n'
}
Output:
"bar.txt"
It also works for std::string
objects.
Note that the later answer of @eliastem is the same...
– Adam Erickson
Jul 4 '18 at 1:25
add a comment |
The boost
filesystem
library is also available as the experimental/filesystem
library and was merged into ISO C++ for C++17. You can use it like this:
#include <iostream>
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
int main () {
std::cout << fs::path("/foo/bar.txt").filename() << 'n'
}
Output:
"bar.txt"
It also works for std::string
objects.
The boost
filesystem
library is also available as the experimental/filesystem
library and was merged into ISO C++ for C++17. You can use it like this:
#include <iostream>
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
int main () {
std::cout << fs::path("/foo/bar.txt").filename() << 'n'
}
Output:
"bar.txt"
It also works for std::string
objects.
edited Jul 4 '18 at 1:23
answered Dec 1 '17 at 19:00
Adam EricksonAdam Erickson
1,7641320
1,7641320
Note that the later answer of @eliastem is the same...
– Adam Erickson
Jul 4 '18 at 1:25
add a comment |
Note that the later answer of @eliastem is the same...
– Adam Erickson
Jul 4 '18 at 1:25
Note that the later answer of @eliastem is the same...
– Adam Erickson
Jul 4 '18 at 1:25
Note that the later answer of @eliastem is the same...
– Adam Erickson
Jul 4 '18 at 1:25
add a comment |
m_szFilePath.MakeLower();
CFileFind finder;
DWORD buffSize = MAX_PATH;
char longPath[MAX_PATH];
DWORD result = GetLongPathName(m_szFilePath, longPath, MAX_PATH );
if( result == 0)
{
m_bExists = FALSE;
return;
}
m_szFilePath = CString(longPath);
m_szFilePath.Replace("/","\");
m_szFilePath.Trim();
//check if it does not ends in => remove it
int length = m_szFilePath.GetLength();
if( length > 0 && m_szFilePath[length - 1] == '\' )
{
m_szFilePath.Truncate( length - 1 );
}
BOOL bWorking = finder.FindFile(this->m_szFilePath);
if(bWorking){
bWorking = finder.FindNextFile();
finder.GetCreationTime(this->m_CreationTime);
m_szFilePath = finder.GetFilePath();
m_szFileName = finder.GetFileName();
this->m_szFileExtension = this->GetExtension( m_szFileName );
m_szFileTitle = finder.GetFileTitle();
m_szFileURL = finder.GetFileURL();
finder.GetLastAccessTime(this->m_LastAccesTime);
finder.GetLastWriteTime(this->m_LastWriteTime);
m_ulFileSize = static_cast<unsigned long>(finder.GetLength());
m_szRootDirectory = finder.GetRoot();
m_bIsArchive = finder.IsArchived();
m_bIsCompressed = finder.IsCompressed();
m_bIsDirectory = finder.IsDirectory();
m_bIsHidden = finder.IsHidden();
m_bIsNormal = finder.IsNormal();
m_bIsReadOnly = finder.IsReadOnly();
m_bIsSystem = finder.IsSystem();
m_bIsTemporary = finder.IsTemporary();
m_bExists = TRUE;
finder.Close();
}else{
m_bExists = FALSE;
}
The variable m_szFileName contains the fileName.
3
wow - that's a lot of code for "get file name" from path... :)
– Nim
Dec 15 '11 at 13:15
4
@Nim My impression as well. In my own code, I use a one-liner:boost::filesystem::path( path ).filename()
.
– James Kanze
Dec 15 '11 at 13:36
I have a CFileInfo class that has that code. I just dumped the code here because it is tested and I did not want to risk anything... You could just use about 5 lines of code from this example.
– Lucian
Dec 15 '11 at 13:42
add a comment |
m_szFilePath.MakeLower();
CFileFind finder;
DWORD buffSize = MAX_PATH;
char longPath[MAX_PATH];
DWORD result = GetLongPathName(m_szFilePath, longPath, MAX_PATH );
if( result == 0)
{
m_bExists = FALSE;
return;
}
m_szFilePath = CString(longPath);
m_szFilePath.Replace("/","\");
m_szFilePath.Trim();
//check if it does not ends in => remove it
int length = m_szFilePath.GetLength();
if( length > 0 && m_szFilePath[length - 1] == '\' )
{
m_szFilePath.Truncate( length - 1 );
}
BOOL bWorking = finder.FindFile(this->m_szFilePath);
if(bWorking){
bWorking = finder.FindNextFile();
finder.GetCreationTime(this->m_CreationTime);
m_szFilePath = finder.GetFilePath();
m_szFileName = finder.GetFileName();
this->m_szFileExtension = this->GetExtension( m_szFileName );
m_szFileTitle = finder.GetFileTitle();
m_szFileURL = finder.GetFileURL();
finder.GetLastAccessTime(this->m_LastAccesTime);
finder.GetLastWriteTime(this->m_LastWriteTime);
m_ulFileSize = static_cast<unsigned long>(finder.GetLength());
m_szRootDirectory = finder.GetRoot();
m_bIsArchive = finder.IsArchived();
m_bIsCompressed = finder.IsCompressed();
m_bIsDirectory = finder.IsDirectory();
m_bIsHidden = finder.IsHidden();
m_bIsNormal = finder.IsNormal();
m_bIsReadOnly = finder.IsReadOnly();
m_bIsSystem = finder.IsSystem();
m_bIsTemporary = finder.IsTemporary();
m_bExists = TRUE;
finder.Close();
}else{
m_bExists = FALSE;
}
The variable m_szFileName contains the fileName.
3
wow - that's a lot of code for "get file name" from path... :)
– Nim
Dec 15 '11 at 13:15
4
@Nim My impression as well. In my own code, I use a one-liner:boost::filesystem::path( path ).filename()
.
– James Kanze
Dec 15 '11 at 13:36
I have a CFileInfo class that has that code. I just dumped the code here because it is tested and I did not want to risk anything... You could just use about 5 lines of code from this example.
– Lucian
Dec 15 '11 at 13:42
add a comment |
m_szFilePath.MakeLower();
CFileFind finder;
DWORD buffSize = MAX_PATH;
char longPath[MAX_PATH];
DWORD result = GetLongPathName(m_szFilePath, longPath, MAX_PATH );
if( result == 0)
{
m_bExists = FALSE;
return;
}
m_szFilePath = CString(longPath);
m_szFilePath.Replace("/","\");
m_szFilePath.Trim();
//check if it does not ends in => remove it
int length = m_szFilePath.GetLength();
if( length > 0 && m_szFilePath[length - 1] == '\' )
{
m_szFilePath.Truncate( length - 1 );
}
BOOL bWorking = finder.FindFile(this->m_szFilePath);
if(bWorking){
bWorking = finder.FindNextFile();
finder.GetCreationTime(this->m_CreationTime);
m_szFilePath = finder.GetFilePath();
m_szFileName = finder.GetFileName();
this->m_szFileExtension = this->GetExtension( m_szFileName );
m_szFileTitle = finder.GetFileTitle();
m_szFileURL = finder.GetFileURL();
finder.GetLastAccessTime(this->m_LastAccesTime);
finder.GetLastWriteTime(this->m_LastWriteTime);
m_ulFileSize = static_cast<unsigned long>(finder.GetLength());
m_szRootDirectory = finder.GetRoot();
m_bIsArchive = finder.IsArchived();
m_bIsCompressed = finder.IsCompressed();
m_bIsDirectory = finder.IsDirectory();
m_bIsHidden = finder.IsHidden();
m_bIsNormal = finder.IsNormal();
m_bIsReadOnly = finder.IsReadOnly();
m_bIsSystem = finder.IsSystem();
m_bIsTemporary = finder.IsTemporary();
m_bExists = TRUE;
finder.Close();
}else{
m_bExists = FALSE;
}
The variable m_szFileName contains the fileName.
m_szFilePath.MakeLower();
CFileFind finder;
DWORD buffSize = MAX_PATH;
char longPath[MAX_PATH];
DWORD result = GetLongPathName(m_szFilePath, longPath, MAX_PATH );
if( result == 0)
{
m_bExists = FALSE;
return;
}
m_szFilePath = CString(longPath);
m_szFilePath.Replace("/","\");
m_szFilePath.Trim();
//check if it does not ends in => remove it
int length = m_szFilePath.GetLength();
if( length > 0 && m_szFilePath[length - 1] == '\' )
{
m_szFilePath.Truncate( length - 1 );
}
BOOL bWorking = finder.FindFile(this->m_szFilePath);
if(bWorking){
bWorking = finder.FindNextFile();
finder.GetCreationTime(this->m_CreationTime);
m_szFilePath = finder.GetFilePath();
m_szFileName = finder.GetFileName();
this->m_szFileExtension = this->GetExtension( m_szFileName );
m_szFileTitle = finder.GetFileTitle();
m_szFileURL = finder.GetFileURL();
finder.GetLastAccessTime(this->m_LastAccesTime);
finder.GetLastWriteTime(this->m_LastWriteTime);
m_ulFileSize = static_cast<unsigned long>(finder.GetLength());
m_szRootDirectory = finder.GetRoot();
m_bIsArchive = finder.IsArchived();
m_bIsCompressed = finder.IsCompressed();
m_bIsDirectory = finder.IsDirectory();
m_bIsHidden = finder.IsHidden();
m_bIsNormal = finder.IsNormal();
m_bIsReadOnly = finder.IsReadOnly();
m_bIsSystem = finder.IsSystem();
m_bIsTemporary = finder.IsTemporary();
m_bExists = TRUE;
finder.Close();
}else{
m_bExists = FALSE;
}
The variable m_szFileName contains the fileName.
answered Dec 15 '11 at 13:14
LucianLucian
2,5971418
2,5971418
3
wow - that's a lot of code for "get file name" from path... :)
– Nim
Dec 15 '11 at 13:15
4
@Nim My impression as well. In my own code, I use a one-liner:boost::filesystem::path( path ).filename()
.
– James Kanze
Dec 15 '11 at 13:36
I have a CFileInfo class that has that code. I just dumped the code here because it is tested and I did not want to risk anything... You could just use about 5 lines of code from this example.
– Lucian
Dec 15 '11 at 13:42
add a comment |
3
wow - that's a lot of code for "get file name" from path... :)
– Nim
Dec 15 '11 at 13:15
4
@Nim My impression as well. In my own code, I use a one-liner:boost::filesystem::path( path ).filename()
.
– James Kanze
Dec 15 '11 at 13:36
I have a CFileInfo class that has that code. I just dumped the code here because it is tested and I did not want to risk anything... You could just use about 5 lines of code from this example.
– Lucian
Dec 15 '11 at 13:42
3
3
wow - that's a lot of code for "get file name" from path... :)
– Nim
Dec 15 '11 at 13:15
wow - that's a lot of code for "get file name" from path... :)
– Nim
Dec 15 '11 at 13:15
4
4
@Nim My impression as well. In my own code, I use a one-liner:
boost::filesystem::path( path ).filename()
.– James Kanze
Dec 15 '11 at 13:36
@Nim My impression as well. In my own code, I use a one-liner:
boost::filesystem::path( path ).filename()
.– James Kanze
Dec 15 '11 at 13:36
I have a CFileInfo class that has that code. I just dumped the code here because it is tested and I did not want to risk anything... You could just use about 5 lines of code from this example.
– Lucian
Dec 15 '11 at 13:42
I have a CFileInfo class that has that code. I just dumped the code here because it is tested and I did not want to risk anything... You could just use about 5 lines of code from this example.
– Lucian
Dec 15 '11 at 13:42
add a comment |
Dont use _splitpath()
and _wsplitpath()
. They are not safe, and they are obsolete!
Instead, use their safe versions, namely _splitpath_s()
and _wsplitpath_s()
add a comment |
Dont use _splitpath()
and _wsplitpath()
. They are not safe, and they are obsolete!
Instead, use their safe versions, namely _splitpath_s()
and _wsplitpath_s()
add a comment |
Dont use _splitpath()
and _wsplitpath()
. They are not safe, and they are obsolete!
Instead, use their safe versions, namely _splitpath_s()
and _wsplitpath_s()
Dont use _splitpath()
and _wsplitpath()
. They are not safe, and they are obsolete!
Instead, use their safe versions, namely _splitpath_s()
and _wsplitpath_s()
answered Aug 5 '13 at 11:57
hkBattousaihkBattousai
5,1591356104
5,1591356104
add a comment |
add a comment |
This should work too :
// strPath = "C:\Dir\File.bat" for example
std::string getFileName(const std::string& strPath)
{
size_t iLastSeparator = 0;
return strPath.substr((iLastSeparator = strPath.find_last_of("\")) != std::string::npos ? iLastSeparator + 1 : 0, strPath.size() - strPath.find_last_of("."));
}
If you can use it, Qt provide QString (with split, trim etc), QFile, QPath, QFileInfo etc to manipulate files, filenames and directories. And of course it's also cross plaftorm.
4
For the sake of the future readers of your code, please use temporary variables with meaningful names instead of stuffing everything into a single line of code (and while you're at it, please encapsulate all this into a functiongetFilename
or something like that).
– Luc Touraille
Dec 15 '11 at 14:07
edited. But the point was to make it short, as several working answers already have been given.
– typedef
Dec 15 '11 at 14:32
1
I think it is WRONG. Should not you replace the last part: "strPath.size() - strPath.find_last_of(".")" by "strPath.find_last_of(".") - iLastSeparator"
– taktak004
Jan 22 '14 at 12:35
@taktak004 you are right, it should be ` return strPath.substr( (iLastSeparator = strPath.find_last_of("/")) != std::string::npos ? iLastSeparator + 1 : 0, strPath.find_last_of(".") - iLastSeparator );`
– phenmod
Dec 8 '15 at 10:08
add a comment |
This should work too :
// strPath = "C:\Dir\File.bat" for example
std::string getFileName(const std::string& strPath)
{
size_t iLastSeparator = 0;
return strPath.substr((iLastSeparator = strPath.find_last_of("\")) != std::string::npos ? iLastSeparator + 1 : 0, strPath.size() - strPath.find_last_of("."));
}
If you can use it, Qt provide QString (with split, trim etc), QFile, QPath, QFileInfo etc to manipulate files, filenames and directories. And of course it's also cross plaftorm.
4
For the sake of the future readers of your code, please use temporary variables with meaningful names instead of stuffing everything into a single line of code (and while you're at it, please encapsulate all this into a functiongetFilename
or something like that).
– Luc Touraille
Dec 15 '11 at 14:07
edited. But the point was to make it short, as several working answers already have been given.
– typedef
Dec 15 '11 at 14:32
1
I think it is WRONG. Should not you replace the last part: "strPath.size() - strPath.find_last_of(".")" by "strPath.find_last_of(".") - iLastSeparator"
– taktak004
Jan 22 '14 at 12:35
@taktak004 you are right, it should be ` return strPath.substr( (iLastSeparator = strPath.find_last_of("/")) != std::string::npos ? iLastSeparator + 1 : 0, strPath.find_last_of(".") - iLastSeparator );`
– phenmod
Dec 8 '15 at 10:08
add a comment |
This should work too :
// strPath = "C:\Dir\File.bat" for example
std::string getFileName(const std::string& strPath)
{
size_t iLastSeparator = 0;
return strPath.substr((iLastSeparator = strPath.find_last_of("\")) != std::string::npos ? iLastSeparator + 1 : 0, strPath.size() - strPath.find_last_of("."));
}
If you can use it, Qt provide QString (with split, trim etc), QFile, QPath, QFileInfo etc to manipulate files, filenames and directories. And of course it's also cross plaftorm.
This should work too :
// strPath = "C:\Dir\File.bat" for example
std::string getFileName(const std::string& strPath)
{
size_t iLastSeparator = 0;
return strPath.substr((iLastSeparator = strPath.find_last_of("\")) != std::string::npos ? iLastSeparator + 1 : 0, strPath.size() - strPath.find_last_of("."));
}
If you can use it, Qt provide QString (with split, trim etc), QFile, QPath, QFileInfo etc to manipulate files, filenames and directories. And of course it's also cross plaftorm.
edited Oct 18 '13 at 0:20
Prashant Kumar
11.2k134059
11.2k134059
answered Dec 15 '11 at 13:38
typedeftypedef
919159
919159
4
For the sake of the future readers of your code, please use temporary variables with meaningful names instead of stuffing everything into a single line of code (and while you're at it, please encapsulate all this into a functiongetFilename
or something like that).
– Luc Touraille
Dec 15 '11 at 14:07
edited. But the point was to make it short, as several working answers already have been given.
– typedef
Dec 15 '11 at 14:32
1
I think it is WRONG. Should not you replace the last part: "strPath.size() - strPath.find_last_of(".")" by "strPath.find_last_of(".") - iLastSeparator"
– taktak004
Jan 22 '14 at 12:35
@taktak004 you are right, it should be ` return strPath.substr( (iLastSeparator = strPath.find_last_of("/")) != std::string::npos ? iLastSeparator + 1 : 0, strPath.find_last_of(".") - iLastSeparator );`
– phenmod
Dec 8 '15 at 10:08
add a comment |
4
For the sake of the future readers of your code, please use temporary variables with meaningful names instead of stuffing everything into a single line of code (and while you're at it, please encapsulate all this into a functiongetFilename
or something like that).
– Luc Touraille
Dec 15 '11 at 14:07
edited. But the point was to make it short, as several working answers already have been given.
– typedef
Dec 15 '11 at 14:32
1
I think it is WRONG. Should not you replace the last part: "strPath.size() - strPath.find_last_of(".")" by "strPath.find_last_of(".") - iLastSeparator"
– taktak004
Jan 22 '14 at 12:35
@taktak004 you are right, it should be ` return strPath.substr( (iLastSeparator = strPath.find_last_of("/")) != std::string::npos ? iLastSeparator + 1 : 0, strPath.find_last_of(".") - iLastSeparator );`
– phenmod
Dec 8 '15 at 10:08
4
4
For the sake of the future readers of your code, please use temporary variables with meaningful names instead of stuffing everything into a single line of code (and while you're at it, please encapsulate all this into a function
getFilename
or something like that).– Luc Touraille
Dec 15 '11 at 14:07
For the sake of the future readers of your code, please use temporary variables with meaningful names instead of stuffing everything into a single line of code (and while you're at it, please encapsulate all this into a function
getFilename
or something like that).– Luc Touraille
Dec 15 '11 at 14:07
edited. But the point was to make it short, as several working answers already have been given.
– typedef
Dec 15 '11 at 14:32
edited. But the point was to make it short, as several working answers already have been given.
– typedef
Dec 15 '11 at 14:32
1
1
I think it is WRONG. Should not you replace the last part: "strPath.size() - strPath.find_last_of(".")" by "strPath.find_last_of(".") - iLastSeparator"
– taktak004
Jan 22 '14 at 12:35
I think it is WRONG. Should not you replace the last part: "strPath.size() - strPath.find_last_of(".")" by "strPath.find_last_of(".") - iLastSeparator"
– taktak004
Jan 22 '14 at 12:35
@taktak004 you are right, it should be ` return strPath.substr( (iLastSeparator = strPath.find_last_of("/")) != std::string::npos ? iLastSeparator + 1 : 0, strPath.find_last_of(".") - iLastSeparator );`
– phenmod
Dec 8 '15 at 10:08
@taktak004 you are right, it should be ` return strPath.substr( (iLastSeparator = strPath.find_last_of("/")) != std::string::npos ? iLastSeparator + 1 : 0, strPath.find_last_of(".") - iLastSeparator );`
– phenmod
Dec 8 '15 at 10:08
add a comment |
For long time I was looking for a function able to properly decompose file path. For me this code is working perfectly for both Linux and Windows.
void decomposePath(const char *filePath, char *fileDir, char *fileName, char *fileExt)
{
#if defined _WIN32
const char *lastSeparator = strrchr(filePath, '\');
#else
const char *lastSeparator = strrchr(filePath, '/');
#endif
const char *lastDot = strrchr(filePath, '.');
const char *endOfPath = filePath + strlen(filePath);
const char *startOfName = lastSeparator ? lastSeparator + 1 : filePath;
const char *startOfExt = lastDot > startOfName ? lastDot : endOfPath;
if(fileDir)
_snprintf(fileDir, MAX_PATH, "%.*s", startOfName - filePath, filePath);
if(fileName)
_snprintf(fileName, MAX_PATH, "%.*s", startOfExt - startOfName, startOfName);
if(fileExt)
_snprintf(fileExt, MAX_PATH, "%s", startOfExt);
}
Example results are:
fileDir: ''
fileName: ''
fileExt: ''
[.htaccess]
fileDir: ''
fileName: '.htaccess'
fileExt: ''
[a.exe]
fileDir: ''
fileName: 'a'
fileExt: '.exe'
[ab.c]
fileDir: 'a'
fileName: 'b'
fileExt: '.c'
[git-archive]
fileDir: ''
fileName: 'git-archive'
fileExt: ''
[git-archive.exe]
fileDir: ''
fileName: 'git-archive'
fileExt: '.exe'
[D:Gitmingw64libexecgit-core.htaccess]
fileDir: 'D:Gitmingw64libexecgit-core'
fileName: '.htaccess'
fileExt: ''
[D:Gitmingw64libexecgit-corea.exe]
fileDir: 'D:Gitmingw64libexecgit-core'
fileName: 'a'
fileExt: '.exe'
[D:Gitmingw64libexecgit-coregit-archive.exe]
fileDir: 'D:Gitmingw64libexecgit-core'
fileName: 'git-archive'
fileExt: '.exe'
[D:Gitmingw64libexecgit.coregit-archive.exe]
fileDir: 'D:Gitmingw64libexecgit.core'
fileName: 'git-archive'
fileExt: '.exe'
[D:Gitmingw64libexecgit-coregit-archiveexe]
fileDir: 'D:Gitmingw64libexecgit-core'
fileName: 'git-archiveexe'
fileExt: ''
[D:Gitmingw64libexecgit.coregit-archiveexe]
fileDir: 'D:Gitmingw64libexecgit.core'
fileName: 'git-archiveexe'
fileExt: ''
I hope this helps you also :)
add a comment |
For long time I was looking for a function able to properly decompose file path. For me this code is working perfectly for both Linux and Windows.
void decomposePath(const char *filePath, char *fileDir, char *fileName, char *fileExt)
{
#if defined _WIN32
const char *lastSeparator = strrchr(filePath, '\');
#else
const char *lastSeparator = strrchr(filePath, '/');
#endif
const char *lastDot = strrchr(filePath, '.');
const char *endOfPath = filePath + strlen(filePath);
const char *startOfName = lastSeparator ? lastSeparator + 1 : filePath;
const char *startOfExt = lastDot > startOfName ? lastDot : endOfPath;
if(fileDir)
_snprintf(fileDir, MAX_PATH, "%.*s", startOfName - filePath, filePath);
if(fileName)
_snprintf(fileName, MAX_PATH, "%.*s", startOfExt - startOfName, startOfName);
if(fileExt)
_snprintf(fileExt, MAX_PATH, "%s", startOfExt);
}
Example results are:
fileDir: ''
fileName: ''
fileExt: ''
[.htaccess]
fileDir: ''
fileName: '.htaccess'
fileExt: ''
[a.exe]
fileDir: ''
fileName: 'a'
fileExt: '.exe'
[ab.c]
fileDir: 'a'
fileName: 'b'
fileExt: '.c'
[git-archive]
fileDir: ''
fileName: 'git-archive'
fileExt: ''
[git-archive.exe]
fileDir: ''
fileName: 'git-archive'
fileExt: '.exe'
[D:Gitmingw64libexecgit-core.htaccess]
fileDir: 'D:Gitmingw64libexecgit-core'
fileName: '.htaccess'
fileExt: ''
[D:Gitmingw64libexecgit-corea.exe]
fileDir: 'D:Gitmingw64libexecgit-core'
fileName: 'a'
fileExt: '.exe'
[D:Gitmingw64libexecgit-coregit-archive.exe]
fileDir: 'D:Gitmingw64libexecgit-core'
fileName: 'git-archive'
fileExt: '.exe'
[D:Gitmingw64libexecgit.coregit-archive.exe]
fileDir: 'D:Gitmingw64libexecgit.core'
fileName: 'git-archive'
fileExt: '.exe'
[D:Gitmingw64libexecgit-coregit-archiveexe]
fileDir: 'D:Gitmingw64libexecgit-core'
fileName: 'git-archiveexe'
fileExt: ''
[D:Gitmingw64libexecgit.coregit-archiveexe]
fileDir: 'D:Gitmingw64libexecgit.core'
fileName: 'git-archiveexe'
fileExt: ''
I hope this helps you also :)
add a comment |
For long time I was looking for a function able to properly decompose file path. For me this code is working perfectly for both Linux and Windows.
void decomposePath(const char *filePath, char *fileDir, char *fileName, char *fileExt)
{
#if defined _WIN32
const char *lastSeparator = strrchr(filePath, '\');
#else
const char *lastSeparator = strrchr(filePath, '/');
#endif
const char *lastDot = strrchr(filePath, '.');
const char *endOfPath = filePath + strlen(filePath);
const char *startOfName = lastSeparator ? lastSeparator + 1 : filePath;
const char *startOfExt = lastDot > startOfName ? lastDot : endOfPath;
if(fileDir)
_snprintf(fileDir, MAX_PATH, "%.*s", startOfName - filePath, filePath);
if(fileName)
_snprintf(fileName, MAX_PATH, "%.*s", startOfExt - startOfName, startOfName);
if(fileExt)
_snprintf(fileExt, MAX_PATH, "%s", startOfExt);
}
Example results are:
fileDir: ''
fileName: ''
fileExt: ''
[.htaccess]
fileDir: ''
fileName: '.htaccess'
fileExt: ''
[a.exe]
fileDir: ''
fileName: 'a'
fileExt: '.exe'
[ab.c]
fileDir: 'a'
fileName: 'b'
fileExt: '.c'
[git-archive]
fileDir: ''
fileName: 'git-archive'
fileExt: ''
[git-archive.exe]
fileDir: ''
fileName: 'git-archive'
fileExt: '.exe'
[D:Gitmingw64libexecgit-core.htaccess]
fileDir: 'D:Gitmingw64libexecgit-core'
fileName: '.htaccess'
fileExt: ''
[D:Gitmingw64libexecgit-corea.exe]
fileDir: 'D:Gitmingw64libexecgit-core'
fileName: 'a'
fileExt: '.exe'
[D:Gitmingw64libexecgit-coregit-archive.exe]
fileDir: 'D:Gitmingw64libexecgit-core'
fileName: 'git-archive'
fileExt: '.exe'
[D:Gitmingw64libexecgit.coregit-archive.exe]
fileDir: 'D:Gitmingw64libexecgit.core'
fileName: 'git-archive'
fileExt: '.exe'
[D:Gitmingw64libexecgit-coregit-archiveexe]
fileDir: 'D:Gitmingw64libexecgit-core'
fileName: 'git-archiveexe'
fileExt: ''
[D:Gitmingw64libexecgit.coregit-archiveexe]
fileDir: 'D:Gitmingw64libexecgit.core'
fileName: 'git-archiveexe'
fileExt: ''
I hope this helps you also :)
For long time I was looking for a function able to properly decompose file path. For me this code is working perfectly for both Linux and Windows.
void decomposePath(const char *filePath, char *fileDir, char *fileName, char *fileExt)
{
#if defined _WIN32
const char *lastSeparator = strrchr(filePath, '\');
#else
const char *lastSeparator = strrchr(filePath, '/');
#endif
const char *lastDot = strrchr(filePath, '.');
const char *endOfPath = filePath + strlen(filePath);
const char *startOfName = lastSeparator ? lastSeparator + 1 : filePath;
const char *startOfExt = lastDot > startOfName ? lastDot : endOfPath;
if(fileDir)
_snprintf(fileDir, MAX_PATH, "%.*s", startOfName - filePath, filePath);
if(fileName)
_snprintf(fileName, MAX_PATH, "%.*s", startOfExt - startOfName, startOfName);
if(fileExt)
_snprintf(fileExt, MAX_PATH, "%s", startOfExt);
}
Example results are:
fileDir: ''
fileName: ''
fileExt: ''
[.htaccess]
fileDir: ''
fileName: '.htaccess'
fileExt: ''
[a.exe]
fileDir: ''
fileName: 'a'
fileExt: '.exe'
[ab.c]
fileDir: 'a'
fileName: 'b'
fileExt: '.c'
[git-archive]
fileDir: ''
fileName: 'git-archive'
fileExt: ''
[git-archive.exe]
fileDir: ''
fileName: 'git-archive'
fileExt: '.exe'
[D:Gitmingw64libexecgit-core.htaccess]
fileDir: 'D:Gitmingw64libexecgit-core'
fileName: '.htaccess'
fileExt: ''
[D:Gitmingw64libexecgit-corea.exe]
fileDir: 'D:Gitmingw64libexecgit-core'
fileName: 'a'
fileExt: '.exe'
[D:Gitmingw64libexecgit-coregit-archive.exe]
fileDir: 'D:Gitmingw64libexecgit-core'
fileName: 'git-archive'
fileExt: '.exe'
[D:Gitmingw64libexecgit.coregit-archive.exe]
fileDir: 'D:Gitmingw64libexecgit.core'
fileName: 'git-archive'
fileExt: '.exe'
[D:Gitmingw64libexecgit-coregit-archiveexe]
fileDir: 'D:Gitmingw64libexecgit-core'
fileName: 'git-archiveexe'
fileExt: ''
[D:Gitmingw64libexecgit.coregit-archiveexe]
fileDir: 'D:Gitmingw64libexecgit.core'
fileName: 'git-archiveexe'
fileExt: ''
I hope this helps you also :)
answered Feb 23 '17 at 19:46
no one specialno one special
458212
458212
add a comment |
add a comment |
shlwapi.lib/dll
uses the HKCU
registry hive internally.
It's best not to link to shlwapi.lib
if you're creating a library or the product does not have a UI. If you're writing a lib then your code can be used in any project including those that don't have UIs.
If you're writing code that runs when a user is not logged in (e.g. service [or other] set to start at boot or startup) then there's no HKCU
. Lastly, shlwapi are settlement functions; and as a result high on the list to deprecate in later versions of Windows.
add a comment |
shlwapi.lib/dll
uses the HKCU
registry hive internally.
It's best not to link to shlwapi.lib
if you're creating a library or the product does not have a UI. If you're writing a lib then your code can be used in any project including those that don't have UIs.
If you're writing code that runs when a user is not logged in (e.g. service [or other] set to start at boot or startup) then there's no HKCU
. Lastly, shlwapi are settlement functions; and as a result high on the list to deprecate in later versions of Windows.
add a comment |
shlwapi.lib/dll
uses the HKCU
registry hive internally.
It's best not to link to shlwapi.lib
if you're creating a library or the product does not have a UI. If you're writing a lib then your code can be used in any project including those that don't have UIs.
If you're writing code that runs when a user is not logged in (e.g. service [or other] set to start at boot or startup) then there's no HKCU
. Lastly, shlwapi are settlement functions; and as a result high on the list to deprecate in later versions of Windows.
shlwapi.lib/dll
uses the HKCU
registry hive internally.
It's best not to link to shlwapi.lib
if you're creating a library or the product does not have a UI. If you're writing a lib then your code can be used in any project including those that don't have UIs.
If you're writing code that runs when a user is not logged in (e.g. service [or other] set to start at boot or startup) then there's no HKCU
. Lastly, shlwapi are settlement functions; and as a result high on the list to deprecate in later versions of Windows.
edited Dec 28 '18 at 16:00
rguerin
50817
50817
answered Dec 28 '18 at 12:38
BrookBrook
1
1
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f8520560%2fget-a-file-name-from-a-path%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
Search from the back until you hit a backspace?
– Kerrek SB
Dec 15 '11 at 13:13
2
@KerrekSB, you mean backslash ;)
– Nim
Dec 15 '11 at 13:14
i have an std::string that contains a path of a file "c:\MyDirectory\Myfile.pdf" i need to rename this file to myfile_md.pdf so i need to get the file name from the path.
– nidhal
Dec 15 '11 at 13:20
1
If you need to do a lot of work with file paths consider using Boost FileSystem boost.org/doc/libs/release/libs/filesystem/v3/doc/index.htm
– edA-qa mort-ora-y
Dec 15 '11 at 13:26
2
@Nim: Yes! I must have been spacing out...
– Kerrek SB
Dec 15 '11 at 13:42