Подтвердить что ты не робот

Обработка Django UploadedFile как UTF-8 с универсальными символами новой строки

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

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

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

Усложнение проблемы заключается в том, что я хочу передать файл в модуль python csv, который не поддерживает Unicode. Я с радостью соглашусь с ответами, которые избегают этой проблемы - как только я получу django, играю хорошо с UTF-8, я уверен, что смогу сделать дубль csv в то же самое. (Аналогично, пожалуйста, проигнорируйте требование поддержки 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.

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

4b9b3361

Ответ 1

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

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

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

Ответ 2

Я использую 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 )

Ответ 3

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