Excel数据合并(追加写入)

数据合并

两表合并

在这里插入图片描述

已知a c两个都含有数据的xlsx文件

要求:将a文件数据写入c数据

只用pandas包实现

为什么不直接df01.to_excel()到c文件的路径?

答:pandas中的to_excel方法会重写覆盖,做不到在c文件中继续写入的功能,所以先合并成总的DataFrame再to_excel重写覆盖进去。

实现逻辑一:
		data1+data2合并  --> 重写覆盖
		
		1,拿出a文件数据df01,拿出c文件数据df02
		2,concat方法,合并2个df,合并后的DataFrame赋值为df03
		3,df03.to_excel()


缺点: 数据文件很大  或者  很多文件都同时插入同一个文件时,执行耗时长。

不是加个mode='a’的参数就可以了么?

答:虽然to_excel和to_csv的两者非常相似,但是在参数方面还是有细微的区别,to_csv里面有mode='a’参数,而to_excel中没有mode参数。

实现逻辑二:
		将要写入的文件进行   excel -->  csv  -->  excel 操作,目的是借用to_csv的mode参数。
		
		1,拿出c文件数据df02写入到一个新的csv文件,命名为f,(直接Excel里面,另存为,可能会出问题)
		2,从a文件拿出数据df01利用to_csv写入到f文件中
		3,将f文件,另存为.xlsx格式的文件就行。
		   或者你代码直接read_csv(记得加参数encoding='gbk'这样不会报错!)再to_excel都行。

下面提供,实现逻辑一,的解决方案:

import pandas as pd
'''
    将一个Excel文件写入另一个Excel文件中
    执行逻辑:
            创建一个需要写入的文件
            在已创建的文件into_file中写入,从open_file中拿出的数据
    执行过程:
            只用pandas , 因为pandas的to_excel相当于重写覆盖
            所以需要把两个文件都打开变成2个Dataframe然后进行合并后,重写覆盖进要写入的文件中
            
'''

def write_excel_xls(open_file,into_file):
    '''
    :param open_file:   要拿出用于写入的文件
    :param into_file:   要写入的汇总文件
    :param combined:    合并后的文件
    :return:
    '''
    open_path = 'C:\\Users\\Administrator\\Desktop\\{}.xlsx'.format(open_file)
    into_path = 'C:\\Users\\Administrator\\Desktop\\{}.xlsx'.format(into_file)
    open_data = pd.read_excel(open_path,header=None)
    into_data = pd.read_excel(into_path,header=None)
    # lens = df[0].shape
    open_row =open_data[0].shape[0]
    into_row =into_data[0].shape[0]
    print(open_data)
    print('{}文件的行数为{}'.format(open_file,open_row))
    print(into_data)
    print('{}文件的行数为{}'.format(into_file,into_row))
    print('合并后的表如下所示:')
    combined = pd.concat([into_data,open_data],ignore_index=True)
    print(combined)
    combined.to_excel(into_path,index=False,header=None)
    print("xls格式表格写入数据成功!")
write_excel_xls('a','c')

如果你要合并到的那个Excel文件(假设文件名叫c)有索引,那么用pandas打开c文件的read_excel的参数header=None这一行不要。
如果你的Excel还有其他别的小需求,可以参考下面这个我写的博客。
pandas对Excel或者CSV或者数据库操作和参数,看这里

用xlrd包实现

Python 在已存在的excel表格中写入数据
xlrd模块详解

xlrd模块我不是很熟悉,花费了一番时间功夫的摸索,还是被我搞定了!
需要注意的是:
			打开的工作簿工作表示谁?
			写入的工作表sheet的对象是谁?
		    对哪个sheet对象执行write操作?
		    哪个工作簿workbook的哪个path进行save?

不然你很容易搞不清楚,从而得到的结果会出现问题,可能还是重写覆盖或者别的问题。
实现逻辑:	
		1,读取d文件(要写入的文件)的行数
		2,读取a文件(sheetobj.get_rows得到一个可迭代对象)
		3,将这个可迭代对象,逐行,从d文件的末尾写下去
		4,保存d文件即可。

import copy
import xlrd
from xlutils import copy

def write_excel_xls(read_file,write_file):
    read_path = 'C:\\Users\\Administrator\\Desktop\\{}.xlsx'.format(read_file)
    write_path = 'C:\\Users\\Administrator\\Desktop\\{}.xlsx'.format(write_file)
    #拿出数据
    r_book = xlrd.open_workbook(read_path)
    #获取sheet表的数据,return一个可迭代对象
    sheets = r_book.sheet_by_index(0).get_rows()
    #获取要写入的工作表的总行数
    r_book02 = xlrd.open_workbook(write_path)
    row = r_book02.sheet_by_index(0).nrows
    #得到可写入的sheet对象w_sheet
    w_book02 = copy.copy(r_book02)
    w_sheet02 = w_book02.get_sheet(0)  # w_sheet = w_book.sheets()[0]
    i = 0
    for k in sheets:
        #在指定 行列 写入数据
        print(k)
        w_sheet02.write(row+i, 0, k[0].value)  # 像表格中写入数据(对应的行和列)
        w_sheet02.write(row+i, 1, k[1].value)  # 像表格中写入数据(对应的行和列)
        w_sheet02.write(row+i, 2, k[2].value)  # 像表格中写入数据(对应的行和列)
        i += 1
    w_book02.save(write_path)  # 保存工作簿
    print('写入{}条数据成功!'.format(i))
write_excel_xls('a','d')

普通的文件读写

普通文件读写,很久没写了,常用的还是会一些,对于编码乱码这方面,还是让我很头痛!
资料查了半天

我觉得,直接open一个xlsx文件应该是不行的,无论你把编码格式改成什么都不行。
但是打开txt文件可行,或者导入csv模块去打开csv文件那就有点绕远了。

实现逻辑:
		将要写入的文件进行   excel -->  txt  -->  excel 操作,目的是借助‘a’参数不会重写覆盖,以及不出现中文乱码。
		(如果有能直接open一个excel文件,并且不出现乱码的方法,麻烦知道的大佬评论指点一下,谢谢!)
		
		1,将a文件另存为txt文件
		2,用read()读取a文件里的数据
		3,将读取的数据通过write()方法写入到另外一个txt文件中(如果是有数据的excel,麻烦转换成txt这样就可以用'a'参数做到不会重写覆盖)
		4, 借用pandas将txt文件转成xlsx文件,先读取read_table(记得加参数encoding='gb18030'这样不会乱码报错!)再to_excel即可,
		直接txt另存为,改编码格式,得到的xlsx文件虽然显示上没问题,但是工作簿里会提示你修复啥的,可能会有些小问题。
import pandas as pd

def write_to_txt(read_file,write_file):
    read_path = 'C:\\Users\\Administrator\\Desktop\\{}.txt'.format(read_file)
    write_path = 'C:\\Users\\Administrator\\Desktop\\{}.txt'.format(write_file)

    with open(read_path,encoding='gb18030', errors='ignore') as f:
        a = f.read()
        with open(write_path,'a') as writer:
            writer.write(a)

write_to_txt('a','f')

df = pd.read_table('C:\\Users\\Administrator\\Desktop\\f.txt',encoding='gb18030')
print(df)
df.to_excel('C:\\Users\\Administrator\\Desktop\\f01.xlsx')

总结

以上4种逻辑,借助csv或者txt转换格式的太麻烦了。

所以相对比较方便的是:
				1,pandas包先合并再重写覆盖。
				2,xlrd模块,进行工作簿工作表直接逐行继续写入操作。

这2个里面,
			方法1需要合并操作,然后再进行重写覆盖操作。
			方法2用for循环去取迭代器的数据,逐行写入。
			
所以,相对来看应该方法2会更快一些。

多表数据合并

在这里插入图片描述
在这里插入图片描述

比如,上面这种,pick文件夹里面,一堆的文件夹,一堆的文件夹里面又是一堆的文件夹或者是xlsx文件



我的最终目的是要把pick文件夹里所有的xlsx文件 全部写到一个total.xlsx文件中。

那么我该怎么构建逻辑呢?

首先有了上述,两表合并的函数之后,我们只需要再写一个遍历文件夹去找文件的方法就行了

一旦找到一个xlsx文件,就执行两表合并的函数方法

当然,文件量一大,效率肯定会降低,不过可以用多进程,或者异步这些来提速,下面我先介绍一般的逻辑构建。

代码由一个查找文件函数,和一个写入文件函数组成。(写入函数我这里用的是pandas包合并,你也可以换成xlrd包的那个函数会快一些)

import pandas as pd
import os
# import  company

total_dir_path = 'C:\\Users\\Administrator\\Desktop\\12.18-12.25\\pick'
# total_list = os.listdir(total_dir_path)
# print(total_list)
target_file_path = 'C:\\Users\\Administrator\\Desktop\\b.xlsx'

def find_file_to_work(total_dir_path,target_file_path):
    total_list = os.listdir(total_dir_path)
    print('该目录下的文件夹(包)总数为:{}'.format(len(total_list)))
    print(total_dir_path)
    for i in total_list:
        print(i)
        test_path = total_dir_path+'\\{}'.format(i)
        condition = os.path.isfile(test_path)
        print(condition)
        if condition:
            write_excel_xls(test_path,target_file_path)
            print('一个文件写入成功!')
        else:
            dir_path = test_path
            find_file_to_work(dir_path,target_file_path)


def write_excel_xls(open_file_path,target_file_path):

    # open_path = 'C:\\Users\\Administrator\\Desktop\\{}.xlsx'.format(open_file)
    # into_path = 'C:\\Users\\Administrator\\Desktop\\{}.xlsx'.format(into_file)
    open_data = pd.read_excel(open_file_path,header=None)
    into_data = pd.read_excel(target_file_path,header=None)
    # lens = df[0].shape
    open_row =open_data[0].shape[0]
    into_row =into_data[0].shape[0]
    print(open_data)
    print('{}文件的行数为{}'.format(open_file_path,open_row))
    print(into_data)
    print('{}文件的行数为{}'.format(target_file_path,into_row))
    print('合并后的表如下所示:')
    combined = pd.concat([into_data,open_data],ignore_index=True)
    print(combined)
    combined.to_excel(target_file_path,index=False,header=None)
    print("xls格式表格写入数据成功!")

find_file_to_work(total_dir_path,target_file_path)

一般逻辑这样写出来,我拿去执行,200多个文件写入同一个文件,花了大概有 7 8 分钟肯定有的,最终得到了一张5万多条的总数据表。 我忘了加时间函数去测一测时间了。。。因为太慢了。。懒得跑第二遍了= =。

但是用多进程多线程、或者协程,来进行优化操作呢?
在这里插入图片描述
逻辑是这样的,进程(线程),在抢占资源过程中,会发生数据覆盖造成的数据丢失。所以这种情景下,并不怎么适合进程线程,协程反而更适合些。

然而用异步协程,在这种逻辑下,在实际意义上也优化不了多少。
python uvloop异步框架学习
最新Python异步编程详解
异步代码如下:

import asyncio
import time
import os
import xlrd
from xlutils import copy

total_dir_path = 'C:\\Users\\Administrator\\Desktop\\12.18-12.25\\pick'
file_list = []

def find_file_to_work(total_dir_path,file_list):
    total_list = os.listdir(total_dir_path)
    print('该目录下的文件夹(包)总数为:{}'.format(len(total_list)))
    print(total_dir_path)
    for i in total_list:
        print(i)
        test_path = total_dir_path+'\\{}'.format(i)
        condition = os.path.isfile(test_path)
        print(condition)
        if condition:
            file_list.append(test_path)
            print('文件写入成功!')
        else:
            dir_path = test_path
            find_file_to_work(dir_path,file_list)
    print(file_list)
    print(len(file_list))
    f_list =file_list
    return f_list
     
async def write_excel_xls(read_path):# 通过async def定义的函数是原生的协程对象
    # 拿出数据
    write_path = 'C:\\Users\\Administrator\\Desktop\\xxx.xlsx'
    r_book = xlrd.open_workbook(read_path)
    # 获取sheet表的数据,return一个可迭代对象
    sheets = r_book.sheet_by_index(0).get_rows()
    # 获取要写入的工作表的总行数
    r_book02 = xlrd.open_workbook(write_path)
    row = r_book02.sheet_by_index(0).nrows
    # 得到可写入的sheet对象w_sheet
    w_book02 = copy.copy(r_book02)
    w_sheet02 = w_book02.get_sheet(0)  # w_sheet = w_book.sheets()[0]
    i = 0
    for k in sheets:
        # 在指定 行列 写入数据
        print(k)
        w_sheet02.write(row + i, 0, k[0].value)  # 像表格中写入数据(对应的行和列)
        w_sheet02.write(row + i, 1, k[1].value)  # 像表格中写入数据(对应的行和列)
        w_sheet02.write(row + i, 2, k[2].value)  # 像表格中写入数据(对应的行和列)
        i += 1
    w_book02.save(write_path)  # 保存工作簿
    print('写入{}条数据成功!'.format(i))

async def main():
    start = time.time()  
    await asyncio.wait([
        write_excel_xls(i) for i in find_file_to_work(total_dir_path,file_list)])
    end = time.time()
    print("Complete in {} seconds".format(end - start))


loop = asyncio.get_event_loop()
loop.run_until_complete(main())

但是我们可以换个角度,逐层优化。
在这里插入图片描述这样逐层优化,比如共有200个文件,你可以20个一组,这样就分出10份,然后这10份再合并到总的数据表中,那么这第一层的耗费时间为max_time1,第二层的耗费时间为max_time2,因为异步的原理,实际执行过程并不会去等一层完成了再完成下一层,但是我们可以估计出最大的耗费时间为total_time = max_time1+max_time2

从一定程度上来看,还是得到了很大的优化,按这样的分法,大概提速了近6.6倍时间。当然分的方案可以自己写逻辑代码。

设计了好久。。跑出来的数据还是有问题,不知道哪里出错了T^T
下次有空了再回过头来补充好了,脑壳疼。。

  • 1
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值