2012-01-19 3 views
6

У меня есть. CSV-файл, который мои пользователи загружают, вводят некоторые данные и загружают на мой сайт.Загрузка 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 

Пример проблемы, я бегу в том, что, когда пользователь открывает файл, данные входы и сохраняет его, разделители изменяются от , к ;. Как я могу покрыть различные типы разделителей, чтобы документ мог быть сохранен из-за того, что он был открыт в разных программах, например, Excel в Excel, Excel в mac, открытый офис на Mac, открытый офис в Linux и т. Д.

Другой пример проблема в том, когда пользователь пытается скопировать и вставить данные в предоставленный шаблон, все ад разрывается.

UPDATE Я использую 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') 
+1

Если ваши пользователи используют инструмент для редактирования csv, тогда было бы легче придерживаться соглашений, используемых этим инструментом. – jcollado

+2

Просто убедитесь, что вы рассмотрели использование редактора табличных таблиц в виде облаков (например, Google Docs, например), чтобы позволить вашим пользователям делать свои изменения напрямую, вместо того, чтобы загружать, редактировать и загружать? –

+0

Нет, у меня нет, но это фантастическое предложение. – super9

ответ

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 ... 
1

Посмотрите на csv.Sniffer, которые могут помочь вам угадать, что CSV диалекте файл используется.

Как только у вас есть предположение от сниффера, попробуйте проанализировать файл на этом диалекте. Если есть какие-либо свойства данных, на которые вы можете положиться (например, определенное количество полей), примените их к каждой полученной записи как проверку работоспособности.

Вы также можете выполнить двухэтапный процесс загрузки. Сначала загрузите файл и обнюхивайте диалект. Затем покажите пользователю, что несколько строк данных выглядят вам после разбора, и дайте пользователю возможность переопределить некоторые настройки диалекта, если он ошибается. Затем обработайте csv после подтверждения. (Диалоговое окно «импорт» в Excel использует этот многоступенчатый метод.)

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() 
2

CSV - это неформат. Класс Sniffer не является надежным, потому что на самом деле это невозможно до 100% надежно обнаружить все данные диалекты.

Я думаю, вам понадобится использовать Sniffer в течение 90% времени, когда он работает, и захватить недопустимые входные файлы, проанализировать их и расширить Sniffer, чтобы поймать их.

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 &amp; 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> 
0

Рассматривали ли вы TAB отделенный файл вместо этого? Он легко читается и записывается всем программным обеспечением, которое вы упомянули, и дал мне намного меньше проблем, чем CSV.

Хотя, я предлагаю энтузиазм +1 за идею заставить пользователей редактировать файл в известном онлайн-редакторе. Google Docs, Zoho и т. Д. Предоставляют общие файлы и возможность экспортировать данные, что позволяет вам контролировать формат и упрощает анализ.

Если вы идете с TSV, обязательно очистите данные, просматривающие цитируемые строки между кавычками? Вы всегда можете использовать .strip ...

+0

вкладка разделена - это вид нет-нет; пробелы и вкладки приводят к разным головным болям. – GoingTharn

+0

Я получаю концепцию, но на практике для файлов, отредактированных с помощью программ типа «Excel», очень сложно поместить вкладку в поле, поскольку программа интерпретирует ее как команду для перехода к следующей ячейке. Для этого случая использования у меня был сильный успех с TSV. –

0

Честно говоря, если у них есть файлы с различными форматами, самым простым решением было бы дать им раскрывающееся меню, позволяющее им выбирать, какую программу они используют. Затем выполните процесс, специально предназначенный для этой программы.

Невозможно иметь один процесс, который может охватывать любые возможные варианты форматирования. Но, разбив его таким образом, вы можете добавить их по мере необходимости и упростить его обслуживание для себя.

2

Я полностью согласен с nfirvine (CSV IS NON FORMAT) - ладно, не так уж и сурово. Но это минимальный формат. Его очень рыхлый. Ожидайте, что ситуация будет часто ломаться, если вы используете CSV, так как кажется, что вы уже это испытываете.

Я также согласен с Mike Bynum - используйте что-то вроде XML.

Но я понимаю, что даже если есть лучший способ, часто существует прагматичный способ. Может быть, вы должны придерживаться своего формата, а также множество причин ... так: два маршрута.

Маршрут 1: CSV

Я сделал (делаю) этот маршрут в настоящее время. Мои пользователи ежедневно обновляют данные (пару тысяч записей). Учитывая частоту и количество обновленных записей, я действительно хочу, чтобы я прошел второй маршрут: при обработке значительного количества данных или обновлений надежная проверка данных - это огромная экономия времени.

указано. Когда вы застряли в CSV. Я предлагаю вам сделать следующее:

  • Предоставьте своим пользователям good/common definition of CSV, а именно RFC 4180. Убедитесь, что ваш клиент понимает, что вы ожидаете от их файла:
    • Линия заголовка.
    • Запятые как разделительные
    • Проценты, содержащие любые данные, содержащие запятые.
  • Наряду с этим определением дайте своим пользователям образец CSV (который звучит так, как вы, хорошо!). Объясните, что вы не можете обработать CSV-файл, который не соответствует определению ваших данных.
  • Убедитесь, что тип текстового файла - это то, что вы ожидаете от него до его импорта - см. convert to/from Unix/Windows.
  • В вашем парсере CSV вам необходимо принять fail fast methodology и убедиться, что у вас есть механизм для уведомления ваших пользователей, когда файл CSV не соответствует стандарту, который вы ожидаете. Предоставьте им как можно больше информации (укажите детали исключения ... если не для них, по крайней мере для вас).
  • Эта проблема, с которой вы сталкиваетесь с файлами одного клиента, предполагает, что вы можете дать своим клиентам какое-то направление, насколько вы редакторы знаете, работают правильно. Excel должен работать, или Open Office. Я предлагаю приложение электронной таблицы B/C они хорошая работа экспорта в CSV и заботиться о цитировании и т.д.

Не то, что вы не можете поддерживать некоторые Странности, но в целом - вы хотите, чтобы избежать этого, и вы хотите избежать случайного импорта плохо сформированных данных.

Маршрут 2: XML

Я хотел бы предложить вам сделать следующее:

  • Определить, что данные пользователи должны импортировать это с определением схемы (XSD). Мне нравится держать w3c definitions под рукой. Но есть good tutorials, чтобы помочь вам написать собственное определение XSD.

  • Дайте вашим пользователям образец XML-файла для заполнения и предложение для редактора. Есть greatcommercialones, и разумно free ones.

  • Вы можете прочитать XML-файлы своего пользователя и быть уверенным, что если он validates, тогда это будет полезно. Если на то пошло, ваши пользователи могут validate, прежде чем отправлять его вам.

+0

+1 Я думаю, что это решение хорошо в отрасли при настройке фида между компаниями. Однако я не думаю, что вы можете ожидать, что ваш пользователь (который, возможно, не разбирается в технологиях) будет иметь дело с форматами csv или спецификациями формата xml. Также я думаю, что вам нужно быть осторожным, конвертируя файлы из unix в windows и т. Д., Так как вы можете сохранить символы новой строки в кавычках. –

0

Инструменты, позволяющие просматривать или импортировать файлы CSV, сталкиваются с этой общей проблемой. Инструменты включают инструменты импорта баз данных, Excel, открытый офис и т. Д. Я знаю, что SOFA был сделан на python и позволяет импортировать csv.

Все эти инструменты имеют предварительный просмотр данных, чтобы пользователь мог убедиться, что он выглядит нормально. По крайней мере, если предварительный просмотр выглядит неправильно, они могут выбрать разделитель csv, который они хотят исправить. Инструмент, который они используют для создания файла csv, должен быть согласованным во всем, поэтому, если он выглядит нормально в предварительном просмотре, он, вероятно, будет в порядке для остальной части файла. APART из сложных, редких ситуаций, когда данные скрываются или заключены в кавычки.

Если файл не слишком большой, попробуйте создать набор всех символов, которые встречаются в файле (символы, которые не являются a-z или 0-9). Теперь убедитесь, что в вашем предварительном просмотре вы указываете строку для каждого из символов, которые происходят. Затем, если эта часть предварительного просмотра перепутана, пользователь может изменить кавычки. Это немного накладные, что делает хороший просмотрщик. Вы хотите убедиться, что предварительный просмотр показывает строки в порядке, чтобы ... представлять строки, которые вы целенаправленно пропустили.

Если предварительный просмотр невозможен, то может быть, бог с вами.

Смежные вопросы