Как сохранить данные с помощью openpyxl с Python3 в файле Excel? Есть ли способ потратить на это немного времени? - PullRequest
1 голос
/ 06 мая 2020

Процедура:

  1. Чтение данных из текстового файла построчно;

  2. Затем отправьте данные в последовательный порт;

  3. Сохраните данные в файл Excel в строке с номером / датой / временем


Я пробовал два метода, и оба из них работают.

Но вот какая проблема:

  1. Чем больше данных , тем больше времени берется при сохранении новых данных в файл Excel. Например, при записи данных в строку 10000 почти требуется 2 секунды (когда я использую append () для добавления новой строки в файл Excel);

  2. Я хочу отправлять и сохранять данные все время, пока я не остановлю скрипт в Pycharm, нажав кнопку STOP . Как только я это сделал, Excel, сохраненный ранее, имеет сломанный и НЕ МОЖЕТ открыть его снова.

Я хочу решить эту проблему. Может у кого-нибудь есть предложения? Большое спасибо!


Вот код:

import serial
import serial.tools.list_ports
import time
import datetime
import sys
import os
import openpyxl
from openpyxl.styles import Font
from openpyxl.styles import PatternFill
from openpyxl.styles import Alignment


# The path to palce the Excel file
def creatfilepath(path):
    # path -- The user input a path

    if os.path.isdir(path):
        datapath = path
        print('\nM1:The path is OK, and the Excel file will be saved in {}'.format(datapath))
    else:
        if os.makedirs(path):
            datapath = path
            print('\nM2:The path does not exist, and scrip will creat the path {} to save the Excel'.format(datapath))
        else:
            datapath = os.getcwd()
            print('\nM3:Creating the path is failed, and the Excel will be saved in same path {} where the script is.'.format(datapath))

    return datapath


# Creating the Excel to save the data
def creatdatafile(filename, path, data_title):
    # filename -- Excel filename
    # path -- The path to save the Excel 
    # data_title -- Excel's title, which is a list and the default value is ['Number', 'Date', 'Time', 'Command', 'Type', 'Comment']

    # Creating a Workbook
    serial_data_1902_wb = openpyxl.Workbook()

    # Accessing the active sheet
    serial_data_1902_sheet = serial_data_1902_wb.active

    # sheet'title
    serial_data_1902_sheetname = datetime.datetime.now().strftime('%Y%m%d_%H%M%S')
    serial_data_1902_sheet.title = serial_data_1902_sheetname

    # Excel's filename
    serial_data_1902_filename = filename + '_' + \
        datetime.datetime.now().strftime('%Y%m%d_%H%M%S') + '.xlsx'

    # The absolute path
    ab_path = path + "\\" + serial_data_1902_filename       

    serial_data_1902_wb.save(ab_path)

    # Loading the Excel
    active_data_file = openpyxl.load_workbook(ab_path)

    # Accessing the sheet
    active_datasheet = active_data_file[serial_data_1902_sheetname]

    # Setting the title
    row_title = data_title
    active_datasheet.append(row_title)

    # Freezing the 1st row
    active_datasheet.freeze_panes = 'A2'

    # Accessing the title's scope
    title_scope = active_datasheet.dimensions

    # Arial/12/Bold/
    title_font_obj = Font(name='Arial', size=10, bold=True,
                          italic=False, strike=False, color='000000')

    # Fill type
    title_fill_obj = PatternFill(fill_type='solid', fgColor='7EC0EE')

    # Alignment
    title_align_obj = Alignment(
        horizontal='center', vertical='center', wrap_text=False)

    # Formating the 1st row
    for rowOfCellObjects in active_datasheet[title_scope]:
        for cellObject in rowOfCellObjects:        
            cellObject.font = title_font_obj
            cellObject.fill = title_fill_obj
            cellObject.alignment = title_align_obj

    active_data_file.save(ab_path)

    # Return the absolute path
    if os.path.exists(ab_path):
        print('\nM4:The Excel {} have created, and the path is {}'.format(
            serial_data_1902_filename, path))
        return ab_path
    else:
        print('\nE0:Creating Excel is failed, please check!')
        sys.exit(0)


def isavailable(port):

    port_list = list(serial.tools.list_ports.comports()
                     )        

    if len(port_list) <= 0:
        print('\nE1:There is not serial port on the host!')
        sys.exit(0)
    else:
        port_name_list = []

        for port_objet in port_list:
            port_name = port_objet[0]

            port_name_list.append(port_name.lower())

        print('\nM5:The serial ports is:{}'.format(port_name_list))

    if port.lower() in port_name_list:       
        print('\nM6:')
    else:
        print('\nE2:')
        sys.exit(0)


# Creating a vitural serial port and open it
def createport(port, baudrate=115200):

    isavailable(port)

    try:
        serialport = serial.Serial(port, baudrate, timeout=1, write_timeout=1)
    except ValueError:
        sys.exit('\nE3:')
    except (OSError, serial.SerialException):
        sys.exit('\nE4:')

    if serialport.is_open and port == serialport.portstr:       
        print('\nM7:')
        serialport.flushInput()        
    else:
        sys.exit('\nE5:')

    return serialport


def savecommand(num, command_list, excelabpath, excelworkbook, excelsheet):
    # num --  The number of command
    # command_list -- A list which contain the data
    # excelabpath -- The absolute path of Excel
    # excelworkbook -- The Excel which save data
    # excelsheet -- the sheet which save the data

    try:
        i = 0
        for row in excelsheet.iter_rows(min_row=num+1, max_col=5, max_row=num+1):
            for cell in row:
                cell.value = command_list[i]
                i += 1

                if i < len(command_list):
                    continue
                else:
                    break

        excelworkbook.save(excelabpath)
    except TypeError:
        print('\nE10:')


def sendcommand(abpath, workbook, sheet, commandfile, port, intertime=0.5, commamd_num=1):
    #
    if not port.is_open:
        try:
            port.open()
        except:
            print('\nE6:')
    else:
        pass


    try:
        with open(commandfile, 'r', encoding='utf-8') as file_object:
            for line in file_object:
                if len(line) > 1 and (not line.startswith('#')):
                    command_hex = bytes.fromhex(
                        line.strip())
                    try:
                        print(commamd_num, " ", datetime.datetime.now(),
                              " ", line)

                        port.write(command_hex)

                        # The list contain the number/date/time/command
                        data_list = [commamd_num, datetime.datetime.now().strftime(
                            '%Y/%m/%d'), datetime.datetime.now().strftime('%H:%M:%S.%f'), line.strip()]

                        savecommand(commamd_num, data_list, abpath, workbook, sheet)

                        time.sleep(intertime)

                        commamd_num += 1

                    except serial.SerialTimeoutException:
                        print("\nE7:")

                        time.sleep(1)
                        port.write(command_hex)

                        # The list contain the number/date/time/command
                        data_list = [commamd_num, datetime.datetime.now().strftime(
                            '%Y/%m/%d'), datetime.datetime.now().strftime('%H:%M:%S.%f'), line.strip()]

                        savecommand (commamd_num, data_list, abpath, workbook, sheet)

                        time.sleep(intertime)

                        commamd_num += 1
                else:
                    continue
    except FileNotFoundError:
        print('\nE8:')
        sys.exit(0)
    except PermissionError:
        print('\nE9:')
        sys.exit(0)

    port.close()

    if not port.is_open:
        print('\nM9:')

    return commamd_num 


# ~~~~~~~~~~~~~~ The parameters of serial port ~~~~~~~~~~~~~~~~~~
# port number
comNumber = 2
# port name
comPort = 'com{}'.format(comNumber)
# baudRate
baudRate = 115200

# ~~~~~~~~~~~~~~ Other parameters ~~~~~~~~~~~~~~~~~~
# The path of command file
commandPath = r'.\1902.txt'

# The Excel path
savePath = r'D:\1902Code'

# The name of Excel
excelName = 'SerialData1902'

# The title
excelTitle = ['Number', 'Date', 'Time', 'Command', 'Type', 'Comment']

# The time between two command was sent
interTime = 0.01

# 
isForever = 1


# ~~~~~~~~~~~~~~~~~~~~~  Begin ~~~~~~~~~~~~~~~~~~~

# Creating the path which save the Excel
excel_path = creatfilepath(savePath)

# Creating the Excel
excel_ab_path = creatdatafile(excelName, excel_path, excelTitle)

# Loading the Excel
excel_workbook = openpyxl.load_workbook(excel_ab_path)

# Accessing the sheet
excel_sheet = excel_workbook.active

# Creating the serial port
serial_port = createport(comPort, baudRate)

# The number of sending command and start with 1
command_num = 1


if isForever:
    print('\nM10:')
    while isForever:
        command_num = sendcommand(excel_ab_path, excel_workbook, excel_sheet,
                                  commandPath, serial_port, interTime, command_num)
elif isForever == 0:
    print('\nM11:')
    command_num = sendcommand(excel_ab_path, excel_workbook, excel_sheet,
                              commandPath, serial_port, interTime, command_num)
else:
    print('\nE11:')

...