функция stat: нет такой ошибки файла или каталога

Когда моя программа пытается stat() файл, содержащий определенные символы UTF-8, функция stat() возвращает ошибку. Например, я могу открыть файл /tmp/surgateDlpMgQure/Özkul Gazete с помощью vi, но при передаче этого же файла в stat() возникает ошибка. Настройки локали системы:

ЯЗЫК=en_US.UTF-8

LC_CTYPE=en_US.UTF-8

LC_COLLATE=С

LC_TIME=en_US.UTF-8

LC_NUMERIC=en_US.UTF-8

LC_MONETARY=en_US.UTF-8

LC_MESSAGES=en_US.UTF-8

ЛК_ВСЕ=

Должен ли я что-то сделать, чтобы stat() понимал символы UTF-8?

Вот код:

int main ()
{
    struct stat s;
    if (stat("/tmp/surgateDlpMgQure/Özkul Gazete", &s) == -1)
            perror("stat");


    switch (s.st_mode & S_IFMT) {
            case S_IFBLK:  printf("block device\n");            break;
            case S_IFCHR:  printf("character device\n");        break;
            case S_IFDIR:  printf("directory\n");               break;
            case S_IFIFO:  printf("FIFO/pipe\n");               break;
            case S_IFLNK:  printf("symlink\n");                 break;
            case S_IFREG:  printf("regular file\n");            break;
            case S_IFSOCK: printf("socket\n");                  break;
            default:       printf("unknown?\n");                break;
    }

 return 0;
}

person iyasar    schedule 08.08.2012    source источник
comment
можете ли вы опубликовать код ... чтобы мы могли знать, как вы используете stat ()?   -  person Jeegar Patel    schedule 08.08.2012


Ответы (3)


Проблема, вероятно, в том, что кодировка имени файла не совпадает с кодировкой, которую вы используете внутри своей программы. Ключевые вопросы здесь заключаются в том, кто создал файл (и дал ему такое имя) и откуда берется строка в вашем коде. Большая часть Unix не зависит от кодировки, пока несколько специальных символов, таких как '/', имеют ожидаемую кодировку. Таким образом, независимо от вашей текущей локали, имя файла может быть на латинице-1, латинице-5 (только предположение, но имя выглядит турецким) или UTF-8. В Unix это практически не имеет значения, но вы должны убедиться, что в вашей программе используется та же кодировка, которая использовалась для создания файла, иначе имена не будут совпадать. (На практике я обнаружил, что простейшей политикой является ограничение символов в имени файла очень небольшим набором: буквенно-цифровые символы ASCII, цифры, '_' и, возможно, '-'.)

Если вы не уверены в фактической кодировке имени файла на диске, вы можете использовать ls | od -t x1 -tc, чтобы узнать фактическое значение байтов в нем. Если ваш Ö равен 0xD6, то кодировка либо Latin-1, либо Latin-5 (и, вероятно, не будет иметь большого значения, какая именно), и вам нужно убедиться, что имя файла, которое вы передаете, stat (или open, или любое другое). другие функции, которые принимают имя файла) закодирован в одной из этих кодировок. Если вместо этого у вас есть двухбайтовая последовательность 0xC3, 0x96, то имя файла будет UTF-8.

Если вы хотите поддерживать символы за пределами подмножества ASCII, я настоятельно рекомендую убедиться, что все имена файлов закодированы в UTF-8. Предположим, что вы можете, кодировка будет определена программой, создающей файл, и если это не ваша программа (или если вы получаете файл из другой системы), вы не сможете ничего с этим поделать. В худшем случае вам, возможно, даже придется использовать opendir и readdir с каким-то алгоритмом сопоставления, чтобы найти фактическое имя файла (в любой кодировке) и использовать его.

person James Kanze    schedule 08.08.2012

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

вы можете попробовать изменить это имя файла без пробела

Özkul Gazete  -> Özkul_Gazete

В Linux обычно я не использую пробел в имени файла или имени каталога.

person Jeegar Patel    schedule 08.08.2012

простой способ взломать его:

используйте экранированное представление этого символа Юникода:

"/tmp/surgateDlpMgQure/\x00\xF6zkul Gazete"

Я не проверял, но должно работать. Хотя это не способ работать со строками Unicode в C.

как ни странно, ваш код работает в моей системе, но не в моей :)

person zmo    schedule 08.08.2012
comment
Это не может работать со строкой, которую вы даете, поскольку \00 является нулевым символом, который будет рассматриваться как конец строки stat. - person James Kanze; 08.08.2012