我有一个.csv文件,我的用户必须下载,输入一些数据并上传到我的网站。
根据下面的代码段,是否有更好的方法可以确保数据成功上传?我还应该检查什么?使用方言会更好吗?
def import(resident_file):
try:
file = resident_file.file.path
reader = csv.reader(open(file, 'rU'), delimiter=',', quotechar='"')
headerline = reader.next()
for row in reader:
try:
# do stuff
except Exception, e:
print e
except Exception, e:
print e
我遇到的问题的一个示例是,当用户打开文件,输入数据并保存时,分隔符会从,
更改为;
。如何覆盖文档可以保存的各种类型的分隔符,因为它在不同的程序中打开,例如windows中的excel,mac中的excel,mac中的open office,linux中的open office等等。
问题的另一个例子是,当用户尝试将数据复制并粘贴到提供的模板中时,一切都会崩溃。
更新
我现在正在使用Sniffer
课程,如下面的一个答案所述,但它仍然不是万无一失的。
更新代码SNIPPET
def bulk_import_residents(condo, resident_file):
"""
COL 1 COL 2 COL 3 COL 4 COL 5
first_name last_name contact_number unit_number block_number
"""
file_path = resident_file.file.path
csvfile = open(file_path, 'rb')
dialect = csv.Sniffer().sniff(csvfile.read(1024))
csvfile.seek(0)
reader = csv.reader(csvfile, dialect)
headerline = reader.next()
for row in reader:
try:
data = ResidentImportData()
data.condo = condo
data.file = resident_file
data.first_name = row[0]
data.last_name = row[1]
data.contact_number = row[2]
data.unit_number = row[3]
data.block_number = row[4]
data.save()
except Exception, e:
print '{0}'.format(e)
raise Http404('Wrong template format')
答案 0 :(得分:2)
CSV是非格式化的。 Sniffer
类不是万无一失的,因为它实际上不可能 100%可靠地检测所有给定的方言。
我认为你必须在90%的时间内使用Sniffer
,并捕获无效的输入文件,分析它们,并扩展Sniffer
以捕获它们。
答案 1 :(得分:2)
我完全赞同nfirvine(CSV是一种非格式) - 好吧,不是那么苛刻。但它是一种最小格式。它很松散。如果您使用CSV,预计事情会经常中断,因为听起来您已经遇到过这种情况。
我也同意迈克拜纳姆 - 使用像XML这样的东西。
但我明白,即使有更好的方法,也常常采用务实的方式。也许你必须坚持你的格式过多的原因......所以:两条路线。
路线1:CSV
我现在已经(正在做)这条路线。我的用户每天更新数据(几千条记录)。鉴于更新的频率和记录数量,我真的希望我已经走了第二条路线:在处理大量数据或更新时,可靠的数据验证可以节省大量时间。
那就是说。当你遇到CSV时。我建议你做以下事情:
并不是说你不能支持一些奇怪的东西,但总的来说 - 你想避免它,并且你想避免意外地导入形成错误的数据。
路线2:XML
我建议你做以下事情:
使用架构定义(XSD)定义用户必须导入的数据。我想保留w3c definitions。但是good tutorials可以帮助您编写自己的XSD定义。
为您的用户提供要填写的示例XML文件,以及对编辑器的建议。有great commercial ones和合理的free ones。
您可以阅读用户的XML文件,并确保如果validates,那么它的好处就可以了。就此而言,您的用户可以在发送给您之前validate。
答案 2 :(得分:1)
啊刚刚找到了嗅探器类。
csvfile = open("example.csv", "rb")
dialect = csv.Sniffer().sniff(csvfile.read(1024))
csvfile.seek(0)
reader = csv.reader(csvfile, dialect)
# ... process CSV file contents here ...
答案 3 :(得分:1)
查看csv.Sniffer
,它可以帮助您猜出文件正在使用的csv方言。
一旦您从嗅探器中猜到,请尝试使用该方言解析文件。如果您可以依赖的数据属性(例如,一定数量的字段),则将它们应用于每个检索到的记录作为完整性检查。
您还可以进行两阶段上传过程。首先上传文件并嗅探方言。然后向用户显示解析后几行数据的样子,并为用户提供覆盖某些方言设置的选项,以防它出错。然后在确认后处理csv。 (Excel中的“导入”对话框使用此多阶段方法。)
答案 4 :(得分:0)
我建议使用这种方法检查所有出现n-1次的字符(n是你需要的列数)。它可以为您提供第一个可能的答案或检查所有文件。
from collections import Counter
def snif_sep(txt, nbcol, force_all=False):
pseps = None
for line in txt.split('\n'):
if line:
psep = [k for k,v in Counter(line).items() if v==nbcol-1]
if pseps is None:
pseps = set(psep)
else:
pseps.intersection_update(psep)
if len(pseps)==1 and not force_all:
return pseps.pop()
if len(pseps)==0:
return None
if len(pseps)==1:
return pseps.pop()
答案 5 :(得分:0)
您是否考虑过使用XML格式? Excel具有XML格式,可以更容易解析并在Excel中轻松打开。
您也可以使用自己的xml格式。
http://msdn.microsoft.com/en-us/library/aa140066(office.10).aspx
<?xml version="1.0"?>
<?mso-application progid="Excel.Sheet"?>
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet">
<Styles>
<Style ss:ID="sBold">
<Font ss:Bold="1"/>
</Style>
<Style ss:ID="sDate">
<NumberFormat ss:Format="General Date"/>
</Style>
</Styles>
<Worksheet ss:Name="2100Q is 2009-Nov-11_17_43_13 ">
<Table>
<Row>
<Cell ss:StyleID="sBold">
<Data ss:Type="String">Date & Time</Data>
</Cell>
<Cell ss:StyleID="sBold">
<Data ss:Type="String">Operator ID</Data>
</Cell>
<Cell ss:StyleID="sBold">
<Data ss:Type="String">Reading Mode</Data>
</Cell>
<Cell ss:StyleID="sBold">
<Data ss:Type="String">Sample ID</Data>
</Cell>
<Cell ss:StyleID="sBold">
<Data ss:Type="String">Sample Number</Data>
</Cell>
<Cell ss:StyleID="sBold">
<Data ss:Type="String">Result</Data>
</Cell>
<Cell ss:StyleID="sBold">
<Data ss:Type="String">Unit</Data>
</Cell>
<Cell ss:StyleID="sBold">
<Data ss:Type="String">Notice</Data>
</Cell>
<Cell ss:StyleID="sBold">
<Data ss:Type="String">Cal.Curve</Data>
</Cell>
<Cell ss:StyleID="sBold">
<Data ss:Type="String">Cal.Time</Data>
</Cell>
<Cell ss:StyleID="sBold">
<Data ss:Type="String">Cal.Status</Data>
</Cell>
<Cell ss:StyleID="sBold">
<Data ss:Type="String">Std. 1 Nom. Value</Data>
</Cell>
<Cell ss:StyleID="sBold">
<Data ss:Type="String">Std. 1 Act. Value</Data>
</Cell>
<Cell ss:StyleID="sBold">
<Data ss:Type="String">Std. 2 Nom. Value</Data>
</Cell>
<Cell ss:StyleID="sBold">
<Data ss:Type="String">Std. 2 Act. Value</Data>
</Cell>
<Cell ss:StyleID="sBold">
<Data ss:Type="String">Std. 3 Nom. Value</Data>
</Cell>
<Cell ss:StyleID="sBold">
<Data ss:Type="String">Std. 3 Act. Value</Data>
</Cell>
<Cell ss:StyleID="sBold">
<Data ss:Type="String">Std. 4 Nom. Value</Data>
</Cell>
<Cell ss:StyleID="sBold">
<Data ss:Type="String">Std. 4 Act. Value</Data>
</Cell>
</Row>
<Row>
<Cell ss:StyleID="sDate">
<Data ss:Type="DateTime">2009-11-10T11:23:30</Data>
</Cell>
<Cell>
<Data ss:Type="String">BARBARA</Data>
</Cell>
<Cell>
<Data ss:Type="String">Normal</Data>
</Cell>
<Cell>
<Data ss:Type="String">ABC-abc-1234</Data>
</Cell>
<Cell>
<Data ss:Type="Number">001</Data>
</Cell>
<Cell>
<Data ss:Type="Number">1.01</Data>
</Cell>
<Cell>
<Data ss:Type="String">FNU</Data>
</Cell>
<Cell>
<Data ss:Type="String"/>
</Cell>
<Cell>
<Data ss:Type="String">StablCal</Data>
</Cell>
<Cell ss:StyleID="sDate">
<Data ss:Type="DateTime">2009-11-10T10:22:06</Data>
</Cell>
<Cell>
<Data ss:Type="String">OK</Data>
</Cell>
</Row>
<Row>
<Cell ss:StyleID="sDate">
<Data ss:Type="DateTime">2009-11-10T10:24:15</Data>
</Cell>
<Cell>
<Data ss:Type="String"/>
</Cell>
<Cell>
<Data ss:Type="String">Cal.Verification</Data>
</Cell>
<Cell>
<Data ss:Type="String"/>
</Cell>
<Cell>
<Data ss:Type="String"/>
</Cell>
<Cell>
<Data ss:Type="Number">1.01</Data>
</Cell>
<Cell>
<Data ss:Type="String">FNU</Data>
</Cell>
<Cell>
<Data ss:Type="String">Verify Cal: Passed</Data>
</Cell>
<Cell>
<Data ss:Type="String">StablCal</Data>
</Cell>
<Cell ss:StyleID="sDate">
<Data ss:Type="DateTime">2009-11-10T10:22:06</Data>
</Cell>
<Cell>
<Data ss:Type="String">OK</Data>
</Cell>
</Row>
</Table>
</Worksheet>
</Workbook>
答案 6 :(得分:0)
您是否考虑过TAB分隔文件?您提到的所有软件都可以轻松读取和写入,并且比CSV给我的麻烦少得多。
尽管如此,我提供了一个热情的+1,让用户在一个已知的在线编辑器中编辑文件。 Google Docs,Zoho等提供共享文件和导出数据的功能 - 这使您可以负责格式并使其更容易解析。
如果您使用TSV,请确保清除数据以查找引号之间的引用字符串?你总是可以使用.strip ...
答案 7 :(得分:0)
老实说,如果他们有不同格式的文件,最简单的解决方案是给他们一个下拉菜单,让他们选择他们正在使用的程序。然后为该计划量身定制流程。
没有办法让一个进程能够覆盖任何和所有可能的格式化选项。但是通过这种方式将其分解,您可以根据需要添加它们,并为自己简化维护。
答案 8 :(得分:0)
允许您查看或导入CSV文件的工具必须面对这个常见问题。 工具包括数据库导入工具,Excel,开放式办公等。 我知道SOFA是在python中创建的,允许csv导入。
所有这些工具都有预览数据,以便用户可以确保它看起来不错。 至少如果预览看起来不对,他们可以选择他们想要纠正的csv分隔符。 他们用来创建csv文件的工具应该始终保持一致,所以如果它在预览中看起来没问题,那么对于文件的其余部分来说可能没问题。 APART来自棘手的罕见情况,其中数据被转义或用引号括起来。
如果文件不是太大,请尝试创建一组文件中出现的所有字符(不是a-z或0-9的字符)。现在确保在预览中包含每个出现的字符的行。然后,如果预览的这一部分搞砸了,用户可以更改引号。这是一个很好的预测器开销。您需要确保预览器按顺序显示行,以表示您故意错过的行。
如果无法预览,那么上帝可能会和你在一起。