Python creates corrupt files of excel when I run my code. How can I save the files without corrupting the file?

huangapple go评论76阅读模式
英文:

Python creates corrupt files of excel when I run my code. How can I save the files without corrupting the file?

问题

我正在尝试编写一个Python代码,它主要比较两个Excel文件中的4个特定命名相同的工作表。在比较后,如果有差异,它将替换这些值,否则它将不执行任何操作并继续向前进行。下一步是运行Excel文件中的宏。一旦循环完成,将创建一个新的Excel文件,然后我必须用一个名为"reconciliation"的新文件中的两个工作表替换它们。

听起来像是简单的Python编码,然而,我在第一部分卡住了,因为我的Python代码创建了一个完全损坏且无法打开的文件,错误消息如下:
Python creates corrupt files of excel when I run my code. How can I save the files without corrupting the file?

这是我正在使用的代码。

import openpyxl as xl
import tkinter as tk
from tkinter import filedialog
import os

root = tk.Tk()
root.withdraw()

# 打开文件对话框选择Excel文件
file_path1 = filedialog.askopenfilename(title='选择第一个Excel文件', filetypes=[('Excel files', '*.xlsm')])
file_path2 = filedialog.askopenfilename(title='选择第二个Excel文件', filetypes=[('Excel files', '*.xlsm')])

wb1 = xl.load_workbook(file_path1, keep_vba=True)
wb2 = xl.load_workbook(file_path2, keep_vba=True)

for sheet_name in wb1.sheetnames:
    sheet1 = wb1[sheet_name]
    sheet2 = wb2[sheet_name]
    max_row = max(sheet1.max_row, sheet2.max_row)
    max_col = max(sheet1.max_column, sheet2.max_column)
    for row in range(1, max_row+1):
        for col in range(1, max_col+1):
            cell1 = sheet1.cell(row=row, column=col).value
            cell2 = sheet2.cell(row=row, column=col).value
            if cell1 != cell2:
                answer = input(f"是否要用第一个文件中的'{sheet_name}'工作表替换第二个文件中的工作表? (Y/N) ")
                if answer.lower() == 'y':
                    new_sheet = wb2.create_sheet(title=sheet_name)
                    for row in sheet1.iter_rows(values_only=True):
                        new_sheet.append(row)
                    new_sheet.title = sheet_name
                    del wb2[sheet_name]
                break
        else:
            continue
        break

file_name, file_ext = os.path.splitext(file_path1)
new_file_path = file_name + "_updated.xlsm"

new_workbook = xl.Workbook()

for sheet_name in wb1.sheetnames:
    sheet = wb1[sheet_name]
    new_sheet = new_workbook.create_sheet(sheet_name)
    for row in sheet.iter_rows():
        new_row = []
        for cell in row:
            new_row.append(cell.value)
        new_sheet.append(new_row)

new_workbook.save(new_file_path)

我尝试了很多解决方法,比如不创建一个新文件,让代码覆盖原始文件。然而,似乎我的比较和替换代码正在搞乱Excel文件。它还会损坏原始文件。我将不胜感激任何指点。我在网上和StackOverflow上搜索了类似的问题,但他们的解决方案对我的问题不起作用。

英文:

I'm trying to write a python code that essentially compares two excel files in 4 specific spreadsheets named the same in both files. After comparing, it will replace the values if there are differences, otherwise it will do nothing and proceed onwards. The next step is to run a macro that is within the excel file. Once the loop is done, a new excel file is created and from there I must replace two spreadsheets with those in a new file called "reconciliation."

It sounds like simple python coding, however, I'm stuck at the first part because my python code is creating a file that is completely corrupted and not openable with the error message:
Python creates corrupt files of excel when I run my code. How can I save the files without corrupting the file?

Here is my code that I'm working with.

import openpyxl as xl
import tkinter as tk
from tkinter import filedialog
import os
root = tk.Tk()
root.withdraw()
# open file dialogs to select the excel files
file_path1 = filedialog.askopenfilename(title='Select the first Excel file',
filetypes=[('Excel files', '*.xlsm')])
file_path2 = filedialog.askopenfilename(title='Select the second Excel file',
filetypes=[('Excel files', '*.xlsm')])
wb1 = xl.load_workbook(file_path1, keep_vba=True)
wb2 = xl.load_workbook(file_path2, keep_vba=True)
for sheet_name in wb1.sheetnames:
sheet1 = wb1[sheet_name]
sheet2 = wb2[sheet_name]
# get the number of rows and columns in the worksheet
max_row = max(sheet1.max_row, sheet2.max_row)
max_col = max(sheet1.max_column, sheet2.max_column)
# loop through each row in the worksheet
for row in range(1, max_row+1):
# loop through each cell in the row
for col in range(1, max_col+1):
# get the values of the corresponding cells in the two worksheets
cell1 = sheet1.cell(row=row, column=col).value
cell2 = sheet2.cell(row=row, column=col).value
if cell1 != cell2:
# if the values are different, ask the user if they want to replace the sheet
answer = input(f"Do you want to replace the sheet '{sheet_name}' in the second file with the sheet from the first file? (Y/N) ")
if answer.lower() == 'y':
new_sheet = wb2.create_sheet(title=sheet_name)
for row in sheet1.iter_rows(values_only=True):
new_sheet.append(row)
new_sheet.title = sheet_name
del wb2[sheet_name]
# break out of the loops, since a difference has already been found
break
else:
# continue to the next row
continue
# break out of the loops, since we already found a difference
break
file_name, file_ext = os.path.splitext(file_path1)
new_file_path = file_name + "_updated.xlsm"
new_workbook = xl.Workbook()
for sheet_name in wb1.sheetnames:
sheet = wb1[sheet_name]
new_sheet = new_workbook.create_sheet(sheet_name)
for row in sheet.iter_rows():
new_row = []
for cell in row:
new_row.append(cell.value)
new_sheet.append(new_row)
new_workbook.save(new_file_path)
# Run the Macro2 in the updated Excel file
# xl = win32.Dispatch("Excel.Application")
# xl.Visible = True
# xl.Workbooks.Open(new_file_path)
# xl.Application.Run("Macro2")
# xl.ActiveWorkbook.Close(SaveChanges=True)
# xl.Quit()
#if input == "y":
#    print("'{sheet_name}' values replaced and new file saved as {}".format(sheet_name, new_file_path))
#else:
#    print("No changes were made")

I've tried numerous workarounds such as not creating a new file and having the code overwrite the original files. However it seems that my code of comparing and replacing is messing up with the excel files. It will also corrupt the original files.
I would appreciate any pointers. I've searched online and on stackoverflow for similar issues but their solutions do not work for mine.

答案1

得分: 1

你是否不想在创建新表之前删除旧表?

而不是这样:

new_sheet = wb2.create_sheet(title=sheet_name)
for row in sheet1.iter_rows(values_only=True):
    new_sheet.append(row)
new_sheet.title = sheet_name
del wb2[sheet_name]

难道你不应该这样做:

del wb2[sheet_name]
new_sheet = wb2.create_sheet(title=sheet_name)
for row in sheet1.iter_rows(values_only=True):
    new_sheet.append(row)
new_sheet.title = sheet_name

假设这不能解决你的问题,你是否尝试将新表写入一个额外的表格,用于测试目的?

new_sheet = wb2.create_sheet(title="TEST " + sheet_name)
for row in sheet1.iter_rows(values_only=True):
    new_sheet.append(row)
new_sheet.title = "TEST " + sheet_name

如果在创建时已经指定了表格名称,为什么还需要写入 new_sheet.title?

英文:

Don't you want to delete the old sheet before you create the new?

Instead of this:

                new_sheet = wb2.create_sheet(title=sheet_name)
for row in sheet1.iter_rows(values_only=True):
new_sheet.append(row)
new_sheet.title = sheet_name
del wb2[sheet_name]

Shouldn't you have this:

                del wb2[sheet_name]                    
new_sheet = wb2.create_sheet(title=sheet_name)
for row in sheet1.iter_rows(values_only=True):
new_sheet.append(row)
new_sheet.title = sheet_name

Assuming that doesn't fix your problem, have you tried writing the new sheet to an EXTRA sheet, for testing purposes?

                new_sheet = wb2.create_sheet(title="TEST "&sheet_name)
for row in sheet1.iter_rows(values_only=True):
new_sheet.append(row)
new_sheet.title ="TEST "& sheet_name

Why even do you need to write new_sheet.title if you have prespecified the sheet name when you created it?

答案2

得分: 0

代替原始的代码块保存新文件,这个替代方法似乎可以解决问题:

# 创建并保存更新的文件
new_file_path = file_path1 + "_updated.xlsm"
shutil.copyfile(file_path1, new_file_path)

确保首先导入 shutil。

英文:

Instead of the original block of code to save a new file, this alternative seems to fix the issue:

# create and save an updated file 
new_file_path = file_path1 + "_updated.xlsm"
shutil.copyfile(file_path1, new_file_path)

Make sure to import shutil first

huangapple
  • 本文由 发表于 2023年2月27日 19:31:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/75579915.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定