Mit einem Django UploadedFile als UTF-8 mit universellen Newlines

In meiner django-Anwendung biete ich ein Formular an, das es Benutzern ermöglicht, eine Datei hochzuladen. Die Datei kann in einer Vielzahl von Formaten (Excel, CSV) sein, kommen aus einer Vielzahl von Plattformen (Mac, Linux, Windows) und werden in einer Vielzahl von Codierungen (ASCII, UTF-8) codiert.

Für die Zwecke dieser Frage, nehmen wir an, dass ich eine Ansicht habe, die request.FILES['file'] empfängt, die eine Instanz von InMemoryUploadedFile , die file . Mein Problem ist, dass InMemoryUploadedFile Objekte (wie file ):

  • Bestimmen Sie die Verschlüsselung von Text in Python
  • Wie kannst du Python in Vim benutzen?
  • Was könnte der Grund für einen Socket-Fehler sein "[Errno 9] Bad file deskriptor"
  • Python-Unterprozeß Wildcard-Nutzung
  • Wie kann man Klassennamen dynamisch setzen?
  • Python design patterns
    1. Unterstützen Sie nicht UTF-8-Codierung (ich sehe ein \xef\xbb\xbf am Anfang der Datei, was ich verstehe, ist ein Flag, das bedeutet, diese Datei ist UTF-8 ').
    2. Unterstützt nicht universelle Newlines (was wohl die Mehrheit der auf dieses System hochgeladenen Dateien benötigt).

    Das Problem zu komplizieren ist, dass ich die Datei in das python csv Modul übergeben möchte, was Unicode nicht nativ unterstützt. Ich werde gerne Antworten akzeptieren, die dieses Problem vermeiden – sobald ich Django nett mit UTF-8 bekomme, bin ich sicher, dass ich bludgeon csv in das gleiche tun kann. (Ebenso ignorieren Sie bitte die Anforderung, Excel zu unterstützen – ich warte, bis CSV arbeitet, bevor ich das Parsing von Excel-Dateien anpacke.)

    Ich habe versucht StringIO , mmap , codec und eine Vielzahl von Möglichkeiten des Zugriffs auf die Daten in einem InMemoryUploadedFile Objekt. Jeder Ansatz hat unterschiedliche Fehler ergeben, bisher war er nicht perfekt. Dies zeigt einige der Code, dass ich fühlte mich am nächsten kam:

     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 

    Bitte beachten Sie, dass ich nicht zu viel Zeit auf den tatsächlichen Parsing-Algorithmus verbracht habe, also kann es wild ineffizient sein, gerade jetzt bin ich mehr mit der Kodierung beschäftigt, um wie erwartet zu arbeiten.

    Das Problem ist, dass die Ergebnisse auch nicht codiert sind, obwohl sie in den Unicode- codecs.EncodedFile Datei-Wrapper eingehüllt sind.

    EDIT: Es stellt sich heraus, der oben genannte Code funktioniert in der Tat. codecs.EncodedFile(file,"utf-8") ist das Ticket. Es stellt sich heraus, den Grund, warum ich dachte, es funktionierte nicht, dass das Terminal, das ich verwendete, nicht UTF-8 unterstützt. Lebe und lerne

    Vielen Dank für jede Hilfe, und bitte lassen Sie mich wissen, wenn ich Ihnen weitere Informationen liefern kann.

    3 Solutions collect form web for “Mit einem Django UploadedFile als UTF-8 mit universellen Newlines”

    Wie oben erwähnt, war das Code-Snippet, das ich zur Verfügung stellte, in der Tat wie beabsichtigt – das Problem war mit meinem Terminal und nicht mit Python-Codierung.

    Wenn deine Ansicht auf eine UTF-8 utf8_file = codecs.EncodedFile(request.FILES['file_field'],"utf-8") du einfach utf8_file = codecs.EncodedFile(request.FILES['file_field'],"utf-8") , um ein utf8_file = codecs.EncodedFile(request.FILES['file_field'],"utf-8") in der korrekten Codierung zu öffnen.

    Ich habe auch bemerkt, dass zumindest für InMemoryUploadedFile s, öffnen Sie die Datei durch die codecs.EncodedFile Wrapper nicht zurücksetzen die seek() Position des Datei-Deskriptor. Um zum Anfang der Datei zurückzukehren (wieder kann dies InMemoryUploadedFile spezifisch sein) Ich habe gerade request.FILES['file_field'].open() , um die seek() Position zurück zu 0 zu senden.

    Ich benutze den csv.DictReader und es scheint gut zu funktionieren. Ich habe mein Code-Snippet beigefügt, aber es ist im Grunde das gleiche wie eine andere Antwort hier.

     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 ) 

    Für CSV und Excel Upload auf Django, kann diese Seite helfen.

    Python ist die beste Programmiersprache der Welt.