2015-02-05 3 views
1

Я пытаюсь открыть файл Excel (.xls) с помощью xlrd. Это резюме коды я использую:Ошибка кодирования при открытии файла Excel с помощью xlrd

import xlrd 
workbook = xlrd.open_workbook('thefile.xls') 

Это работает для большинства файлов, но не для файлов, которые я получаю от конкретной организации. Ошибка, которую я получаю, когда я пытаюсь открыть файлы Excel из этой организации.

Traceback (most recent call last): 
    File "<console>", line 1, in <module> 
    File "/app/.heroku/python/lib/python2.7/site-packages/xlrd/__init__.py", line 435, in open_workbook 
    ragged_rows=ragged_rows, 
    File "/app/.heroku/python/lib/python2.7/site-packages/xlrd/book.py", line 116, in open_workbook_xls 
    bk.parse_globals() 
    File "/app/.heroku/python/lib/python2.7/site-packages/xlrd/book.py", line 1180, in parse_globals 
    self.handle_writeaccess(data) 
    File "/app/.heroku/python/lib/python2.7/site-packages/xlrd/book.py", line 1145, in handle_writeaccess 
    strg = unpack_unicode(data, 0, lenlen=2) 
    File "/app/.heroku/python/lib/python2.7/site-packages/xlrd/biffh.py", line 303, in unpack_unicode 
    strg = unicode(rawstrg, 'utf_16_le') 
    File "/app/.heroku/python/lib/python2.7/encodings/utf_16_le.py", line 16, in decode 
    return codecs.utf_16_le_decode(input, errors, True) 
UnicodeDecodeError: 'utf16' codec can't decode byte 0x40 in position 104: truncated data 

Это выглядит так, как будто xlrd пытается открыть файл Excel, закодированной в нечто иное, чем UTF-16. Как я могу избежать этой ошибки? Является ли файл написанным некорректным способом или существует только конкретный символ, который вызывает проблему? Если я открою и заново сохраню файл Excel, xlrd откроет файл без проблем.

Я попытался открыть книгу с другими ограничениями кодирования, но это тоже не сработает.

Файл Я пытаюсь открыть доступен здесь: сообщил здесь

https://dl.dropboxusercontent.com/u/6779408/Stackoverflow/AEPUsageHistoryDetail_RequestID_00183816.xls

Издание: https://github.com/python-excel/xlrd/issues/128

ответ

10

Что они используют для создания этого файла?

Они используют некоторый Java Excel API (см. Ниже, link here), возможно, на мэйнфрейме IBM или аналогичном.

Из трассировки стека информация о записи не может декодировать в Юникод, потому что символ @.

Для получения дополнительной информации о информации о записи в файле формата XLS см. 5.112 WRITEACCESS или Page 277.

Это поле содержит имя пользователя, который сохранил файл.

import xlrd 
dump = xlrd.dump('thefile.xls') 

Запуск xlrd.dump на исходном файле дает

36: 005c WRITEACCESS len = 0070 (112) 
    40:  d1 81 a5 81 40 c5 a7 83 85 93 40 c1 d7 c9 40 40 [email protected][email protected][email protected]@ 
    56:  40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 @@@@@@@@@@@@@@@@ 
    72:  40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 @@@@@@@@@@@@@@@@ 
    88:  40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 @@@@@@@@@@@@@@@@ 
    104:  40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 @@@@@@@@@@@@@@@@ 
    120:  40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 @@@@@@@@@@@@@@@@ 
    136:  40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 @@@@@@@@@@@@@@@@ 

После resaving его с Excel или в моем случае LibreOffice Calc информацию доступа записи переписывается с чем-то вроде

36: 005c WRITEACCESS len = 0070 (112) 
40:  04 00 00 43 61 6c 63 20 20 20 20 20 20 20 20 20 ?~~Calc   
56:  20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20     
72:  20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20     
88:  20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20     
104:  20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20     
120:  20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20     
136:  20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 

На основании пробелов, кодируемых как 40, я считаю, что кодирование является EBCDIC, и когда мы конвертируем d1 81 a5 81 40 c5 a7 83 85 93 40 c1 d7 c9 40 40 в EBCDIC, получаем Java Excel API.

Таким образом, файл записывается некорректным образом в случае BIFF8, ​​и выше он должен быть строкой в ​​виде юникода, а в BIFF3 - BIFF5, он должен быть байтовой строкой в ​​кодировке в информации CODEPAGE, которая является

152: 0042 CODEPAGE len = 0002 (2) 
156:  12 52           ?R 

1252 является Windows, CP-1252 (Latin I) (BIFF4-BIFF5), который не является EBCDIC_037.

Тот факт, что xlrd попытался использовать unicode, означает, что он определил версию файла как BIFF8.

В этом случае у вас есть два варианта

  1. Закрепить файл перед его открытием с xlrd. Вы можете проверить использование дампа в файле, который не является стандартным, а затем, если это так, вы можете перезаписать информацию о записи через xlutils.save или другую библиотеку.

  2. Патч xlrd для обработки вашего частного случая, в handle_writeaccess, добавляя блок try и установив strg в пустую строку при ошибке unpack_unicode.

Следующий фрагмент кода

def handle_writeaccess(self, data): 
     DEBUG = 0 
     if self.biff_version < 80: 
      if not self.encoding: 
       self.raw_user_name = True 
       self.user_name = data 
       return 
      strg = unpack_string(data, 0, self.encoding, lenlen=1) 
     else: 
      try: 
       strg = unpack_unicode(data, 0, lenlen=2) 
      except: 
       strg = "" 
     if DEBUG: fprintf(self.logfile, "WRITEACCESS: %d bytes; raw=%s %r\n", len(data), self.raw_user_name, strg) 
     strg = strg.rstrip() 
     self.user_name = strg 

с

workbook=xlrd.open_workbook('thefile.xls',encoding_override="cp1252") 

Кажется, чтобы открыть файл успешно.

Без кодирования переопределения он жалуется ERROR *** codepage 21010 -> encoding 'unknown_codepage_21010' -> LookupError: unknown encoding: unknown_codepage_21010

+0

Я не уверен, что использует организация для записи файла Excel, хотя у меня есть вопрос к ним по этому вопросу. Я попробую ваш второй вариант, поскольку вы говорите, что он сработал для вас и опубликовал мои результаты. Я надеюсь, спасибо за отличный ответ. – Erik

+0

Это отлично работало. Спасибо. – Erik

+0

Я не могу наградить щедрот еще 15 часов - но тогда я это сделаю. Еще раз спасибо. – Erik

Смежные вопросы