Использование std :: filesystem :: path для преобразования между типами разделителей - PullRequest
0 голосов
/ 04 февраля 2019

Я работаю над кодом, который включает в себя загрузку файла из пути, который составлен как объединение заданного «базового» пути и вторичного относительного пути, загруженного из другого файла.Например (и там, где я сталкиваюсь с проблемой), базовый путь - «assets / models /», а вторичный путь - «maps \ map.png».Прямое объединение этих двух строк дает "assets / models / maps \ map.png".При работе в системах POSIX это не удается загрузить.До сих пор я разбирался с этим, просто заменяя обратные слэши на прямые косые черты на

std::replace( path.begin(), path.end(), '\\', '/' );

, но я хотел бы использовать C ++ 17 для std::filesystem::pathэто вместо этого.

Описание std::filesystem::path::make_preferred() предполагает, что он должен заменить разделители:

"Преобразовывает все разделители каталога в представлении общего формата пути к предпочтительному каталогуразделитель. Например, в Windows, где \ является предпочтительным разделителем, путь foo / bar будет преобразован в foo \ bar "

Однако при реализации в коде он не преобразуетсячто-нибудь.Я также проверил, что std :: filesystem :: path :: предпочитаемый_сепаратор соответствует ожидаемому - '/'.

Не понимаю ли я цель make_preferred()?Или я просто неправильно его использую?

Вот урезанная версия кода, которая не работает (это не реализованный код, но достаточно близко к нему):

const char * loadedPath = "maps\\map.png"
std::string loadedPathStr = std::string( loadedPath );
auto wPath = std::filesystem::path( loadedPathStr );
wPath = wPath.make_preferred();

basePath = std::filesystem::path( "./a/b/" );
auto totalPath = basePath / wPath;
auto wStr = totalPath.generic_string();
std::cout << wStr << std::endl;

Это выводит "./a/b/maps\\map.png"

При отладке внедренного кода, похоже, что wPath оптимизировано;нет никакого способа проверить это.

Странно, когда я компилирую и запускаю эту автономную тестовую программу, она работает как положено:

int main(){
   assert( std::filesystem::path::preferred_separator == '/' );            
   const char * cPath = "maps\\map.png";
   std::string path = std::string( cPath );
   auto wPath = std::filesystem::path( path );
   wPath = wPath.make_preferred();
   std::string wStr = wPath.generic_string();
   std::cout << wStr << std::endl;
}

Это выводит "maps / map.png". Я не умею читать.Это также выводит неверное значение.

Кто-нибудь знает, что здесь происходит?

РЕДАКТИРОВАТЬ: Попытка компиляции с помощью clang (с использованием gcc раньше), и она работает как положено (разделитель конвертируется). Проигнорируйте это, допустили ошибку при перекомпиляции.

Я запускаю это в Linux, и путь существует.

Ответы [ 2 ]

0 голосов
/ 04 февраля 2019

Если вы хотите написать кроссплатформенный код с filesystem, вам следует придерживаться универсального формата.Поведение всех других форматов строк файловой системы зависит от реализации.

Реализация, которая позволяет альтернативным разделителям каталогов рассматривать их как разделители каталогов.Но другие, совершенно допустимые реализации, которые не распознают эти разделители, не распознают их.«/» всегда является разделителем каталогов;"\" является разделителем или нет, зависит от реализации.

make_preferred преобразует из формата пути реализации в общий формат.Таким образом, его поведение зависит от реализации.

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

0 голосов
/ 04 февраля 2019

Не понимаю ли я цель make_preferred()?

Не совсем, но тонко да.Разделитель каталогов (в общем формате) является либо предпочтительным разделителем, либо резервным разделителем: /.В системах, где предпочтительным разделителем является / (например, POSIX), разделителем каталога является только /.В таких системах make_preferred не изменяет путь, что объясняет, почему он будет полностью оптимизирован.

Самый простой способ заменить обратные косые черты на прямые косые черты - std::replace.Однако обратите внимание, что обратная косая черта является допустимым символом в именах файлов в POSIX, поэтому такое преобразование может нарушить использование имен файлов, которые его используют.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...