<p>在我的django应用程序中,我提供了一个允许用户上传文件的表单。该文件可以采用多种格式(Excel、CSV),来自多种平台(Mac、Linux、Windows),并采用多种编码(ASCII、UTF-8)进行编码。</p>
<p>为了解决这个问题,假设我有一个接收<code>request.FILES['file']</code>的视图,它是<code>InMemoryUploadedFile</code>的一个实例,名为<code>file</code>。我的问题是<code>InMemoryUploadedFile</code>对象(比如<code>file</code>):</p>
<ol>
<li>不支持UTF-8编码(我在文件开头看到一个<code>\xef\xbb\xbf</code>,据我所知,这是一个标志,表示“这个文件是UTF-8”)。</li>
<li>不支持通用换行符(可能上载到此系统的大多数文件都需要这些换行符)。</li>
</ol>
<p>使问题复杂化的是,我希望将文件传递到python<code>csv</code>模块,该模块本机不支持Unicode。我很乐意接受避免这个问题的答案-一旦我让django和UTF-8玩得很好,我肯定我可以强迫他也这么做。(类似地,请忽略支持Excel的要求-我正在等待CSV工作,然后才开始分析Excel文件。)</p>
<p>我尝试过使用<code>StringIO</code>、<code>mmap</code>、<code>codec</code>,以及访问<code>InMemoryUploadedFile</code>对象中的数据的各种方法。每种方法都产生了不同的错误,迄今为止没有一种是完美的。这显示了一些我觉得最接近的代码:</p>
<pre><code>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
</code></pre>
<p>请注意,我没有花太多的时间在实际的解析算法上,所以它可能是非常低效的,现在我更关心的是让编码按预期工作。</p>
<p>问题是,结果也没有被编码,尽管被包装在Unicode<code>codecs.EncodedFile</code>文件包装器中。</p>
<p><strong>编辑:</strong>事实证明,上述代码确实有效。<code>codecs.EncodedFile(file,"utf-8")</code>就是票。结果我认为它不起作用的原因是我使用的终端不支持UTF-8。活到老学到老!</p>