проблема с std::ifstream::open
От: _hum_ Беларусь  
Дата: 30.09.16 14:22
Оценка:
пытаюсь открыть файл через std::ifstream::open, полный путь к которому передается через диалог "выбор файла" (Qt5 + MSVS2013). и вот какая гадость: по одним путям он файл открывает, а по другим — нет. в чем может быть засада?
путь, по которому не открывает, наподобие "d:\WORK\!!!!!статья — блабла\programma\projs\conception\"
что-то с кириллицей? или из-за пробелов?

и еще, можно ли как-то узнать про причину (код ошибки)? гугл ничего хорошего не дает
Re: проблема с std::ifstream::open
От: uzhas Ниоткуда  
Дата: 30.09.16 14:33
Оценка:
Здравствуйте, _hum_, Вы писали:

__>что-то с кириллицей?


я бы предположил, что из-за кириллицы
какой именно open используете?
этот?

open(const wchar_t *_Filename


как входную строчку задаете? что куда конвертируете (скорее всего из QtString?)? в какой кодировке? короче, надо код и точные значения строк, которые в дебагере, иначе много телепатировать
Re[2]: проблема с std::ifstream::open
От: _hum_ Беларусь  
Дата: 30.09.16 14:39
Оценка:
Здравствуйте, uzhas, Вы писали:

U>Здравствуйте, _hum_, Вы писали:


__>>что-то с кириллицей?


U>я бы предположил, что из-за кириллицы



да, кириллица. и да через обычный (не wide-char)

теперь переделал на
QString qsFullFileName = QFileDialog::getOpenFileName(...);

if(!qsFullFileName.isEmpty())
        {
            //---
            std::ifstream ifs;

            ifs.open(qsFullFileName.toStdWString());


заработало. но такой код вообще переносим (меня смущает конвертация из QString в std::wstring)?
Re[3]: проблема с std::ifstream::open
От: uzhas Ниоткуда  
Дата: 30.09.16 15:00
Оценка:
Здравствуйте, _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).


ну и open(wchar_t*) есть только на винде
Re[4]: проблема с std::ifstream::open
От: _hum_ Беларусь  
Дата: 30.09.16 15:21
Оценка:
Здравствуйте, 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
Re[5]: проблема с std::ifstream::open
От: uzhas Ниоткуда  
Дата: 30.09.16 16:05
Оценка: -1
Здравствуйте, _hum_, Вы писали:

__>ну, как бы это считается переносимостью (ибо для юниса придется компилировать для юникса)


в юниксах не используют wchar_t, используют char* в UTF-8 формате

__>в каком смысле "есть только на винде"? и, кстаи, что-то я в доках вообще не нахожу этой функции: cplusplus.com/ifstream::open


я же говорю, что есть только в visual studio. читай msdn
Re[3]: проблема с std::ifstream::open
От: _niko_ Россия  
Дата: 30.09.16 18:48
Оценка:
Здравствуйте, _hum_, Вы писали:

__>теперь переделал на

__>
__>QString qsFullFileName = QFileDialog::getOpenFileName(...);

__>if(!qsFullFileName.isEmpty())
__>        {
__>            //---
__>            std::ifstream ifs;

__>            ifs.open(qsFullFileName.toStdWString());
__>


__>заработало. но такой код вообще переносим (меня смущает конвертация из 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;
Отредактировано 30.09.2016 18:50 _niko_ . Предыдущая версия .
Re[6]: проблема с std::ifstream::open
От: _hum_ Беларусь  
Дата: 30.09.16 20:10
Оценка:
Здравствуйте, 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, чтобы функция сама уже там внутри конвертила к нужной файловой системе кодировке, не утруждая программиста заниматься этими техническими деталями
Re[4]: проблема с std::ifstream::open
От: _hum_ Беларусь  
Дата: 30.09.16 20:14
Оценка:
Здравствуйте, _niko_, Вы писали:

__>На 99% уверен что проблемы была в кодировке, ибо вот:


да. но остался вопрос — как все-таки правильно тогда работать, чтоб не зависеть от платформы (с точностью до перекомпиляции под нужную)?
Re[5]: проблема с std::ifstream::open
От: b0r3d0m  
Дата: 30.09.16 23:01
Оценка:
__>да. но остался вопрос — как все-таки правильно тогда работать, чтоб не зависеть от платформы (с точностью до перекомпиляции под нужную)?

Кросс-платформенного решения на этот счёт в стандартной библиотеке C++, к сожалению, не существует. Так что вы можете:
— Использовать какую-то стороннюю библиотеку
— Хранить пути до файлов в UTF8 (использовать при этом std::string) и в случае WinAPI конвертировать их в UTF-16 с последующим вызовом wchar_t-функций (CreateFileW / нестандартная перегрузка функции-члена std::ifstream::open). Больше по этому поводу тут.
Re: проблема с std::ifstream::open
От: b0r3d0m  
Дата: 30.09.16 23:32
Оценка: +1
И да, раз уж вы всё равно используете Qt, то почему бы не сохранить исходный файл в UTF8 и использовать что-то наподобие

QString filename(QString::fromUtf8("файл.txt"));
QFile file(filename);
if (file.open(QIODevice::ReadWrite))
{
    // ...
}
Re[2]: проблема с std::ifstream::open
От: _hum_ Беларусь  
Дата: 01.10.16 10:31
Оценка:
Здравствуйте, b0r3d0m, Вы писали:

B>И да, раз уж вы всё равно используете Qt, то почему бы не сохранить исходный файл в UTF8 и использовать что-то наподобие


B>
B>QString filename(QString::fromUtf8("файл.txt"));
B>QFile file(filename);
B>if (file.open(QIODevice::ReadWrite))
B>{
B>    // ...
B>}
B>

так проблема именно в том, что пути формирует qt-шный QFileDialog, а объект файла создает std::ifstream. и нужно каким-то образом согласовать их между собой (отказаться от std::ifstream я не могу, поскольку пользуюсь библиотекой сериализации cereal, в которой требуется именно он).
вот если бы было QFile::toStdIfstream(), то тогда все бы просто решалось


п.с. и как все-таки обстоит дело с "можно ли как-то узнать про причину (код ошибки)?" при работе с std::ifstream. судя по гуглу, создается впечатление, что с++ до сих пор ничего внятного на этот счет не может предложить.
Re[3]: проблема с std::ifstream::open
От: b0r3d0m  
Дата: 01.10.16 20:34
Оценка:
B>>И да, раз уж вы всё равно используете Qt, то почему бы не сохранить исходный файл в UTF8 и использовать что-то наподобие

B>>
B>>QString filename(QString::fromUtf8("файл.txt"));
B>>QFile file(filename);
B>>if (file.open(QIODevice::ReadWrite))
B>>{
B>>    // ...
B>>}
B>>

__>так проблема именно в том, что пути формирует qt-шный QFileDialog, а объект файла создает std::ifstream

И в чём конкретно проблема?
QString хранит строки в UTF16 (https://wiki.qt.io/QString). Берите и конвертируйте их в UTF8 для *nix-систем или передавайте как есть в CreateFileW / std::fstream::open в случае Windows.

__>п.с. и как все-таки обстоит дело с "можно ли как-то узнать про причину (код ошибки)?" при работе с std::ifstream. судя по гуглу, создается впечатление, что с++ до сих пор ничего внятного на этот счет не может предложить.


Либо устанавливай exception mask для std::fstream

std::ifstream f;
f.exceptions(std::ios_base::failbit | std::ios_base::badbit);
try
{
    f.open("some_file.txt");
}
catch (const std::exception& ex)
{
    std::cerr << ex.what() << std::endl;
}


, либо юзай std::strerror.

В последнем случае, правда, надо быть аккуратным:

21.5 Null-terminated sequence utilities [c.strings]

14 The functions strerror and strtok are not required to avoid data races (17.6.5.9).

Re[6]: проблема с std::ifstream::open
От: b0r3d0m  
Дата: 01.10.16 20:42
Оценка:
А за что, кстати, минусанули?
Re[4]: проблема с std::ifstream::open
От: _hum_ Беларусь  
Дата: 02.10.16 09:59
Оценка:
Здравствуйте, b0r3d0m, Вы писали:

B>>>И да, раз уж вы всё равно используете Qt, то почему бы не сохранить исходный файл в UTF8 и использовать что-то наподобие


B>>>
B>>>QString filename(QString::fromUtf8("файл.txt"));
B>>>QFile file(filename);
B>>>if (file.open(QIODevice::ReadWrite))
B>>>{
B>>>    // ...
B>>>}
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>
B>std::ifstream f;
B>f.exceptions(std::ios_base::failbit | std::ios_base::badbit);
B>try
B>{
B>    f.open("some_file.txt");
B>}
B>catch (const std::exception& ex)
B>{
B>    std::cerr << ex.what() << std::endl;
B>}
B>


B>, либо юзай std::strerror.


B>В последнем случае, правда, надо быть аккуратным:


B>

B>21.5 Null-terminated sequence utilities [c.strings]

B>14 The functions strerror and strtok are not required to avoid data races (17.6.5.9).



это не работает, см. stackoverflow.com: how-to-get-error-message-when-ifstream-open-fails
Re[5]: проблема с std::ifstream::open
От: b0r3d0m  
Дата: 02.10.16 10:12
Оценка:
__>в моем понимании, переносимость кода — это независимость от системы, под которую он будет компилироваться (то есть, без "если под 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 и может быть совершенно не информативным.
Re[6]: проблема с std::ifstream::open
От: _hum_ Беларусь  
Дата: 02.10.16 11:37
Оценка:
Здравствуйте, 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" считаете, что это рабочий вариант?
Re[7]: проблема с std::ifstream::open
От: b0r3d0m  
Дата: 02.10.16 13:02
Оценка:
__>>>в моем понимании, переносимость кода — это независимость от системы, под которую он будет компилироваться (то есть, без "если под 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++. Либо это, либо сторонние либы.
Re[8]: проблема с std::ifstream::open
От: _hum_ Беларусь  
Дата: 04.10.16 11:28
Оценка:
Здравствуйте, b0r3d0m, Вы писали:

B>Иначе средствами стандартной библиотеки сделать не получится.


B>Это единственный вариант с использованием только стандартной библиотеки C++. Либо это, либо сторонние либы.


попутно вопрос: это принципиально невозможно, или просто недоработка языка?
Re[9]: проблема с std::ifstream::open
От: uzhas Ниоткуда  
Дата: 04.10.16 11:39
Оценка:
Здравствуйте, _hum_, Вы писали:

__>попутно вопрос: это принципиально невозможно, или просто недоработка языка?


скорее, недоработка
немного инфы здесь: http://stackoverflow.com/questions/23393870/read-write-file-with-unicode-file-name-with-plain-c-boost
Re[10]: проблема с std::ifstream::open
От: _hum_ Беларусь  
Дата: 04.10.16 12:22
Оценка:
Здравствуйте, uzhas, Вы писали:

U>Здравствуйте, _hum_, Вы писали:


__>>попутно вопрос: это принципиально невозможно, или просто недоработка языка?


U>скорее, недоработка

U>немного инфы здесь: http://stackoverflow.com/questions/23393870/read-write-file-with-unicode-file-name-with-plain-c-boost

так а где там видно, что так можно (приницпиально)? по идее, для этого у системного апи должна быть функция, которая бы возвращала формат, в котором ос предполагает обращение к файлу. тогда бы c++ мог бы автоматом конвертить из unicod-а в нужный формат, без участия программиста. вот я и интересуюсь, такое вообще возможно? есть ли там какие стандарты на ос, требующие поддержку соответствующей функции?
Re[11]: проблема с std::ifstream::open
От: uzhas Ниоткуда  
Дата: 04.10.16 12:40
Оценка:
Здравствуйте, _hum_, Вы писали:

__>так а где там видно, что так можно (приницпиально)? по идее, для этого у системного апи должна быть функция, которая бы возвращала формат, в котором ос предполагает обращение к файлу. тогда бы c++ мог бы автоматом конвертить из unicod-а в нужный формат, без участия программиста. вот я и интересуюсь, такое вообще возможно? есть ли там какие стандарты на ос, требующие поддержку соответствующей функции?


неправильно вы рассуждаете
STL (а именно это и стандартизуется) пишут под платформу. у платформы есть документация, которая говорит, в какой кодировке должны путь файловые пути. STL удовлетворяет эти требования. не вижу принципиальных проблем, да и библиотеки, которые сразу на много платформ, уже показали, что в принципе это реализуемо. (см. буст, qt)
Re[12]: проблема с std::ifstream::open
От: _hum_ Беларусь  
Дата: 04.10.16 13:03
Оценка:
Здравствуйте, uzhas, Вы писали:

U>Здравствуйте, _hum_, Вы писали:


__>>так а где там видно, что так можно (приницпиально)? по идее, для этого у системного апи должна быть функция, которая бы возвращала формат, в котором ос предполагает обращение к файлу. тогда бы c++ мог бы автоматом конвертить из unicod-а в нужный формат, без участия программиста. вот я и интересуюсь, такое вообще возможно? есть ли там какие стандарты на ос, требующие поддержку соответствующей функции?


U>неправильно вы рассуждаете

U>STL (а именно это и стандартизуется) пишут под платформу. у платформы есть документация, которая говорит, в какой кодировке должны путь файловые пути.

ну да, при условии, что у всех платформ правила обращения к файлу по имени одинаковые (например, нет такого, что на какой-то платформе кодировкак зависит от того, в какой директории лежит файл)
Re[13]: проблема с std::ifstream::open
От: uzhas Ниоткуда  
Дата: 04.10.16 14:19
Оценка:
Здравствуйте, _hum_, Вы писали:

__>ну да, при условии, что у всех платформ правила обращения к файлу по имени одинаковые (например, нет такого, что на какой-то платформе кодировкак зависит от того, в какой директории лежит файл)


даже если бы и были такие правила, то опять же на уровне стандарта наверняка можно было бы все разрулить. стандартизируется абстракция, далее уже конкретная реализация использует системное API
на текущий момент проблем стандартного метода stream::open(char*) в том, что не зафиксировано, в какой же кодировке передается строка. каждая реализация STL по-своему интерпретирует переданный аргумент
Re[14]: проблема с std::ifstream::open
От: _hum_ Беларусь  
Дата: 04.10.16 14:56
Оценка:
Здравствуйте, uzhas, Вы писали:

U>Здравствуйте, _hum_, Вы писали:


__>>ну да, при условии, что у всех платформ правила обращения к файлу по имени одинаковые (например, нет такого, что на какой-то платформе кодировкак зависит от того, в какой директории лежит файл)


U>даже если бы и были такие правила, то опять же на уровне стандарта наверняка можно было бы все разрулить. стандартизируется абстракция, далее уже конкретная реализация использует системное API


в этом месте как раз может быть прокол — нужная абстракция (открытие файла по unicode) может не покрывать все случаи (например, если платформа вообще хранит файлы в разных форматах наименования так, как они были созданы), а потому ее придется расширять и делать самый общий вариант, как счас — открываю в том формате, что передали.
Re[15]: проблема с std::ifstream::open
От: uzhas Ниоткуда  
Дата: 04.10.16 14:59
Оценка:
Здравствуйте, _hum_, Вы писали:

__>придется расширять и делать самый общий вариант, как счас — открываю в том формате, что передали.


да, придется расширять
Re[16]: проблема с std::ifstream::open
От: _hum_ Беларусь  
Дата: 04.10.16 15:11
Оценка:
Здравствуйте, uzhas, Вы писали:

U>Здравствуйте, _hum_, Вы писали:


__>>придется расширять и делать самый общий вариант, как счас — открываю в том формате, что передали.


U>да, придется расширять


ну а значит, нельзя будет сужать существующий на данный момент вариант ( open(char* unknown_format_filename) ), о чем я и вел речь (что такое гипотетически возможно)
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.