пытаюсь открыть файл через std::ifstream::open, полный путь к которому передается через диалог "выбор файла" (Qt5 + MSVS2013). и вот какая гадость: по одним путям он файл открывает, а по другим — нет. в чем может быть засада?
путь, по которому не открывает, наподобие "d:\WORK\!!!!!статья — блабла\programma\projs\conception\"
что-то с кириллицей? или из-за пробелов?
и еще, можно ли как-то узнать про причину (код ошибки)? гугл ничего хорошего не дает
Здравствуйте, _hum_, Вы писали:
__>что-то с кириллицей?
я бы предположил, что из-за кириллицы
какой именно open используете?
этот?
open(const wchar_t *_Filename
как входную строчку задаете? что куда конвертируете (скорее всего из QtString?)? в какой кодировке? короче, надо код и точные значения строк, которые в дебагере, иначе много телепатировать
Здравствуйте, _hum_, Вы писали:
__>заработало. но такой код вообще переносим (меня смущает конвертация из QString в std::wstring)?
конвертация хитро работает:
std::wstring QString::toStdWString() const
Returns a std::wstring object with the data contained in this QString. The std::wstring is encoded in utf16 on platforms where wchar_t is 2 bytes wide (e.g. windows) and in ucs4 on platforms where wchar_t is 4 bytes wide (most Unix systems).
Здравствуйте, uzhas, Вы писали:
U>Здравствуйте, _hum_, Вы писали:
__>>заработало. но такой код вообще переносим (меня смущает конвертация из QString в std::wstring)?
U>конвертация хитро работает: U>
U>std::wstring QString::toStdWString() const
U>Returns a std::wstring object with the data contained in this QString. The std::wstring is encoded in utf16 on platforms where wchar_t is 2 bytes wide (e.g. windows) and in ucs4 on platforms where wchar_t is 4 bytes wide (most Unix systems).
ну, как бы это считается переносимостью (ибо для юниса придется компилировать для юникса)
U>ну и open(wchar_t*) есть только на винде
в каком смысле "есть только на винде"? и, кстаи, что-то я в доках вообще не нахожу этой функции: cplusplus.com/ifstream::open
Здравствуйте, _hum_, Вы писали:
__>ну, как бы это считается переносимостью (ибо для юниса придется компилировать для юникса)
в юниксах не используют wchar_t, используют char* в UTF-8 формате
__>в каком смысле "есть только на винде"? и, кстаи, что-то я в доках вообще не нахожу этой функции: cplusplus.com/ifstream::open
я же говорю, что есть только в visual studio. читай msdn
__>заработало. но такой код вообще переносим (меня смущает конвертация из QString в std::wstring)?
На 99% уверен что проблемы была в кодировке, ибо вот:
QString qsFullFileName;
// Если исходный файл в кодировке: utf-8
qsFullFileName = QString::fromUtf8(R"(d:\WORK\!!!!!статья — блабла\programma\projs\conception\file)");
qsFullFileName = QTextCodec::codecForName("UTF8")->toUnicode(R"(d:\WORK\!!!!!статья — блабла\programma\projs\conception\file)");
// Если исходный файл в кодировке: Windows-1251
qsFullFileName = QTextCodec::codecForName("CP1251")->toUnicode(R"(d:\WORK\!!!!!статья — блабла\programma\projs\conception\file)");
std::ifstream ifs;
ifs.open(qsFullFileName.toLocal8Bit());
// Если код исполняется на ОС Windows (запуск из explorer'а, IDE)
ifs.open(QTextCodec::codecForName("CP1251")->fromUnicode(qsFullFileName));
// Если код исполняется на ОС Windows (запуск из CMD)
ifs.open(QTextCodec::codecForName("IBM866")->fromUnicode(qsFullFileName));
std::cout << "open = " << std::boolalpha << ifs.is_open() << std::endl;
Здравствуйте, uzhas, Вы писали:
U>Здравствуйте, _hum_, Вы писали:
__>>ну, как бы это считается переносимостью (ибо для юниса придется компилировать для юникса)
U>в юниксах не используют wchar_t, используют char* в UTF-8 формате
вот же гадство.. а я всюду старался с wstring работать, а оно, оказывается:
"The width of wchar_t is compiler-specific and can be as small as 8 bits. Consequently, programs that need to be portable across any C or C++ compiler should not use wchar_t for storing Unicode text. The wchar_t type is intended for storing compiler-defined wide characters, which may be Unicode characters in some compilers."
__>>в каком смысле "есть только на винде"? и, кстаи, что-то я в доках вообще не нахожу этой функции: cplusplus.com/ifstream::open
U>я же говорю, что есть только в visual studio. читай msdn
нее, wchar_t есть в стандарте, поэтому не совсем понятно, почему в стандарте нет open(wchar_t*) [конечно, оно выглядит кривовато, но весь wchar_t, как оказалось, сам такой, а потому, если уж поддерживаете в одном месте, то почему не поддерживаете в другом]
а еще непонятно, почему не сделают open(char_t* filename) с явным указанием кодировки filename, чтобы функция сама уже там внутри конвертила к нужной файловой системе кодировке, не утруждая программиста заниматься этими техническими деталями
__>да. но остался вопрос — как все-таки правильно тогда работать, чтоб не зависеть от платформы (с точностью до перекомпиляции под нужную)?
Кросс-платформенного решения на этот счёт в стандартной библиотеке C++, к сожалению, не существует. Так что вы можете:
— Использовать какую-то стороннюю библиотеку
— Хранить пути до файлов в UTF8 (использовать при этом std::string) и в случае WinAPI конвертировать их в UTF-16 с последующим вызовом wchar_t-функций (CreateFileW / нестандартная перегрузка функции-члена std::ifstream::open). Больше по этому поводу тут.
Здравствуйте, b0r3d0m, Вы писали:
B>И да, раз уж вы всё равно используете Qt, то почему бы не сохранить исходный файл в UTF8 и использовать что-то наподобие
B>
так проблема именно в том, что пути формирует qt-шный QFileDialog, а объект файла создает std::ifstream. и нужно каким-то образом согласовать их между собой (отказаться от std::ifstream я не могу, поскольку пользуюсь библиотекой сериализации cereal, в которой требуется именно он).
вот если бы было QFile::toStdIfstream(), то тогда все бы просто решалось
п.с. и как все-таки обстоит дело с "можно ли как-то узнать про причину (код ошибки)?" при работе с std::ifstream. судя по гуглу, создается впечатление, что с++ до сих пор ничего внятного на этот счет не может предложить.
__>так проблема именно в том, что пути формирует qt-шный QFileDialog, а объект файла создает std::ifstream
И в чём конкретно проблема?
QString хранит строки в UTF16 (https://wiki.qt.io/QString). Берите и конвертируйте их в UTF8 для *nix-систем или передавайте как есть в CreateFileW / std::fstream::open в случае Windows.
__>п.с. и как все-таки обстоит дело с "можно ли как-то узнать про причину (код ошибки)?" при работе с std::ifstream. судя по гуглу, создается впечатление, что с++ до сих пор ничего внятного на этот счет не может предложить.
Здравствуйте, b0r3d0m, Вы писали:
B>>>И да, раз уж вы всё равно используете Qt, то почему бы не сохранить исходный файл в UTF8 и использовать что-то наподобие
B>>>
__>>так проблема именно в том, что пути формирует qt-шный QFileDialog, а объект файла создает std::ifstream
B>И в чём конкретно проблема? B>QString хранит строки в UTF16 (https://wiki.qt.io/QString). Берите и конвертируйте их в UTF8 для *nix-систем или передавайте как есть в CreateFileW / std::fstream::open в случае Windows.
в моем понимании, переносимость кода — это независимость от системы, под которую он будет компилироваться (то есть, без "если под unix, то так, если под win, то эдак")
__>>п.с. и как все-таки обстоит дело с "можно ли как-то узнать про причину (код ошибки)?" при работе с std::ifstream. судя по гуглу, создается впечатление, что с++ до сих пор ничего внятного на этот счет не может предложить.
B>Либо устанавливай exception mask для std::fstream
B>
__>в моем понимании, переносимость кода — это независимость от системы, под которую он будет компилироваться (то есть, без "если под unix, то так, если под win, то эдак")
Чёт не понял. Вы же в любом случае не сможете, например, запустить ELF на системе, где требуется PE. Так что компилировать исходники под каждую платформу отдельно всё равно придётся. Не вижу проблем написать парочку препроцессорных директив, если требуется переносимость кода.
__>это не работает, см. stackoverflow.com: how-to-get-error-message-when-ifstream-open-fails
Не "не работает", а пользоваться надо с осторожностью, о чём я и написал.
Да, std::strerror нельзя вызывать одновременно из нескольких потоков. Да, errno после вызова std::fstream::open может содержать не то значение, на которое рассчитывает разработчик.
Если это не устраивает, то устанавливайте exception mask, пример кода я привёл ранее. Да, текст ошибки implementation-defined и может быть совершенно не информативным.
Здравствуйте, b0r3d0m, Вы писали:
__>>в моем понимании, переносимость кода — это независимость от системы, под которую он будет компилироваться (то есть, без "если под unix, то так, если под win, то эдак")
B>Чёт не понял. Вы же в любом случае не сможете, например, запустить ELF на системе, где требуется PE. Так что компилировать исходники под каждую платформу отдельно всё равно придётся. Не вижу проблем написать парочку препроцессорных директив, если требуется переносимость кода.
мне нужна независимость source code от платформы, под которую он будет компилироваться. вариант с препроцессорными директивами — это, имхо, костыли
__>>это не работает, см. stackoverflow.com: how-to-get-error-message-when-ifstream-open-fails
B>Не "не работает", а пользоваться надо с осторожностью, о чём я и написал. B>Да, std::strerror нельзя вызывать одновременно из нескольких потоков. Да, errno после вызова std::fstream::open может содержать не то значение, на которое рассчитывает разработчик. B>Если это не устраивает, то устанавливайте exception mask, пример кода я привёл ранее. Да, текст ошибки implementation-defined и может быть совершенно не информативным.
вы серьезно после всего сказанного "и что не всегда работает, и что текст ошибки implementation-defined" считаете, что это рабочий вариант?
__>>>в моем понимании, переносимость кода — это независимость от системы, под которую он будет компилироваться (то есть, без "если под unix, то так, если под win, то эдак")
B>>Чёт не понял. Вы же в любом случае не сможете, например, запустить ELF на системе, где требуется PE. Так что компилировать исходники под каждую платформу отдельно всё равно придётся. Не вижу проблем написать парочку препроцессорных директив, если требуется переносимость кода.
__>мне нужна независимость source code от платформы, под которую он будет компилироваться. вариант с препроцессорными директивами — это, имхо, костыли
Иначе средствами стандартной библиотеки сделать не получится.
__>>>это не работает, см. stackoverflow.com: how-to-get-error-message-when-ifstream-open-fails
B>>Не "не работает", а пользоваться надо с осторожностью, о чём я и написал. B>>Да, std::strerror нельзя вызывать одновременно из нескольких потоков. Да, errno после вызова std::fstream::open может содержать не то значение, на которое рассчитывает разработчик. B>>Если это не устраивает, то устанавливайте exception mask, пример кода я привёл ранее. Да, текст ошибки implementation-defined и может быть совершенно не информативным.
__>вы серьезно после всего сказанного "и что не всегда работает, и что текст ошибки implementation-defined" считаете, что это рабочий вариант?
Это единственный вариант с использованием только стандартной библиотеки C++. Либо это, либо сторонние либы.
Здравствуйте, b0r3d0m, Вы писали:
B>Иначе средствами стандартной библиотеки сделать не получится.
B>Это единственный вариант с использованием только стандартной библиотеки C++. Либо это, либо сторонние либы.
попутно вопрос: это принципиально невозможно, или просто недоработка языка?