1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
|
import win32com.client as win32 import datetime import os import re import tkinter.messagebox import math import pandas as pd from openpyxl import load_workbook from openpyxl import Workbook from tkinter import Tk from tkinter.filedialog import askopenfilename
#function : 欄位、行號轉成A1 A2 A3....格式 def col_name(col,row): arr = ["","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"] n = math.floor(col/26) l = col % 26 return "%s%s%s" % (arr[n],arr[l],row)
#function : 讀取excel def win32_read_excel(): print("讀取資料中[win32_read_excel]") #開啟檔案 wb = excel.Workbooks.Open(full_path)
#從第一個工作頁開始抓資料 for i in range(1,wb.Sheets.Count+1): #目前工作頁 sh = wb.Sheets(i) #工作頁名稱 sheet_name = sh.Name #將舊資料工作頁名稱寫到new_data變數 new_data[sheet_name] = [] #取得目前使用的欄數與行數 used = sh.UsedRange nrows = used.Row + used.Rows.Count - 1 ncols = used.Column + used.Columns.Count - 1 #取得所有資料,並寫入new_data for row in range(1,nrows +1): for col in range(1,ncols +1): value = sh.Cells(row,col).Formula #取得欄位公式(包含文字) #value = sh.Cells(row,col).Value #取得欄位公式(包含文字) if len(value) > 0: #如果欄位有資料則寫入到new_data目錄內 #print("==>",value) #if value: new_data[sheet_name].append([row,col,value]) # if show_message : print("讀出資料 : [%s] %s : %s " % (sheet_name,col_name(col,row),value))
#關閉excel excel.Application.Quit()
#function : win32com寫入檔案 def write_new_exel_by_win32com(): print("寫入資料中[write_new_exel_by_win32com]") #新增excel wb = excel.Workbooks.Add() #工作頁變數 ws = {} #將資料寫入新excel內 for sheet_idx,i in enumerate(range(len(new_data)-1,-1,-1)): if sheet_idx == 0: ws[i] = wb.Sheets(1) else: ws[i] = wb.Worksheets.Add() sheet_name = list(new_data)[i] ws[i].Name = sheet_name for j in new_data[sheet_name]: row,col,val = j #ws[i].Cells(row,col).Formula = val ws[i].Cells(row,col).Value = val if show_message : print("寫入資料 : [%s] %s : %s " % (sheet_name,col_name(col,row),val)) #存檔 wb.SaveAs(now_path+new_file_name, FileFormat = 51) #關閉excel excel.Application.Quit() #已完成訊息 pop_message("通知","資料已寫入檔案 : %s " % (new_file_name))
#function : 透過openpyxl寫入檔案 def write_new_exel_by_openpyxl(): print("寫入資料中[write_new_exel_by_openpyxl]") #新增excel wb = Workbook() #工作頁變數 ws = {} #將資料寫入新excel內 for sheet_idx,i in enumerate(range(0,len(new_data))): if sheet_idx == 0: ws[i] = wb.active else: ws[i] = wb.create_sheet()
sheet_name = list(new_data)[i] ws[i].title = sheet_name
for j in new_data[sheet_name]: row,col,val = j ws[i].cell(row=row, column=col).value = val if show_message : print("寫入資料 : [%s] %s : %s " % (sheet_name,col_name(col,row),val)) # Save the file wb.save(now_path+new_file_name) #已完成訊息 pop_message("通知","資料已寫入檔案 : %s " % (new_file_name))
#function : def pandas_xls_to_xlsx(): print("轉檔中[pandas_xls_to_xlsx]")
xls = pd.ExcelFile(full_path) with pd.ExcelWriter(new_file_name) as writer: for sheet_name in xls.sheet_names: data = xls.parse(sheet_name,header = None) data.to_excel(writer,sheet_name=sheet_name,index=None,header=None)
#function : def openpyxl_remove_object(): #使用openpyxl 讀取excel print("讀取資料中[openpyxl_remove_object]") wb = load_workbook(full_path)
#寫入新excel print("寫入資料中[openpyxl_remove_object]") wb.save(filename = new_file_name)
#顯示視窗通知已完成 #tkinter.messagebox.showinfo("通知",("資料已寫入檔案 : %s " % (new_file_name))) pop_message("通知","資料已寫入檔案 : %s " % (new_file_name))
#function : def pop_message(title,message): tkinter.messagebox.showinfo(title,message)
#function : 選擇檔案對話框 def select_file(): #initialdir 指定開啟選擇檔案路徑,讀取作業系統哪個目錄(可以刪除不使用預設就直接讀windows的文件目錄) return askopenfilename(initialdir = now_path,title = "讀取excel檔",filetypes = (("xls","*.xls"),("xlsx","*.xlsx")))
############################################################
#取得目前程式位置 now_path = os.getcwd().replace('\'','/') + '/'
#新資料 new_data = {}
#執行時顯示資料 show_message = False # True 和 False
#從xls to xlsx是否需要保留公式? need_formula = True # True or False
#選擇從xls to xlsx要寫入的function 請輸入 1 或 2 #(1)write_new_exel_by_win32com() ==> 文字、公式一併寫入,但速度慢 #(2)write_new_exel_by_openpyxl() ==> 文字、公式一併寫入,速度快,可是=today()公式有問題,但sum正常,其他未知 need_formula_def = 2 # 1 或 2
#是否執行的變數 run = True
#開啟對話框選擇要讀取的excel檔案 Tk().withdraw()
#開始選擇檔案對話框 while True: file_name = re.split("/",select_file())[-1] if file_name: #如果有選擇檔案則跳出while迴圈繼續程式 break select = tkinter.messagebox.askquestion('通知', '沒選擇檔案,是否重新選擇檔案?') if select == "no": #沒選擇檔案,並且按下N後則會退出程式 run = False break
#開始執行程式 if run: print("程式執行中...") #今天日期 today = datetime.datetime.today().strftime("%Y-%m-%d")
#完整路徑 full_path = now_path + file_name #副檔名 file_type = re.split("\.",file_name)[1] #將舊檔名加上今天日期成為新檔案名稱 : 舊檔名_2020_09_19.xlsx new_file_name = re.split("\.",file_name)[0] + "_" + today + ".xlsx" #開始執行時間 start = datetime.datetime.now() #檔案格式為xls取出所有資料後,寫入格式為xlsx的空白excel檔內 if file_type == "xls": if need_formula: #呼叫excel excel = win32.gencache.EnsureDispatch('Excel.Application') #讀取excel資料 win32_read_excel()
#寫入新excel if need_formula_def == 1 : write_new_exel_by_win32com() elif need_formula_def == 2 : write_new_exel_by_openpyxl() else: pop_message("通知","請指定數值給變數 need_formula_def : 1或2") os._exit() else: #使用pandas轉xls to xlsx很快速,但是公式都會變成結果文字(如日期=today() 就變成日期文字) pandas_xls_to_xlsx() #檔案格式為xlsx或其他,寫入格式為xlsx的空白excel檔內 else: #使用openpyxl 移除object openpyxl_remove_object() #程式結束時間 end = datetime.datetime.now() print("執行時間 : %.2f 秒" % (end-start).seconds) |