C / C ++ Есть ли кросс-платформенный способ использования относительных путей? - PullRequest
4 голосов
/ 22 декабря 2010

Я программирую небольшую игру на SDL, и файлы структурированы так:

"src / game /" содержит исходные файлы .h и .cpp.

«данные /» содержат файлы игры, такие как карты, наборы плиток, спрайты и так далее ...

для загрузки спрайта, например, я бы использовал следующий код.

spriteLib.loadSprite("data/sprites/sprite-ghost.bmp");

для преобразования этой строки в абсолютный путь. У меня есть эти строки в первых 4 строках функции:

SSprite CSpriteLib::loadSprite(std::string file)
{
    //Converting the file path
    char converted[128];
    realpath(file.c_str(),converted);
    file = converted;

Но в этом случае программа компилируется только под liux, так что ... если кто-нибудь знает другой способ сделать это, я был бы благодарен.

Ответы [ 4 ]

5 голосов
/ 22 декабря 2010

Повышение - твой друг. Вот ссылка на учебник Boost Filesystem .

3 голосов
/ 22 декабря 2010

Несколько баллов:

char converted[128];
realpath(file.c_str(),converted);
  1. Прежде всего realpath в некоторых операционных системах (Solaris) может по-прежнему возвращать относительный путь.
  2. Ваш код содержит переполнение буфера,лучше использовать canonicalize_file_name или char *m=realpath(file.c_str(),0); ... free(m); - однако это специфично для Linux.Смотрите man realpath, чтобы узнать, как использовать его более или менее правильно.

Кроме того, как realpath поможет вам открыть ваши данные?Если

fopen(converted,"r")

работает в вашем случае, то

fopen(file.c_str(),"r")

также будет работать.Он предназначен для удаления всех символических ссылок и т. Д.

Если вам нужна функциональность, аналогичная realpath, вы можете использовать GetFullPathName под Windows, но она по-прежнему ведет себя по-другому.

1 голос
/ 22 декабря 2010

Просто написал крошечный класс для него:

#include <string>
#include <vector>
#include <iostream>

class CFilePath
{
        typedef std::vector<std::string> TPath;
    public:
        enum EPlatform
        {  
            Windows,
            Unix
        };
        CFilePath(EPlatform p_platform) : m_platform(p_platform) {}
        CFilePath& operator/(const char* p_path)
        {  
            m_path.push_back(p_path);
            return *this;
        }

        std::string GetPath()
        {  
            std::string ret;
            if (m_path.empty())
                return ret;
            for (unsigned i = 0; i < m_path.size();)
            {
                ret+=m_path[i];
                i++;
                if (i < m_path.size())
                {  
                    switch (m_platform)
                    {  
                        case Windows:
                            ret+="\\";
                            break;
                        case Unix:
                            ret+="/";
                            break;
                    }
                }
            }
            return ret;
        }
        operator const char*()
        {
            return GetPath().c_str();
        }
        EPlatform m_platform;

    private:
        std::vector<std::string> m_path;
};

int main(int argc, char* argv[])
{
    CFilePath::EPlatform platform = CFilePath::Windows; // variable
    CFilePath path(platform);
    path/"data"/"sprites"/"sprite-ghost.bmp";
    std::cout << path << std::endl;
    path.m_platform = CFilePath::Unix;
    std::cout << path << std::endl;

    return 0;
}

будет печатать:

data\sprites\sprite-ghost.bmp
data/sprites/sprite-ghost.bmp
0 голосов
/ 22 декабря 2010

Моя рекомендация: во-первых, ваша основная программа должна принять собственное имя файла в качестве аргумента, представляющего, где находятся данные для программы, например,

C:\program files\mycompany\mygame

Это возлагает ответственность за решение, какие данные использовать.другой программе (например, bash-скрипту или драйверу и т. д.).

Во-вторых, определите части пространства каталога с данными в формате unix , чтобы все литералы имен файлов в вашей программеесть этот формат.Нет ifs и но, всегда Unix.Например:

spriteLib.loadSprite("data/sprites/sprite-ghost.bmp");

Теперь напишите функцию, которая объединяет переданное имя каталога (в собственном формате) с именем файла unix, переведенным в собственный формат, чтобы получить подходящее имя файла для доступа.Вы уже пытались это сделать, но используете функцию, зависящую от ОС.Не.Напиши это сам.Вы хотите получить это:

C:\program files\mycompany\mygame\data\sprites\sprite-ghost.bmp

Метод @ Industrial-антидепрессант (ранее @ хорошая блондинка глупая девушка) тоже довольно хорош, но это немного больше работы.

...