tkinter实现通用对账文件解析软件

软件需求

和银行等金融机构合作过程中,经常会有还款计划、放款文件等定时推送的文件,以常见的分隔符进行分隔开,为了在系统出现问题时,快速查找异常数据,写了一个小工具解析这些文件并写入到excel中。

image-20240403171558023

软件功能

将常见分隔符的文件解析后写入到excel中

软件界面

image-20240403170655979

软件源码

  • 使用前请安装openpyxl,pip install openpyxl,可使用pyinstaller打包成exe文件。
import os
import datetime
import loggingfrom openpyxl import Workbookimport tkinter as tk
from tkinter import filedialog,messagebox
from tkinter.ttk import *class FileParser(object):def __init__(self):pass@staticmethoddef getAllFiles(folder,data_str,suffix=".txt"):'''获取文件路径下的所有文件'''filepath_list = []for root,folder_names, file_names in os.walk(folder):for file_name in file_names:file_path = root + os.sep + file_nameif data_str != '' or data_str is not None:if data_str in file_name and os.path.splitext(file_path)[-1]==suffix:filepath_list.append(file_path)else:if os.path.splitext(file_path)[-1]==suffix:filepath_list.append(file_path)if len(filepath_list)==0:messagebox.showinfo('文件不存在',"该目录下不存在包含{}且后缀为{}的文件,请检查!".format(data_str,suffix))returnfile_path = sorted(file_path, key=str.lower)return filepath_listdef batchParseDataFile(self,data_str,logbox,start_date,end_date,date_format,source_dir,target_dir,source_suffix=".txt",data_sep="|",data_start_row=1,data_end_flag="",start_row=1,start_col=1):'''获取数据文件中的有效数据:param start_date:解析的文件的开始日期:param end_date:解析的结束日期:param date_format:日期格式:param source_dir:需要解析的文件的文件夹路径:param target_dir:生成excel文件的文件夹路径:param data_sep:数据分隔符:param data_start_row:有效数据的开始行:param data_end_flag:有效数据结束标识:param start_row:写入excel的开始行:param start_col:写入excel的开始列:param table_head:有效数据是否包含表头'''self.log = logboxstart=datetime.datetime.strptime(start_date,date_format)end=datetime.datetime.strptime(end_date,date_format)source_filelist = FileParser.getAllFiles(source_dir,data_str,source_suffix)if source_filelist is None or len(source_filelist)==0:self.log.info("该目录{}下不存在文件".format(source_dir))returnif start > end:self.log.info("开始日期{}大于结束日期{}".format(start_date,end_date))returnfiles = []null_files = []starttime = datetime.datetime.now()while start<=end:for fname in source_filelist:if start.strftime(date_format) in fname:if os.stat(fname).st_size==0:null_files.append(fname)else:files.append(fname)basename = os.path.basename(fname)file_date = start.strftime(date_format)self.log.info("{}日期的{}文件正在解析".format(file_date,basename))target_basename =  basename.split(".")[0]+".xlsx" if file_date in basename else basename.split(".")[0]+"_"+file_date+".xlsx"target_fname = os.path.join(target_dir,target_basename)self.log.info("生成{}日期的excel文件{}".format(file_date,target_basename))self.parseDataFile(fname,target_fname,data_sep=data_sep,data_start_row=data_start_row,data_end_flag=data_end_flag,start_row=start_row,start_col=start_col)start+=datetime.timedelta(days=1)endtime=datetime.datetime.now()costtime = round((endtime - starttime).total_seconds(),2)if len(files)==0:self.log.info("{}目录不存在{}-{}时间区间内的目标文件".format(source_dir,start_date,end_date))else:messagebox.showinfo('解析完成提示',"文件解析完成,{}-{}时间段内合计{}个文件,空文件{}个,解析{}个有数据文件,,耗时{}秒".format(start_date,end_date,len(files)+len(null_files),len(null_files),len(files),costtime))def parseDataFile(self,source_dir,target_dir,data_sep="|",data_start_row=1,data_end_flag="",start_row=1,start_col=1):'''获取数据文件中的有效数据:param source_dir:数据文件绝对路径:param target_dir:生成excel文件的绝对路径:param data_sep:数据分隔符:param data_start_row:有效数据的开始行:param data_end_flag:有效数据结束标识:param start_row:写入excel的开始行:param start_col:写入excel的开始列:param table_head:有效数据是否包含表头'''data = self.__getFileData(source_dir,data_sep,data_start_row,data_end_flag)fname,basename = self.__writeToExcel(source_dir,target_dir,data,start_row,start_col)return fname,basenamedef __getFileData(self,filename,data_sep,data_start_row,data_end_flag):data = []try:if os.stat(filename).st_size==0:self.log.info("{}文件为空".format(os.path.basename(filename)))with open(filename,"r",encoding="utf-8") as f:line_index = 1for line in f:if line:line = line.replace("\n","")if line_index >= data_start_row and line != data_end_flag:data.append(line.split(data_sep))if line == data_end_flag:breakelse:breakline_index = line_index+1except Exception as e:self.log.info("{}解析错误".format(filename))return datadef __writeToExcel(self,source_file,target_file,data,start_row,start_col):basename =Nonetry: if os.stat(source_file).st_size==0 or data is None or len(data)==0:self.log.info("{}文件为空,未生成对应的excel文件".format(source_file))else:with open(target_file,"w+",encoding="utf-8") as f:passbasename = os.path.basename(target_file)# self.__write_col(filename,basename,col=start_col,data=data)self.__write2ExcelOpenexl(target_file,basename,row=start_row,col=start_col,data=data)self.log.info("数据写入excel完成,文件路径{}".format(target_file))except Exception as e:self.log.info("写入文件{}错误".format(e))return target_file,basenamedef __write2ExcelOpenexl(self,excelname,sheet,row,col,data=None):wb = Workbook()ws = wb.create_sheet(sheet, 0)for y,i in enumerate(data):for x,n in enumerate(i):ws.cell( y + col, x + row, n )wb.save(excelname)wb.close()class LoggerBox(tk.Text):def write(self, message):self.insert("end", message)class APP(object):def __init__(self,window):window.title('通用对账文件解析软件')#获取屏幕尺寸计算参数,使窗口显示再屏幕中央screen_width = window.winfo_screenwidth() screen_height = window.winfo_screenheight()width = 750height = 800# window_size = '%dx%d+%d+%d' % (width, height, (screen_width-width)/2, (screen_height-height)/2)window_size = f'{width}x{height}+{round((screen_width-width)/2)}+{round((screen_height-height)/2)}'window.geometry(window_size)z = tk.Label(window,anchor = 'center',bg='white',justify = 'center', width=500, height=500)z.place(x = 0, y = 0)a = tk.Label(window,anchor = 'center',text="对账文件解析软件",relief="raised", font=('TimesNewRoman', 30),justify = 'center', width=32, height=1)a.place(x = 50, y = 30)self.source_dir = tk.StringVar()self.source_dir.set("数据文件路径")b = tk.Label(window,anchor='nw',textvariable=self.source_dir,fg='black',bg='white',font=('TimesNewRoman',12),justify='center',width=50,height=1)b.place(x = 50, y = 100)self.data_str = tk.StringVar()self.data_str.set("文件包含字符串")c = tk.Label(window,anchor='nw',textvariable=self.data_str,fg='black',bg='white',font=('TimesNewRoman',12),justify='center',width=50,height=1)c.place(x = 50, y = 150)self.suffix = tk.StringVar()self.suffix.set("数据文件后缀")d = tk.Label(window,anchor='nw',textvariable=self.suffix,fg='black',bg='white',font=('TimesNewRoman',12),justify='center',width=50,height=1)d.place(x = 400, y = 150)self.target_dir = tk.StringVar()self.target_dir.set("文件存放路径")f = tk.Label(window,anchor='nw',textvariable=self.target_dir,fg='black',bg='white',font=('TimesNewRoman',12),justify='center',width=50,height=1)f.place(x = 50, y = 200)self.data_sep = tk.StringVar()self.data_sep.set("数据分隔符")g = tk.Label(window,anchor='nw',textvariable=self.data_sep,fg='black',bg='white',font=('TimesNewRoman',12),justify='center',width=50,height=1)g.place(x = 50, y = 250)self.start_date = tk.StringVar()self.start_date.set("开始日期")h = tk.Label(window,anchor='nw',textvariable=self.start_date,fg='black',bg='white',font=('TimesNewRoman',12),justify='center',width=50,height=1)h.place(x = 50, y = 300)self.end_date = tk.StringVar()self.end_date.set("结束日期")i = tk.Label(window,anchor='nw',textvariable=self.end_date,fg='black',bg='white',font=('TimesNewRoman',12),justify='center',width=50,height=1)i.place(x = 400, y = 300)self.date_format = tk.StringVar()self.date_format.set("日期格式")j = tk.Label(window,anchor='nw',textvariable=self.date_format,fg='black',bg='white',font=('TimesNewRoman',12),justify='center',width=50,height=1)j.place(x = 50, y = 350)self.data_start_row = tk.StringVar()self.data_start_row.set("数据开始行")k = tk.Label(window,anchor='nw',textvariable=self.data_start_row,fg='black',bg='white',font=('TimesNewRoman',12),justify='center',width=50,height=1)k.place(x = 50, y = 400)self.data_end_flag = tk.StringVar()self.data_end_flag.set("数据结束标志")l = tk.Label(window,anchor='nw',textvariable=self.data_end_flag,fg='black',bg='white',font=('TimesNewRoman',12),justify='center',width=50,height=1)l.place(x = 50, y = 450)self.start_row = tk.StringVar()self.start_row.set("excel写入行")m = tk.Label(window,anchor='nw',textvariable=self.start_row,fg='black',bg='white',font=('TimesNewRoman',12),justify='center',width=50,height=1)m.place(x = 50, y = 500)self.start_col = tk.StringVar()self.start_col.set("excel写入列")n = tk.Label(window,anchor='nw',textvariable=self.start_col,fg='black',bg='white',font=('TimesNewRoman',12),justify='center',width=50,height=1)n.place(x = 400, y = 500)self.source_dir = tk.StringVar()entry_source_dir = tk.Entry(window, textvariable=self.source_dir).place(x=200, y=100)tk.Button(window,text="选择源文件夹",command=lambda:self.select_dir(self.source_dir),width=15,height=1).place(x=400, y=100)self.data_str = tk.StringVar()entry_source_dir = tk.Entry(window, textvariable=self.data_str).place(x=200, y=150)self.suffix = tk.StringVar()self.suffix.set(".txt")entry_source_dir = tk.Entry(window, textvariable=self.suffix).place(x=550, y=150)self.target_dir = tk.StringVar()entry_target_dir = tk.Entry(window, textvariable=self.target_dir).place(x=200, y=200)tk.Button(window,text="选择存放文件夹",command=lambda:self.select_dir(self.target_dir),width=15,height=1).place(x=400, y=200)self.data_sep = tk.StringVar()self.data_sep.set("|")entry_data_sep = tk.Entry(window, textvariable=self.data_sep).place(x=200, y=250)self.date_format = tk.StringVar()self.date_format.set("%Y%m%d")entry_date_format = tk.Entry(window, textvariable=self.date_format).place(x=200, y=350)now=datetime.datetime.now()self.start_date = tk.StringVar()self.start_date.set(now.strftime(self.date_format.get()))entry_start_date = tk.Entry(window, textvariable=self.start_date).place(x=200, y=300)self.end_date = tk.StringVar()self.end_date.set(now.strftime(self.date_format.get()))entry_end_date = tk.Entry(window, textvariable=self.end_date).place(x=550, y=300)self.data_start_row = tk.IntVar()self.data_start_row.set(int(1))entry_data_start_row = tk.Entry(window, textvariable=self.data_start_row).place(x=200, y=400)self.data_end_flag = tk.StringVar()entry_data_end_flag = tk.Entry(window, textvariable=self.data_end_flag).place(x=200, y=450)self.start_row = tk.IntVar()self.start_row.set(int(1))entry_start_row = tk.Entry(window, textvariable=self.start_row).place(x=200, y=500)self.start_col = tk.IntVar()self.start_col.set(int(1))entry_start_col = tk.Entry(window, textvariable=self.start_col).place(x=550, y=500)n = tk.Button(window, text='开始解析', width=90,height=1, command=self.parse_file)n.place(x = 50,y = 550)logBox = LoggerBox(window, width=90,height=10)logBox.place(x=50,y=600)self.log = logging.getLogger("log")self.log.setLevel(logging.INFO)handler = logging.StreamHandler(logBox)self.log.addHandler(handler)def select_dir(self,dir):dir.set(filedialog.askdirectory())def parse_file(self):try:parser = FileParser()parser.batchParseDataFile(self.data_str.get(),self.log,self.start_date.get(),self.end_date.get(),self.date_format.get(),self.source_dir.get(),self.target_dir.get(),self.suffix.get(),self.data_sep.get(),self.data_start_row.get(),self.data_end_flag.get(),self.start_row.get(),self.start_col.get())except  Exception as e:messagebox.showinfo('错误信息',e)if __name__=="__main__":window = tk.Tk()app = APP(window)window.mainloop()

本文由【产品经理不是经理】gzh 同步发布,欢迎关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/789724.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vue ElementPlus Input 输入框

Input 输入框 通过鼠标或键盘输入字符 input 为受控组件&#xff0c;它总会显示 Vue 绑定值。 通常情况下&#xff0c;应当处理 input 事件&#xff0c;并更新组件的绑定值&#xff08;或使用v-model&#xff09;。否则&#xff0c;输入框内显示的值将不会改变&#xff0c;不支…

异构加速GPU服务器设计方案:904-全国产化异构加速GPU服务器

全国产化异构加速GPU服务器 一、产品介绍 X7340H0是中科可控基于HYGON系列处理器开发的一款全新高端2U双路GPU服务器。X7340H0采用优异的可扩展架构设计&#xff0c;支持高密度扩展GPU加速卡&#xff0c;为深度学习推理场景提供更加安全可靠、高性价比的解决方案。 性能卓越 ●…

经典文献阅读之--LOG-LIO(高效局部几何信息估计的激光雷达惯性里程计)

0. 简介 局部几何信息即法线和点分布在基于激光雷达的同时定位与地图构建&#xff08;SLAM&#xff09;中是至关重要&#xff0c;因为它为数据关联提供了约束&#xff0c;进一步确定了优化方向&#xff0c;最终影响姿态的准确性。然而即使在使用KD树或体素图的辅助下&#xff…

【CANN训练营笔记】AscendCL图片分类应用(C++实现)

样例介绍 基于PyTorch框架的ResNet50模型&#xff0c;对*.jpg图片分类&#xff0c;输出各图片所属分类的编号、名称。 环境介绍 华为云AI1s CPU&#xff1a;Intel Xeon Gold 6278C CPU 2.60GHz 内存&#xff1a;8G NPU&#xff1a;Ascend 310 环境准备 下载驱动 wget ht…

在 Windows 中安装部署并启动连接 MongoDB 7.x(命令行方式启动、配置文件方式启动、将启动命令安装为系统服务实现开机自启)

MongoDB 的下载 下载地址&#xff1a;https://www.mongodb.com/try/download/community 这里需要对 MongoDB 的版本号说明一下&#xff1a; MongoDB 版本号的命名规则是 x.y.z&#xff0c;当其中的 y 是奇数时表示当前的版本为开发版&#xff0c;当其中的 y 是偶数时表示当前的…

非关系型数据库之Redis配置与优化

一、关系数据库与非关系型数据库 1.1关系型数据库 关系型数据库是一个结构化的数据库&#xff0c;创建在关系模型&#xff08;二维表格模型&#xff09;基础上一般面向于记录。SQL语句&#xff08;标准数据查询语言&#xff09;就是一种基于关系型数据库的语言&#xff0c;用…

首场直播,就在4月11日!

2024年的第一场直播&#xff0c;我们把目光聚焦到“大会员”。 这一次我们想聊聊&#xff0c;当大会员遇上泛零售企业&#xff0c;会产生怎样的“火花”。泛零售企业突破增长压力的机会在哪里&#xff1f;又有哪些挑战必须直面&#xff1f; 本次直播将结合泛零售企业“多业态、…

GEE问题——在使用sentienl数据云掩膜的时候发现出现中间连贯性的“条带”问题,如何解决?

简介 在使用sentienl+landsat数据掩膜的时候发现出现了中间连贯性的条带问题,如何解决?这里我们使用GEE出品的Landsat和sentinel数据的过程中,当我们进行云掩膜的时候出现了条带的问题。 问题 您注意到这个问题了吗? 我该如何消除它们(例如,在镶嵌前遮蔽瓦片最外层的 …

1379. 找出克隆二叉树中的相同节点

说在前面 &#x1f388;不知道大家对于算法的学习是一个怎样的心态呢&#xff1f;为了面试还是因为兴趣&#xff1f;不管是出于什么原因&#xff0c;算法学习需要持续保持。 题目描述 给你两棵二叉树&#xff0c;原始树 original 和克隆树 cloned&#xff0c;以及一个位于原始…

UniApp 应用发布到苹果商店指南

&#x1f680; 想要让你的 UniApp 应用在苹果商店亮相吗&#xff1f;别着急&#xff0c;让我来带你一步步完成这个重要的任务吧&#xff01;在这篇博客中&#xff0c;我将详细介绍如何将 UniApp 应用顺利发布到苹果商店&#xff0c;让你的应用跻身于苹果生态之中。 引言 &…

高德定位 SDK 到底提供了什么服务?

最近我被高德的销售烦到不行&#xff0c;说是我用了他们的 SDK&#xff0c;现在 SDK 要收费。 表达是很绕的&#xff0c;什么授权啦&#xff0c;什么企业认证风险啦&#xff0c;讲了一堆&#xff0c;还跟我开始搬出协议了。感觉高德的销售真够垃圾的&#xff0c;编个话术都不会…

Lua环境下载与配置

这里介绍如何下载已经编译好的Lua环境&#xff0c;如何配置Lua环境。 如希望自己从源码编译Lua环境&#xff0c;请自行搜索资料。 第一步&#xff1a;下载编译好的lua环境 打开下面链接&#xff0c;然后根据指引下载。 The Programming Language Luahttps://www.lua.org/hom…

windows下基于python语言的TTS开发

AI应用开发相关目录 本专栏包括AI应用开发相关内容分享,包括不限于AI算法部署实施细节、AI应用后端分析服务相关概念及开发技巧、AI应用后端应用服务相关概念及开发技巧、AI应用前端实现路径及开发技巧 适用于具备一定算法及Python使用基础的人群 AI应用开发流程概述Visual St…

算法打卡day33|动态规划篇01|动态规划理论基础| Leetcode 509. 斐波那契数、70. 爬楼梯、746. 使用最小花费爬楼梯

动态规划理论 定义 动态规划(Dynamic Programming&#xff0c;简称DP)&#xff0c;主要用于解决多阶段决策问题。它的核心思想是将一个复杂的多阶段问题转化为一系列相对简单的单阶段问题&#xff0c;然后逐一求解这些单阶段问题&#xff0c;最后将这些单阶段问题的解合并&…

坦克大战_java源码_swing界面_带毕业论文

一. 演示视频 坦克大战_java源码_swing界面_带毕业论文 二. 实现步骤 完整项目获取 https://githubs.xyz/y22.html 部分截图 启动类是 TankClinet.java&#xff0c;内置碰撞检测算法&#xff0c;线程&#xff0c;安全集合&#xff0c;一切皆对象思想等&#xff0c;是java进阶…

【vue2+antvx6】报错Cannot read properties of undefined (reading ‘toUpperCase‘)

我的代码是这样的 <el-collapseref"collapse"v-model"active"accordionclass"collapseStart"change"collapsechange"><el-collapse-item:name"String(index 1)"v-for"(i, index) in List":key"in…

杂货铺 | 使用 Github Pages 和 Hexo 搭建自己的独立博客

文章目录 &#x1f4da;Step1&#xff1a;安装Node.js和Git&#x1f4da;Step2&#xff1a;安装并初始化配置Hexo&#x1f4da;Step3&#xff1a;本地查看效果&#x1f4da;Step4&#xff1a;将博客部署到Github Pages上&#x1f407;创建项目代码库&#x1f407;配置SSH密钥&a…

本题解答错误----暂做记录----130. 被围绕的区域

130. 被围绕的区域 原题链接&#xff1a;完成情况&#xff1a;解题思路&#xff1a;参考代码&#xff1a;_130被围绕的区域_dfs_130被围绕的区域_bfs_01 错误经验吸取 原题链接&#xff1a; 添加链接描述130. 被围绕的区域 https://leetcode.cn/problems/surrounded-regions…

JavaSE:抽象类和接口

目录 一、前言 二、抽象类 &#xff08;一&#xff09;抽象类概念 &#xff08;二&#xff09;使用抽象类的注意事项 &#xff08;三&#xff09;抽象类的作用 三、接口 &#xff08;一&#xff09;接口概念 &#xff08;二&#xff09;接口语法规则 &#xff08;三&a…

视频创作者必备应用!三步帮你解决前置内容条件,打造专属大片!

你还没尝试过AI视频生成&#xff1f;AI技术逐渐浸透我们的生活&#xff0c;太多的事物变得有了捷径可走。AI视频生成为创作者们提供更加便利快捷的输出形式&#xff0c;更优质更契合的生产内容。尝试AI视频生成系列应用&#xff0c;迎接AI宇宙&#xff01; 生成剧本分镜 视频…