Unicode имена файлов в Windows с Python & subprocess.Popen () - PullRequest
12 голосов
/ 15 декабря 2009

Почему происходит следующее:

>>> u'\u0308'.encode('mbcs')   #UMLAUT
'\xa8'
>>> u'\u041A'.encode('mbcs')   #CYRILLIC CAPITAL LETTER KA
'?'
>>>

У меня есть приложение Python, принимающее имена файлов из операционной системы. Это работает для некоторых международных пользователей, но не для других.

Например, это имя файла Unicode: и '\ u041a \ u0433 \ u044b \ u044b \ u0448 \ u0444 \ u0442'

не будет кодироваться с помощью кодировки Windows 'mbcs' (используемой файловой системой, возвращаемой sys.getfilesystemencoding ()). Я получаю «???????», указывая, что кодировщик не работает на этих символах. Но это не имеет смысла, так как имя файла пришло от пользователя.

Обновление: вот фон для моих причин этого ... В моей системе есть файл с именем на кириллице. Я хочу вызвать subprocess.Popen () с этим файлом в качестве аргумента. Попен не будет обрабатывать Unicode. Обычно я могу избежать кодирования аргумента с помощью кодека, заданного sys.getfilesystemencoding (). В этом случае это не будет работать

Ответы [ 5 ]

8 голосов
/ 02 февраля 2012

В Py3K - по крайней мере из Python 3.2 - subprocess.Popen и sys.argv работают согласованно со строками (по умолчанию Unicode) в Windows. CreateProcessW и GetCommandLineW используются очевидно.

В Python - по крайней мере до v2.7.2 - subprocess.Popen глючит с аргументами Юникода. Он придерживается CreateProcessA (в то время как os.* соответствует Unicode). И shlex.split создает дополнительную ерунду.

Pywin32 win32process.CreateProcess также не выполняет автоматического переключения на версию W, а также win32process.CreateProcessW. То же самое с GetCommandLine. Таким образом, ctypes.windll.kernel32.CreateProcessW... необходимо использовать. Модуль подпроцесса, возможно, должен быть исправлен относительно этой проблемы.

UTF8 на argv[1:] с частными приложениями остается неуклюжим на Unicode OS. Такие приемы могут быть допустимы для 8-разрядных строковых ОС «Latin1», таких как Linux.

ОБНОВЛЕНИЕ vaab создал исправленную версию Popen для Python 2.7, которая устраняет проблему.
См https://gist.github.com/vaab/2ad7051fc193167f15f85ef573e54eb9
Сообщение в блоге с объяснениями: http://vaab.blog.kal.fr/2017/03/16/fixing-windows-python-2-7-unicode-issue-with-subprocesss-popen/

5 голосов
/ 31 мая 2017

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: Я являюсь автором исправления, упомянутого в следующем.

Для поддержки командной строки Unicode в Windows с Python 2.7, вы можете использовать этот патч до subprocess.Popen(..)

Ситуация

Поддержка Python 2 командной строки Unicode в Windows очень плохая.

Серьезно прослушивается:

  • выдача командной строки Unicode в систему со стороны вызывающего абонента (через subprocess.Popen(..)),

  • и чтение текущих аргументов Unicode командной строки со стороны вызываемого абонента (через sys.argv),

Это подтверждено и не будет исправлено на Python 2. Они исправлены в Python 3.

Технические причины

В Python 2 реализация Windows subprocess.Popen(..) и sys.argv использует системный вызов Windows, не поддерживающий Юникод, CreateProcess(..) (см. Python code и MSDN документ CreateProcess ) и не использует GetCommandLineW(..) для sys.argv.

В Python 3 реализация Windows subprocess.Popen(..) использует правильные системные вызовы Windows CreateProcessW(..) начиная с 3.0 (см. код в 3.0) и sys.argv использует GetCommandLineW(..) начиная с 3.3 (см. код в 3.3).

Как это исправить

Данный патч будет использовать ctypes модуль для вызова C windows система CreateProcessW(..) напрямую. Он предлагает новый фиксированный Popen объект путем переопределения закрытого метода Popen._execute_child(..) и закрытой функции _subprocess.CreateProcess(..) для настройки и использования CreateProcessW(..) из lib системы Windows таким образом, который максимально имитирует, как это делается в Python * 1075. *.

Как его использовать

Как использовать данный патч демонстрируется с этим объяснением в блоге . Это дополнительно показывает, как читать текущие процессы sys.argv с другим исправлением .

3 голосов
/ 16 декабря 2009

Документы для sys.getfilesystemencoding () говорят, что для Windows NT и более поздних версий имена файлов изначально являются Unicode. Если у вас есть допустимое имя файла Unicode, зачем вам его кодировать с помощью mbcs?

Документы для модуля кодеков говорят, что mbcs кодирует с использованием "кодовой страницы ANSI" (которая будет отличаться в зависимости от локали пользователя), поэтому, если в локали не используются символы кириллицы, знак сплат.

Edit: ваш процесс вызывает subprocess.Popen (). Если ваш вызванный процесс находится под вашим контролем, эти два процесса смогут договориться об использовании UTF-8 в качестве транспортного формата Unicode. В противном случае вам может потребоваться обратиться к списку рассылки pywin32. В любом случае отредактируйте свой вопрос, указав степень контроля над запущенным процессом.

2 голосов
/ 29 декабря 2009

Если вам нужно передать имя существующего файла, у вас может быть больше шансов на успех, передав версию 8.3 имени файла Unicode.

Вам нужно установить пакет pywin32 , тогда вы можете сделать:

>>> import win32api
>>> win32api.GetShortPathName(u"C:\\Program Files")
'C:\\PROGRA~1'

Я считаю, что в этих коротких именах файлов используются только символы ASCII, и поэтому вы должны иметь возможность использовать их в качестве аргументов командной строки.

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

ОБНОВЛЕНИЕ: пользователь bogdan правильно говорит, что 8.3 генерация имени файла может быть отключена (у меня это тоже было отключено, когда у меня на ноутбуке была Windows XP), поэтому вы не можете на них положиться Таким образом, в качестве другого более надуманного подхода при работе с томами NTFS можно жестко связать имена файлов Unicode с простыми ASCII-файлами; передать имена файлов ASCII внешней команде и затем удалить их.

0 голосов
/ 08 октября 2018

В Python 3 просто не кодируйте строку. Имена файлов Windows изначально являются Unicode, а все строки в Python 3 - Unicode, а Popen использует Unicode-версию CreateProcess функции Windows API.

В Python 2.7 самое простое решение - использовать сторонний модуль https://pypi.org/project/subprocessww/. Не существует «встроенного» решения для получения полной поддержки Unicode (независимо от языкового стандарта системы) и сопровождающих Python. 2.7. Считайте, что это запрос функции, а не исправление, так что это не изменится.

Подробное техническое объяснение того, почему вещи такие, какие они есть, см. В других ответах.

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