Обработка Django UploadedFile как UTF-8 с универсальными символами новой строки - PullRequest
12 голосов
/ 19 января 2011

В моем приложении django я предоставляю форму, которая позволяет пользователям загружать файл.Файл может быть в различных форматах (Excel, CSV), поступать с различных платформ (Mac, Linux, Windows) и кодироваться в различных кодировках (ASCII, UTF-8).

Для целей этого вопроса давайте предположим, что у меня есть представление, которое получает request.FILES['file'], который является экземпляром InMemoryUploadedFile, называемым file.Моя проблема в том, что InMemoryUploadedFile объекты (например, file):

  1. Не поддерживают кодировку UTF-8 (я вижу \xef\xbb\xbf в начале файла, что, как я понимаю,флаг, означающий «этот файл - UTF-8»).
  2. Не поддерживает универсальные символы новой строки (которые, вероятно, понадобятся большинству файлов, загружаемых в эту систему).

Сложнопроблема в том, что я хочу передать файл в модуль python csv, который изначально не поддерживает Unicode.Я с радостью приму ответы, которые помогут избежать этой проблемы - как только я получу джанго, играющий хорошо с UTF-8, я уверен, что смогу сделать то же самое.(Точно так же, пожалуйста, игнорируйте требование поддержки Excel - я жду, пока CSV заработает, прежде чем приступить к анализу файлов Excel.)

Я попытался использовать StringIO, mmap, codec и любой изширокий спектр способов доступа к данным в InMemoryUploadedFile объекте.Каждый подход привел к различным ошибкам, но ни одна из них не была идеальной.Это показывает некоторый код, который мне кажется наиболее близким:

import csv
import codecs

class CSVParser:
    def __init__(self,file):
        # 'file' is assumed to be an InMemoryUploadedFile object.
        dialect = csv.Sniffer().sniff(codecs.EncodedFile(file,"utf-8").read(1024))
        file.open() # seek to 0
        self.reader = csv.reader(codecs.EncodedFile(file,"utf-8"),
                                 dialect=dialect)
        try:
            self.field_names = self.reader.next()
        except StopIteration:
            # The file was empty - this is not allowed.
            raise ValueError('Unrecognized format (empty file)')

        if len(self.field_names) <= 1:
            # This probably isn't a CSV file at all.
            # Note that the csv module will (incorrectly) parse ALL files, even
            # binary data. This will catch most such files.
            raise ValueError('Unrecognized format (too few columns)')

        # Additional methods snipped, unrelated to issue

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

Проблема заключается в том, что результаты также не кодируются, несмотря на то, что они помещены в оболочку файла Unicode codecs.EncodedFile.

РЕДАКТИРОВАТЬ: Оказывается, приведенный выше код действительно работает.codecs.EncodedFile(file,"utf-8") это билет.Оказывается, причина, по которой я думал, что это не сработало, заключалась в том, что используемый мной терминал не поддерживает UTF-8.Живи и учись!

Ответы [ 3 ]

7 голосов
/ 19 января 2011

Как упомянуто выше, фрагмент кода, который я предоставил, фактически работал должным образом - проблема была с моим терминалом, а не с кодировкой python.

Если вашему представлению необходим доступ к UTF-8 UploadedFile, вы можете просто использовать utf8_file = codecs.EncodedFile(request.FILES['file_field'],"utf-8"), чтобы открыть объект файла в правильной кодировке.

Я также заметил, что, по крайней мере, на InMemoryUploadedFile с, открытие файла через оболочку codecs.EncodedFile НЕ сбрасываетсяseek() позиция дескриптора файла.Чтобы вернуться к началу файла (опять же, это может быть InMemoryUploadedFile специфично), я просто использовал request.FILES['file_field'].open(), чтобы отправить позицию seek() обратно в 0.

2 голосов
/ 27 февраля 2012

Я использую csv.DictReader, и он, кажется, работает хорошо. Я прикрепил свой фрагмент кода, но он в основном совпадает с другим ответом здесь.

import csv as csv_mod
import codecs

file = request.FILES['file']    
dialect = csv_mod.Sniffer().sniff(codecs.EncodedFile(file,"utf-8").read(1024))
file.open() 
csv = csv_mod.DictReader( codecs.EncodedFile(file,"utf-8"), dialect=dialect )
0 голосов
/ 19 января 2011

Для загрузки CSV и Excel в django, этот сайт может помочь.

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