• 4

各位好,我又來了,我遇到一個奇怪的狀況,全選複製就當機。

shibuy wrote:
稻草人到處草人大大其(恕刪)


原來還可以用這種方式做成bat檔

這麼便捷的話肯定用得到的

感謝

我會學來用的

laurent5680 wrote:
真的office很耗(恕刪)


Basic的歷史比windows長得多

會去怪basic真的是無可名狀
srwe wrote:
Basic的歷史比windows...(恕刪)


我是認為任何一種程式碼一定都有它存在的理由跟價值,不然不會被創造出來

VB除了感覺上似乎跟其他語法差距較遠以外,使用上也算是相當有趣的語法,如果真的這麼糟糕應該早就被淘汰了

特殊的用途應該要使用對應的工具才是,常聽到動輒十萬筆資料的內容應該要使用資料庫而非EXCEL....

所以應該是工具選擇造成的問題而非微軟軟體本身

當然BUG例外
稻草人到處草人 wrote:
我是認為任何一種程式(恕刪)


BASIC全名是Beginners' All-purpose Symbolic Instruction Code,直譯就是初學者的全功能符號化指令碼(美國人真的很會搞這種首字母縮寫),會和其他語言不同是因為BASIC是直譯式的語言,由直譯器一句句的執行,所以和JAVA之類要編譯的語言不一樣,運行效率也相對較差

BASIC由1964年開始始終都是面向初學者的高階語言,OFFICE的VBA只是一個工具語言令使用者可以自行定義自動化功能

甚麼可能扯到WINDOWS身上?windows又不是用VB.net寫的
shibuy wrote:

from openpyxl import load_workbook
from tkinter import Tk
from tkinter.filedialog import askopenfilename
import tkinter.messagebox
import os


報告Shibuy大:
按照S大說法做了以上操作之後,系統提示了這個訊息
---
openpyxl.utils.exceptions.InvalidFileException: openpyxl does not support the old .xls file format, please use xlrd to read this file, or convert it to the more recent .xlsx file format.
C:\Users\abc\Desktop\PythonTest>pause
---
因此我想大概是xlrd才能支援xls
因此我又去安裝了相關套件之後,將所bat以及py檔全都指定給xlrd來開啟
結果出現的是下列訊息
---
Traceback (most recent call last):
File "read_excel_xlrd.py", line 2, in <module>
from xlrd import load_workbook
ImportError: cannot import name 'load_workbook' from 'xlrd' (C:\Users\abc\AppData\Local\Programs\Python\Python38\lib\site-packages\xlrd\__init__.py)
---
但我就算找了一些關於 import Error的解法也不太確定該從哪裡下手

可否請S大指教一二

感謝
稻草人到處草人 wrote:
報告Shibuy大:(恕刪)

我試著用了一個奇怪的程式將xls轉成xlsx(不過以過多透明物件的檔案來說即便用了python仍算有點花時間)
---
import win32com.client as win32

fname = "D:\\0\\9.xls"
excel = win32.gencache.EnsureDispatch('Excel.Application')
wb = excel.Workbooks.Open(fname)

wb.SaveAs(fname+"x", FileFormat = 51) #FileFormat = 51 is for .xlsx extension
wb.Close() #FileFormat = 56 is for .xls extension
excel.Application.Quit()
---
成功轉成xlsx之後,測試對象檔案容量從9297K先縮小成了3642K
之後再進行S大的檔案轉檔之後
出現了權限錯誤的訊息
---
Traceback (most recent call last):
File "read_excel_openpyxl.py", line 35, in <module>
wb.save(filename = file_name)
File "C:\Users\abc\AppData\Local\Programs\Python\Python38\lib\site-packages\openpyxl\workbook\workbook.py", line 392, in save
save_workbook(self, filename)
File "C:\Users\abc\AppData\Local\Programs\Python\Python38\lib\site-packages\openpyxl\writer\excel.py", line 291, in save_workbook
archive = ZipFile(filename, 'w', ZIP_DEFLATED, allowZip64=True)
File "C:\Users\abc\AppData\Local\Programs\Python\Python38\lib\zipfile.py", line 1251, in __init__
self.fp = io.open(file, filemode)
PermissionError: [Errno 13] Permission denied: 'D:/0/9.xlsx'

D:\0>pause
---
用管理員權限啟動仍然沒幫助,目前卡住了。
稻草人到處草人 wrote:
我試著用了一個奇怪的(恕刪)

稻草人到處草人大大

==================== 更新 ====================
出現 permission deied 應該是檔案已經被其他程式開啟,但是在背景執行,
然後無法再複寫的錯誤訊息!
所以只要去工作管理員找到excel,關閉即可!
=============================================

我重新修改程式,流程如下 :
ps.請先在dos視窗執行 pip install pandas 安裝pandas模組

1.讀取檔案
2.判斷檔案格式是xls or xlsx
3.是xls則是否需要公式?
4.將結果寫入到新檔案 : "舊檔名_2020_09_20.xlsx"

因為xls 轉 xlsx如果都是用win32com轉沒有公式問題
但是透過openpyxl日期會出錯,但是sum正常,其它公式我就沒測試
不過因為openpyxl轉存速度比win32快很多因此請依照您的需求修改 :

(A)xls需要正確公式,請設定(寫入速度慢):
  need_formula = True
  need_formula_def = 1

(B)xls需要公式,請設定(寫入速度快,但可能部分公式有問題):
  need_formula = True
  need_formula_def = 2

(C)xls不需要公式,請設定(寫入速度快):
  need_formula = False

(D)xlsx 移除空白物件並不會有公式問題所以依照xls需求設定即可

169
170
171
172
173
174
175

#從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


更新的程式碼
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)
shibuy wrote:
稻草人到處草人大大=(恕刪)


后里穴!!

Shibuy大你嚇到我了!

後來確實我有找到那個excel在背景執行的問題並且解決掉,只是忘了上來回報了

沒想到S大又更新了整個程式

真的是太佩服太感謝了

確實也是有遇到S大提到的執行時間的問題

速度上來說其實是還能接受的,畢竟最重要的excel程式在python跑的過程中還是可以另外執行其他動作,這點確實差很多

但這個被優化過的程式感覺一看就覺得非常優秀啊……

等不及明天試試看了

感謝S大這麼熱心特地寫了這麼縝密的程式給我

謝謝!!

shibuy wrote:
稻草人到處草人大大=(恕刪)


報告shibuy大,程式測試結果非常的好用,因為我的檔案正常情況下不需要也不會有任何公式存在,純資料,
因此都選擇最快的程序去處理就行了,處理的結果非常優秀,速度極快,幾秒內就匯出乾淨的新檔案了

真的是太感謝S大了



獻上我的膝蓋
稻草人到處草人 wrote:
報告shibuy大,(恕刪)

稻草人到處草人大大
有bug再跟我說
  • 4
內文搜尋
X
評分
評分
複製連結
Mobile01提醒您
您目前瀏覽的是行動版網頁
是否切換到電腦版網頁呢?