2016-12-27 5 views
0

Это моя функция для создания записи о выполненном пользователем действии в cythv python. Он получит имя пользователя из глобального и выполнит приращение, заданное в параметре amount, в конкретное местоположение csv, соответствующее строке пользователя и текущей дате.Что такое безопасный способ обновления Python CSV

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

Каждый первый элемент в строках является именем пользователя, а заголовок имеет даты.

Accs\Dates,12/25/2016,12/26/2016,12/27/2016 
user1,217,338,653 
user2,261,0,34 
user3,0,140,455 

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

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

Я думаю, что, возможно, я могу написать статистику отдельно и уникально для каждого пользователя и объединить позже, отсюда исключение возможного столкновения в письменной форме. Хотя было бы здорово, если бы я мог просто улучшить то, что у меня есть, и читать/писать все в файле.

Любой надежный способ сделать то, что я пытаюсь сделать здесь?

# Search current user in first rows and updating the count on the column (today's date) 
# 'amount' will be added to the respective position 
def dailyStats(self, amount, code = None): 
    def initStats(): 
     # prepping table 
     with open(self.stats, 'r') as f: 
      reader = csv.reader(f) 
      for row in reader: 
       if row: 
        self.statsTable.append(row) 
        self.statsNames.append(row[0]) 

    def getIndex(list, match): 
     # get the index of the matched date or user 
     for i, j in enumerate(list): 
      if j == match: 
       return i 

    self.statsTable = [] 
    self.statsNames = [] 
    self.statsDates = None 

    initStats() 
    today = datetime.datetime.now().strftime('%m/%d/%Y') 
    user_index = None 
    today_index = None 

    # append header if the csv is empty 
    if len(self.statsTable) == 0: 
     self.statsTable.append([r'Accs\Dates']) 
     # rebuild updated table 
     initStats() 

    # add new user/date if not found in first row/column 
    self.statsDates = self.statsTable[0] 
    if getIndex(self.statsNames, self.username) is None: 
     self.statsTable.append([self.username]) 
    if getIndex(self.statsDates, today) is None: 
     self.statsDates.append(today) 

    # rebuild statsNames after table appended 
    self.statsNames = [] 
    for row in self.statsTable: 
     self.statsNames.append(row[0]) 

    # getting the index of user (row) and date (column) 
    user_index = getIndex(self.statsNames, self.username) 
    today_index = getIndex(self.statsDates, today) 

    # the row where user is matched, if there are previous dates than today which 
    # has no data, append 0 (e.g. user1,0,0,0,) until the column where today's date is match 
    if len(self.statsTable[user_index]) < today_index + 1: 
     for i in range(0,today_index + 1 - len(self.statsTable[user_index])): 
      self.statsTable[user_index].append(0) 

    # insert pv or tb code if found 
    if code is None: 
     self.statsTable[user_index][today_index] = amount + int(re.match(r'\b\d+?\b', str(self.statsTable[user_index][today_index])).group(0)) 
    else: 
     self.statsTable[user_index][today_index] = str(re.match(r'\b\d+?\b', str(self.statsTable[user_index][today_index])).group(0)) + ' - ' + code 

    # Writing final table 
    with open(self.stats, 'w', newline='') as f: 
     writer = csv.writer(f) 
     writer.writerows(self.statsTable) 

    # return the summation of the user's total count 
    total_follow = 0 
    for i in range(1, len(self.statsTable[user_index])): 
     total_follow += int(re.match(r'\b\d+?\b', str(self.statsTable[user_index][i])).group(0)) 

    return total_follow 
+0

Можете подробно объяснить вашу проблему и какой результат вы ожидаете. Невозможно помочь с небольшим количеством информации. Также попробуйте воспроизвести свою проблему в MWE. – jlandercy

+0

Привет @jlandercy Я бы хотел дать больше информации, но ошибки не было. Когда я проверю csv, может произойти 2 вещи, либо 1-я строка будет нажата, создавая новый заголовок, либо данные полностью стираются (это редко, но произошло несколько раз). Кроме того, мне нужно указать, что в одном файле может быть несколько сценариев и запись. Я самоучка, поэтому мой словарь в какой-то степени ограничен, что такое MWE? – Randize

+0

Мы не знаем, что вы намереваетесь сделать, вы просто отправляете код и структуру файлов, но не описываете, что должен делать код. – jlandercy

ответ

1

Как говорит Дэвид Z, параллелизм, скорее всего, является причиной вашей проблемы. Я добавлю, что формат CSV не подходит для хранения, индексирования, сортировки базы данных, поскольку он является простым/текстовым и последовательным.

Вы можете обрабатывать его с использованием СУБД для хранения и обновления ваших данных и периодической обработки вашей статистики. Тогда ваш формат CSV - это только формат импорта/экспорта.

Python offers a SQLite binding в его стандартной библиотеке, если вы строите разъем, импорт/обновление содержимого CSV в SQLite схеме, а затем сбросить результаты в CSV, вы сможете справиться с concurency и сохранить свой собственный формат без worring об установке сервера баз данных и установка новых пакетов в Python.

+0

Да, я думал об этой же проблеме, связанной с хранением базы данных. Спасибо за ваш вклад, посмотрим больше на это. – Randize

1

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

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

Простой способ исправить это только то, что вы упомянули в вопросе, каждый отдельный процесс (или поток) записывать в свой собственный файл, а затем иметь отдельный код для объединения всех этих файлов в конце. Это то, что я, вероятно, сделаю.

Если вы не хотите этого делать, то, что вы можете сделать, это разные процессы/потоки отправлять свою информацию в «процесс агрегатора», который объединяет все и записывает их в файл - ключ состоит в том, что только агрегатор когда-либо пишет файл. Конечно, для этого требуется, чтобы вы построили некоторый метод межпроцессного взаимодействия (IPC), и это, в свою очередь, может быть сложным, в зависимости от того, как вы это делаете. На самом деле одним из лучших способов реализации IPC для простых программ является использование временных файлов, что является тем же самым, что и в предыдущем абзаце.

+0

Спасибо, ваш вход, никогда бы не знал, что есть такая вещь, как агрегатор без вас. – Randize

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