Имена файлов Unicode в Windows с Python & subprocess.Popen ()

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

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

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

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

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

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

4 Solutions collect form web for “Имена файлов Unicode в Windows с Python & subprocess.Popen ()”

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

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

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

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

UPDATE 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/

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

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

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

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

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

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

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

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

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

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

Чтобы поддерживать командную строку unicode в Windows с помощью python 2.7, вы можете использовать этот патч для subprocess.Popen(..)

Ситуация

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

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

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

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

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

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

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

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

Как это исправлено

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

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

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

  • Копирование с использованием диалогового окна копирования Windows
  • Сценарии Python для глотания шейп-файла в базу PostgreSQL / PostGIS с использованием shp2pgsql.exe на окнах
  • Как запустить пакетный файл из сценария python и отсоединить его от него
  • Печать символов unicode в stdout в python печатает неправильные символы
  • Py2exe: Имеются ли файлы манифеста и w9xpopen.exe при компиляции веб-сервера без интерфейса GUI?
  • Как обновить python 2.7.8 до 2.7.9 в Anaconda без конфликта других компонентов в своей среде?
  • Можем ли мы узнать, запущен ли сценарий Python из Windows или текстового терминала?
  • Python - как читать дату «Созданная Media» (не дата создания файла)
  • Python - лучший язык программирования в мире.