Не удается открыть файл с символами Юникода в имени файла с помощью CLion

У меня возникли проблемы с открытием файла, в имени которого есть символы Юникода. Я создал файл на своем рабочем столе всего с парой строк текста.

c:\users\james\desktop\你好世界.txt

РЕДАКТИРОВАТЬ: я использую CLion. CLion передает параметры в юникоде.

Когда я помещаю эту строку в диалоговое окно запуска Windows, он находит файл и открывает его.

Однако интересно то, что я получаю двойное L'\\' L'\\' в имени папки из моего вызова CommandLineToArgvW:
L"c:\\\\users\\\\james\\\\desktop\\\\你好世界.txt"

Поэтому я написал небольшую процедуру для копирования имени файла в другой wchar_t * и удаления косых черт. Все еще не работает.

errno == 2 и f == NULL.

size_t filename_max_len = wcslen(filename);

//strip double slashes
wchar_t proper_filename[MAX_PATH + 1];

wchar_t previous = L'\0';
size_t proper_filename_location = 0;

for(int x = 0; x < filename_max_len; ++x)
{
    if(previous == L'\\' && filename[x] == L'\\')
        continue;

    previous = filename[x];
    proper_filename[proper_filename_location++] = filename[x];
}

proper_filename[proper_filename_location] = L'\0';

//Read in binary mode to prevent the C system from screwing with line endings
FILE *f = _wfopen(proper_filename, L"rb");

int le = errno;

if (f == NULL)
{
    perror(strerror(le));

    if(le == ERROR_FILE_NOT_FOUND)
    {
        return DUST_ERR_FILE_NOT_FOUND;
    }
    else {
        return DUST_ERR_COULD_NOT_OPEN_FILE;
    }
}

person Bluebaron    schedule 04.09.2015    source источник
comment
На самом деле errno == 2. Думаю, это означает, что файл не найден.   -  person Bluebaron    schedule 04.09.2015
comment
если errno не 0, то посмотрите, что говорит strerror()   -  person Jack    schedule 04.09.2015
comment
Ничего здесь не имеет смысла. Как вы думаете, что означают 4 обратных слэша? Почему 4?   -  person David Heffernan    schedule 04.09.2015
comment
Отладчики часто удваивают обратную косую черту, чтобы строки выглядели как строковые литералы C. Может быть, это то, что происходит? Но я не вижу здесь ничего плохого в вашем коде, поэтому покажите код, который создает «имя файла».   -  person Roddy    schedule 04.09.2015
comment
В Windows они игнорируются. c:\\\\\\\\\\\\\\\\\\\\\\\\\\bin такое же, как c:\bin   -  person Jack    schedule 04.09.2015
comment
также вам нужно +1 в malloc() для хранения L'\0'   -  person Jack    schedule 04.09.2015
comment
@ Джек Еще лучше, без malloc или бесплатно. wchar_t proper_filename[filename_max_len+1];   -  person Roddy    schedule 04.09.2015
comment
предполагая, что он использует C99, это лучше.   -  person Jack    schedule 04.09.2015
comment
Четыре обратных слэша — это два обратных слэша для escape-кода. Но их два комплекта. Поэтому я удалил второй набор обратных косых черт, указав просто \\.   -  person Bluebaron    schedule 04.09.2015
comment
К. Я реализовал все ваши предложения. Вывод strerror(le): Нет такого файла или каталога. Мне интересно, имеет ли это какое-то отношение к параметрам отладки CLion. Я думаю, что это может быть передача ввода как юникод или что-то в этом роде.   -  person Bluebaron    schedule 04.09.2015
comment
Вот байты, которые я получаю для части строки, отличной от ascii. 228, 189, 160, 229, 165, 189, 228, 184, 8211, 231, 8226, 338. У меня сложилось впечатление, что wchar_t имеет длину просто 16 бит. Таким образом, каждая запись должна представлять символ, и поэтому должно быть только 4 широких символа, а не 12. Пожалуйста, сообщите, если я ошибаюсь.   -  person Bluebaron    schedule 04.09.2015
comment
Пожалуйста, дважды проверьте мое редактирование. Сообщения на SO также используют '\' в качестве escape-символа и могут сделать редактирование неправильным.   -  person chux - Reinstate Monica    schedule 04.09.2015
comment
Прошу прощения, если перепутал пост.   -  person chux - Reinstate Monica    schedule 04.09.2015
comment
Как вы проверяете, сколько символов обратной косой черты есть? Как уже указывал @Roddy, некоторые отладчики (включая Visual Studio) отображают символы обратной косой черты как 2 последовательных символа обратной косой черты, чтобы имитировать синтаксис литерала символьной строки C. Откройте представление памяти и проверьте символы там.   -  person IInspectable    schedule 04.09.2015
comment
@chux Я знал об этом, и теперь косых черт в два раза больше, чем должно быть.   -  person Bluebaron    schedule 05.09.2015
comment
@IInspectable Если вы посмотрите на начало сообщения и некоторые комментарии: там два L'\\' L'\\'. Первая косая черта в каждом — управляющий символ.   -  person Bluebaron    schedule 05.09.2015
comment
Опять же, как вы определяете наличие лишних символов обратной косой черты? Если вы просматриваете строки символов в отладчике, таком как Visual Studio, символы обратной косой черты отображаются как двойные символы обратной косой черты. Это не истинное содержимое строки. Откройте вид памяти и посмотрите на содержимое там. Это Настоящая Вещь™.   -  person IInspectable    schedule 05.09.2015
comment
@IInspectable Опять же, ДА, это экранирующие косые черты. Вы читаете хоть один мой комментарий, прежде чем комментировать?   -  person Bluebaron    schedule 06.09.2015
comment
Использование ' указывает на символ, а не на строку. Таким образом, L'\\' может быть только экранированным \. Я также сказал, что они были экранированы косой чертой дважды выше, и в исходном вопросе я также поставил L'\\'.   -  person Bluebaron    schedule 06.09.2015
comment
Я получаю двойные L'\\' L'\\' в имени папки при вызове CommandLineToArgvW Как вы определили, что это действительно двойные символы обратной косой черты? Когда вы просматриваете содержимое строки в окне Autos или Locals в Visual Studio, строковые литералы отображаются с дополнительными символами обратной косой черты. Там нет этих персонажей. Вместо этого просмотрите содержимое в окне Память.   -  person IInspectable    schedule 06.09.2015
comment
Как они могли не быть экранированными символами? L'ab' недействителен, потому что ' означает символ, поэтому L'\\' должен означать экранированный символ.   -  person Bluebaron    schedule 06.09.2015
comment
Точно так же, как L'\0' или L'\n'... теперь, если бы я сказал L\\, я бы увидел, что у вас проблемы с пониманием этого.   -  person Bluebaron    schedule 06.09.2015
comment
Вы не конструируете строку из символьных литералов. Это результат вызова CommandLineToArgvW. Строковые или символьные литералы не задействованы, поэтому возникает вопрос, как определить наличие дополнительных символов обратной косой черты. Почему вы постоянно уходите от ответа на этот, казалось бы, простой вопрос? Причина этого вопроса уже неоднократно упоминалась.   -  person IInspectable    schedule 07.09.2015
comment
Два способа, один из которых я уже упоминал выше if(previous == L'\\' && filename[x] == L'\\') и ручной проверкой через отладчик CLion где я вижу L'\\' L'\\'. Я не знаю, почему вы думаете, что я недостаточно умен, чтобы понять разницу между L'\\' и L\\\\ или почему вы не можете понять, когда я говорю L'\\', я имею в виду сбежавшее\ . Кажется, никто больше не считает меня глупым. Я имею в виду ... Я знаю мало людей, которые после программирования почти на любом языке более двух дней были бы смущены тем, что такое экранированный символ, но, видимо, я нашел его.   -  person Bluebaron    schedule 08.09.2015
comment
Не говоря уже о том, что мы так далеки от темы. Кто-то еще упомянул выше, что это не может иметь ничего общего с более чем одной косой чертой, потому что косые черты пути к файлу Windows являются идемпотентными, а ответ уже опубликован.   -  person Bluebaron    schedule 08.09.2015


Ответы (2)


Я понял проблему. Моя догадка была верна. CLion, похоже, предоставляет Unicode в качестве входных данных для программы. Используя диалоговое окно запуска Windows и передав его в качестве параметра моей программе, я смог без проблем открыть и обработать файл.

person Bluebaron    schedule 04.09.2015
comment
Я отправил сообщение об ошибке в CLion, и они приняли и назначили проблему. youtrack.jetbrains.com/issue/IDEA-144864 - person Bluebaron; 07.09.2015

Мое первое предположение состоит в том, что 228, 189, 160 представляет собой первый символ вашего имени файла, закодированного как последовательность байтов UTF-8, поскольку мне она кажется такой последовательностью. E4 BD A0 (228, 189, 160) декодируется как U+4F60, что действительно является кодовой точкой Unicode, соответствующей первому символу.

Я изменил раздел вывода main в примере программы здесь, чтобы напечатать каждый аргумент в виде последовательности байтов в шестнадцатеричном коде. Я скопировал и вставил ваш путь в качестве аргумента в программу, а символы Han закодированы в UTF-8 как:

E4 BD A0
E5 A5 BD
E4 B8 96
E7 95 8C

В вашем комментарии упоминаются немного другие номера (в частности, 8211/U+2013, 8226/U+2022 и 338/U+0152). Глядя на кодовые страницы Windows 1250 и Windows 1252, байты 0x96, 0x95 и 0x8C в обеих кодовых страницах точно соответствуют U+2013, U+2022 и U+0152 соответственно. Я предполагаю, что ваша исходная программа где-то ошибается, когда сталкивается с вводом Unicode (вы используете GetCommandLineW и передаете его CommandLineToArgvW, верно?)

Вот скриншот моего вывода, который я отредактировал, чтобы выделить соответствующие последовательности символов (глифы ¥ предназначены для \ глифов, но я использую кодовая страница 932 для cmd.exe):

вывод программы с выделенными байтами UTF-8

person Community    schedule 05.09.2015
comment
Ага. Я узнал, что параметры отладки CLion выполняются в юникоде. - person Bluebaron; 06.09.2015