开发者

Portable generation of a new file name in a specified directory

How can I portably (I am mostly interested in windows and linux) generate a new file name in a specified directory, with specified filename prefix and suffix?

std::string UniqueName(std::string const& dir, std::string const& prefix,
                       std::string const& suffix);

Any suggestions to implem开发者_开发问答ent this function, with as little as possible explicit dependencies on specific platforms.


Be aware that doing this wrong is a security hole. There are tricks to exploit temporary(ish) files, and these can give Administrator access to the whole system, not just your app. See this for some advice.

A couple of ways to do this:

  • Whenever possible, use library-provided functions instead of writing your own. For example, in Windows use GetTempFileName, on Linux use mkstemp.
  • Use boost::filesystem::unique_path, which lets you reliably generate unique filenames according to a template you provide.

boost::filesystem is scheduled to become a part of C++ TR2, which should be supported by almost all compilers in the future. Note that you must #define BOOST_FILESYSTEM_VERSION 3 (info), otherwise you’ll get an older version of boost::filesystem that doesn’t support unique_path.


You could generate a UUID to create unique names. See this link for a list of implementations in C++.


For a windows solution, Generate a guid and use it as the filename

Here is the code to generate the guid to get you started.

_TUCHAR *guidStr = 0x00;
GUID *pguid = 0x00;
pguid = new GUID;
CoCreateGuid(pguid);
// Convert the GUID to a string
UuidToString(pguid, &guidStr);
delete pguid;


The function, given the signature you have, is impossible to implement perfectly. With filesystems, you very often have the problem of race conditions:

  • Your functions decides on a filename "foobar"
  • Someone else creates the file "foobar"
  • Your program can't open "foobar" because someone else in step 2 beat you to it.

POSIX machines have a function to get around this: mkstemp. Unfortunately, there is no Windows equivalent to this. On Windows, use GetTempFileName, which is closer to mktemp, but use CREATE_NEW when calling CreateFile, which will cause CreateFile to fail if the file exists. From there, you can implement a Windows version of mkstemp.


untested code, but i use something very similar in a couple projects

std::string UniqueName(std::string const& dir = _T(""), std::string const& prefix = _T(""), std::string const& suffix = _T(""))
{
    std::string retVal = _T("");

    std::string sDirectory = boost::filesystem::temp_directory_path().string();

    if ( ! dir.empty() )
        sDirectory = dir;

    std::string sFilesName = _T("%%%%-%%%%-%%%%-%%%%");

    if ( ! prefix.empty() )
        sFilesName = prefix;

    boost::format fmter( _T("%s%s%s") );
    std::string sModel = boost::str ( boost::format ( fmter 
        % sDirectory
        % sFilesName
        % suffix ) );

    boost::filesystem::path temp = boost::filesystem::unique_path(sModel);
    retVal = temp.string();

    return retVal;
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜