使用通用换行符将Django上载文件处理为UTF-8

2024-10-06 11:19:05 发布

您现在位置:Python中文网/ 问答频道 /正文

在我的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. 不支持通用换行符(可能上载到此系统的大多数文件都需要这些换行符)。

使问题复杂化的是,我希望将文件传递到pythoncsv模块,该模块本机不支持Unicode。我很乐意接受避免这个问题的答案-一旦我让django和UTF-8玩得很好,我肯定我可以强迫他也这么做。(类似地,请忽略支持Excel的要求-我正在等待CSV工作,然后才开始分析Excel文件。)

我尝试过使用StringIOmmapcodec,以及访问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

请注意,我没有花太多的时间在实际的解析算法上,所以它可能是非常低效的,现在我更关心的是让编码按预期工作。

问题是,结果也没有被编码,尽管被包装在Unicodecodecs.EncodedFile文件包装器中。

编辑:事实证明,上述代码确实有效。codecs.EncodedFile(file,"utf-8")就是票。结果我认为它不起作用的原因是我使用的终端不支持UTF-8。活到老学到老!


Tags: 文件csvtoself编码excelutfreader
3条回答

对于CSV和Excel上传到django,this site可能会有帮助。

如上所述,我提供的代码片段实际上是按预期工作的——问题出在我的终端上,而不是python编码上。

如果您的视图需要访问UTF-8UploadedFile,您可以使用utf8_file = codecs.EncodedFile(request.FILES['file_field'],"utf-8")以正确的编码打开文件对象。

我还注意到,至少对于InMemoryUploadedFiles,通过codecs.EncodedFile包装器打开文件不会重置文件描述符的seek()位置。要返回到文件的开头(同样,这可能是特定于InMemoryUploadedFile),我只使用request.FILES['file_field'].open()seek()位置发送回0。

我使用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 )

相关问题 更多 >