Python 合并多Excel案例

其实python有很多库都可以操作excel,比如xlrd,xlwt,但是xlwt只能写不超过65535行数据,有很大局限,因此我采用了openpyxl这个库读写excel。

这个案例分成两部分:

第一部分是创建多个excel文档,每个文档中有AB两个个sheet,每个sheet中有多列,多行。比如:
Python 合并多Excel案例

第二部分是合并多个excel文档,把多个文件的多个sheet根据名称合并到对应的sheet,每个sheet中的列也需要对应起来

第一部分:创建源文件

思路是专业的
1.创建单个文件
2.创建多个sheet
3.创建列标题,A B C D E
4.写入数据,具体的数据是100到999之间的随机数,在E列写入公式:SUM(A1:Ex)

使用到的库:os, random, gc, openpyxl

import os
import random
import gc
from openpyxl import Workbook, load_workbook

def clearFile(file):
    if os.path.exists(file):
        os.remove(file)

# 使用Openpyxl创建一个xlsx, 行数可以指定,2个sheet
def createExcelWithOpenpyxl(file,rows):
    wb = Workbook()
    # 创建2个sheet
    for name in ['A','B']:
        ws = wb.create_sheet(name)
    
    # 定义列标题    
    columns = ['A','B','C','D']
    
    # 删除默认的Sheet
    ws = wb['Sheet']
    wb.remove(ws)    
    
    sheetnames = wb.get_sheet_names()
    for sheet in sheetnames:
        ws = wb[sheet]
        sheetName = '数据 {n}'.format(n=sheet)
        print('开始写入 [{s}]...'.format(s=sheetName))
        
        # 设置列标题
        for i,c in enumerate(columns): 
            p = '{col}1'.format(col=c)
            
            ws[p] = '字段_{n}'.format(n=i+1)            
        ws['E1']='合并'
            
            
        # 写入数据    
        for i in range(1,rows+1):
            for c in columns:
                p = '{x}{y}'.format(x=c, y=i+1 )                
                
                # 单元格写入随机值
                ws[p] = random.randint(100,999)                
                
                # 合计列增加公式
                # 给合计列增加公式
                formula = "=SUM(A{a1}:D{a2})".format(a1=i+1,a2=i+1)
                ws['E{n}'.format(n=i+1)] = formula
             
                
        del ws
        gc.collect()    
    wb.save(file)    


# 创建一个excel文件,里面创建50个sheet    
def createExcelFile():
    path = r'data\\datafile_{n}.xlsx'
    
    # 定义文件数量
    fileCount = 200
    for i in range(fileCount):        
        finallyFileName = path.format(n=i+1)        
        print('\n开始创建{n}'.format(n=finallyFileName))
        # 删除文件
        clearFile(finallyFileName)
        
        # 每个文件创建100行数据
        createExcelWithOpenpyxl(finallyFileName,1000)
    
    print('createExcelWithOpenpyxl() done.')   
    
    
if __name__ == '__main__':
    createExcelFile()
    print('done.')    

使用createExcelWithOpenpyxl()创建具体的文件,用createExcelFile()来调用前面的函数,循环N次就可以创建N个文件。调用createExcelWithOpenpyxl()时指定好路径和每个文件中的数据行数即可。

第二部分:合并多个文件

思路:
1.遍历指定路径下的.xlsx文件
2.初始化好目标文件summery1.xlsx,根据源文件创建好目标文件中的sheet还有列标题
3.遍历源文件列表读取每个文件的每个Sheet数据
4.写入目标文件对应的sheet、对应的列当中

使用到的库:os, random, gc, openpyxl

import os
import time
from openpyxl import Workbook,load_workbook
import gc
from win32com.client import Dispatch


# 定义一个类使用openpyxl合并多个excel文件
class Merge:

    # 源文件路径
    srcFilePath=''
    
    # 目标文件路径
    destFilePath=''
    
    
    sheetRowDict = dict()
    
    def logback(self):
        pass

    def __init__(self, srcFilePath, destFilePath):
        self.srcFilePath = srcFilePath
        self.destFilePath = destFilePath
        
        #初始化汇总文件
        self.initExcel()
        
        
    # 初始化目标excel文件,创建好文件,根据原始src文件列表中第一个文件的内容,在目标文件中创建表头和sheet
    def initExcel(self):
        
        self.logbak('开始初始化汇总文件'+self.destFilePath)
        try:
            # 创建一个工作簿
            book = Workbook()# xlwt.Workbook(encoding="utf-8")
            
            ws =  book['Sheet']
            book.remove(ws)    
            
            self.logbak('开始收集源文件名集合')
            # 返回第一个src文件
            self.srcFileList = self.getExcelNameList()
            
            
            self.logbak('准备读取第一个源文件,创建汇总文件的表头和sheet集合')
            # 一个待合并execl的路径
            excel_path = self.srcFilePath + "\\" + self.srcFileList[0]
            
            self.logbak('准备读取第一个源文件的sheet 名字列表')
            # 获取excel的所有sheet
            sheetNameList = self.getSheets(excel_path)
            
            
            self.logbak('准备遍历第一个源文件的sheet对象,创建汇总文件的所有sheet')
            # 遍历sheet列表,给汇总文件增加好所有的sheet
            for sheetName in sheetNameList:
            
                # 初始化字典,每个sheet的开始行数初始化成2,表示从第2行开始写入数据
                Merge.sheetRowDict[sheetName] = 2;
                ws = book.create_sheet(sheetName)# book.add_sheet(sheetName)
                
                self.logbak('根据{f}的sheet:{s} 创建汇总文件表头'.format(f=self.srcFileList[0],s=sheetName))
                filedNames = self.getFields(excel_path,sheetName)
                
                self.logbak('开始创建表头,字段列表: '+ ', '.join(filedNames))

                # 给当前sheet写入表头
                for i in range(len(filedNames)):
                    
                    # cell(行号,列号) 行号,列号至少是1
                    ws.cell(1,i+1).value = filedNames[i]
                    
            book.save(self.destFilePath)
            self.logbak('初始化汇总文件完成')
        except Exception as e:
            print('初始化文件失败,',e)
        #return False
        
       
    
       
    # 读取指定目录下的所有文件,文件后缀默认是.xlsx
    def getExcelNameList(self,exten='.xlsx'):
        #excelName_list = os.listdir(self.srcFilePath)
        #return excelName_list       
        fileList=[]
        for root, dirs, files in os.walk(self.srcFilePath):
            for file in files:
                (filename, extension) = os.path.splitext(file)
                if extension == exten:
                    fileList.append(file)
        
        print('fileList',fileList)
        return fileList
        
        
    # 返回指定文件的所有sheet 名称
    def getSheets(self,file):
        workbook = load_workbook(file)
        sheets = workbook.get_sheet_names()
        #print('sheets=',sheets)
        return sheets
        
    # 返回指定文件指定sheet中第一行的数据,通常是字段名    
    def getFields(self,file, sheetName):
        workbook = load_workbook(file)
        
        # 得到指定的sheet
        ws = workbook[sheetName]
        
        # 得到第一行数据作为表头返回,ws.max_column 是当前sheet的列总数
        field_data = ws.iter_rows(min_row=1, max_col=ws.max_column, max_row=1)
        fieldName = []
        field_tuple = tuple(field_data)        
        
        # 遍历第一行的数据,组装成list
        for row in field_tuple:
            for col in row:
                fieldName.append(col.value)
        return fieldName
        
        
    # 返回指定文件的指定的sheet
    def getSheetByName(self,file,sheetName):        
        workbook = load_workbook(file)        
        # 得到指定的sheet
        ws = workbook[sheetName]
        
        # 返回迭代器
        data_all = ws.rows
        data_tuple = tuple(data_all)
        return data_tuple
        
        
    # 自定义输出日志的格式    
    def logbak(self,info):
        datetime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
        print('[{m}] {s}'.format(m=datetime, s=info))
    
    # 解决openpyxl打开excel文件读取公式列是空的问题,把该文件打开后重新保存即可
    def resaveExcel(self,filename):
        xlApp = Dispatch("Excel.Application")
        xlApp.Visible = False
        xlBook = xlApp.Workbooks.Open(filename)
        xlBook.Save()
        xlBook.Close()
    
    # 核心方法合并文件
    def mergeExcel(self):
        # 用来记录总表中的行数
        total_excel_row = 1
        
        # 获取总表的book,sheet

        self.logbak('开始打开汇总文件')
        
        workbook = load_workbook(self.destFilePath)#, formatting_info=True)
        
        self.logbak('开始收集源文件名集合')
        # 得到原始的excel文件列表
        self.srcFileList=self.getExcelNameList()
        self.logbak('开始遍历源文件名集合'+ ','.join(self.srcFileList))

        
        # 遍历文件列表,打开每个文件
        for srcFile in self.srcFileList:     
            srcFielPath = self.srcFilePath+'\\'+srcFile
            print('\n')
            self.logbak('读取[{s}]获得所有的sheet'.format(s=srcFile))
            #self.resaveExcel(srcFielPath)
            srcSheetList = self.getSheets(srcFielPath)
            self.logbak('sheet个数:[{n}]'.format(n=len(srcSheetList)) )
            
            #total_excel_row = 1
            # 遍历源文件的所有sheet
            for index,sheetName in enumerate(srcSheetList):
                
                self.logbak('读取汇总文件 sheet index=[{i}]'.format(i=index))
                
                # 得到目标汇总表的对应的sheet
                destSheet = workbook[sheetName]#wtbook.get_sheet(index)
                
                self.logbak('读取源文件   sheet name=[{s}]'.format(s=sheetName))               

                
                # 打开需要合并的源文件, 仅仅装载数据,忽略公式
                srcWookbook = load_workbook(srcFielPath, data_only=True)
                
                # 激活指定的sheet
                srcSheet = srcWookbook[sheetName]
                
                srcDataTuple = tuple(srcSheet.rows)
                
                # n_rows-1表示减去标题行
                self.logbak('源数据[{rows}]行,写入汇总文件起始行:{startRow}'.format(rows=(srcSheet.max_row-1), startRow=Merge.sheetRowDict[sheetName]) )

                # 开始遍历读取数据,并写入数据,从1开始而非0开始是要跳过标题行
                for row_index in range(1,srcSheet.max_row): 
                
                    # 读取一行的数据,列表形式
                    row_data_list = srcDataTuple[row_index] 
                    
                    
                    # 遍历刚读取的一行数据
                    for index,data in enumerate(row_data_list):
                        #print('--> {x} {y}={v}'.format(x=Merge.sheetRowDict[sheetName], y=index+1, v=data.value) )
                        destSheet.cell(Merge.sheetRowDict[sheetName] ,index+1).value = data.value
                    
                    # 每写一行,相关的sheet的总行数加1
                    Merge.sheetRowDict[sheetName] += 1
                
                del srcWookbook,srcSheet
                gc.collect()
                
                self.logbak('源文件中[{sheet}]处理完成'.format(sheet=sheetName) )                
                workbook.save(self.destFilePath)

            
        self.logbak("数据合并已完成")
       
        
        
def testMerge():
    srcPath = r'data'
    destPath = r'dest\summery1.xlsx'
    m = Merge(srcPath,destPath)
    m.mergeExcel()    
    
if __name__ == '__main__':
    testMerge()
    print('done.')   

 

上一篇:JavaScript 如何导出 Excel


下一篇:Excel sheetName 过滤特殊字符