在我的django应用程序中,我提供了一个允许用户上传文件的表单。该文件可以采用多种格式(Excel、CSV),来自多种平台(Mac、Linux、Windows),并采用多种编码(ASCII、UTF-8)进行编码。
为了解决这个问题,假设我有一个接收request.FILES['file']
的视图,它是InMemoryUploadedFile
的一个实例,名为file
。我的问题是InMemoryUploadedFile
对象(比如file
):
\xef\xbb\xbf
,据我所知,这是一个标志,表示“这个文件是UTF-8”)。使问题复杂化的是,我希望将文件传递到pythoncsv
模块,该模块本机不支持Unicode。我很乐意接受避免这个问题的答案-一旦我让django和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
请注意,我没有花太多的时间在实际的解析算法上,所以它可能是非常低效的,现在我更关心的是让编码按预期工作。
问题是,结果也没有被编码,尽管被包装在Unicodecodecs.EncodedFile
文件包装器中。
编辑:事实证明,上述代码确实有效。codecs.EncodedFile(file,"utf-8")
就是票。结果我认为它不起作用的原因是我使用的终端不支持UTF-8。活到老学到老!
对于CSV和Excel上传到django,this site可能会有帮助。
如上所述,我提供的代码片段实际上是按预期工作的——问题出在我的终端上,而不是python编码上。
如果您的视图需要访问UTF-8
UploadedFile
,您可以使用utf8_file = codecs.EncodedFile(request.FILES['file_field'],"utf-8")
以正确的编码打开文件对象。我还注意到,至少对于
InMemoryUploadedFile
s,通过codecs.EncodedFile
包装器打开文件不会重置文件描述符的seek()
位置。要返回到文件的开头(同样,这可能是特定于InMemoryUploadedFile
),我只使用request.FILES['file_field'].open()
将seek()
位置发送回0。我使用csv.DictReader,它看起来运行良好。我附上了我的代码片段,但它基本上与这里的另一个答案相同。
相关问题 更多 >
编程相关推荐