<think>我们遇到了一个错误:`Exception: Attempt to overwrite cell: sheetname=u'存储对比' rowx=2 colx=0`。这个错误发生在写入Excel文件时,表明我们试图在同一个单元格(第2行,第0列)重复写入。
分析原因:
在之前的修复中,我们尝试为每个单元格设置样式,但是写入逻辑存在重复写入的问题。具体来说,我们在两个地方写入了同一个单元格:
1. 首先,在循环中写入每个单元格的值(不带样式):
```python
for col_idx, value in enumerate(row_data):
ws.write(row_idx, col_idx, value)
```
2. 然后,在检查到差异百分比大于10%或小于-10%时,我们又为整行的每个单元格重新写入(带样式):
```python
for col in range(5):
cell_style = ...
ws.write(row_idx, col, row_data[col], cell_style)
```
这样,对于差异显著的单元格,我们实际上写入了两次:第一次不带样式,第二次带样式。但是,xlwt不允许对同一个单元格重复写入(除非使用覆盖模式,但默认不允许)。
解决方案:
我们可以调整写入逻辑,确保每个单元格只写入一次。具体做法是:先判断这一行是否需要高亮,然后决定写入时是否带样式。
修改后的写入逻辑:
1. 对于每一行,先判断差异百分比是否满足高亮条件(>10% 或 <-10%)。
2. 如果需要高亮,则整行使用带背景色的样式写入;否则,正常写入(不带背景色)。
具体步骤:
- 将内层循环(写入一行中的每个单元格)改为:先检查该行是否需要高亮,然后为每个单元格设置相应的样式。
- 注意:为了避免重复创建样式对象(可能超出xlwt的样式数量限制),我们可以提前创建两个样式:红色背景和绿色背景,以及一个普通样式(无背景色)。但是,由于我们可能有很多行,且样式只有三种(红色、绿色、普通),我们可以提前创建好这三个样式。
修改代码:
步骤1:在循环外部创建三个样式对象(普通、红色、绿色):
```python
# 创建样式
normal_style = xlwt.easyxf() # 普通样式
red_style = xlwt.easyxf('pattern: pattern solid, fore_colour rose')
green_style = xlwt.easyxf('pattern: pattern solid, fore_colour light_green')
```
步骤2:在写入每一行之前,判断该行的差异百分比(注意:差异百分比在row_data的第4列,即索引4):
```python
# 判断该行是否需要高亮
diff_pct = row_data[4] # 第5列(索引4)是差异百分比
if isinstance(diff_pct, (int, float)):
if diff_pct > 10:
style = red_style
elif diff_pct < -10:
style = green_style
else:
style = normal_style
else:
style = normal_style
```
步骤3:然后,在写入该行的每个单元格时,使用同一个样式(整行使用同一种背景色):
```python
for col_idx, value in enumerate(row_data):
ws.write(row_idx, col_idx, value, style)
```
这样,每个单元格只写入一次,且整行使用相同的背景色(如果需要高亮)。
完整修改后的代码段(从创建样式到写入数据):
```python
# 创建样式
normal_style = xlwt.easyxf() # 普通样式
red_style = xlwt.easyxf('pattern: pattern solid, fore_colour rose')
green_style = xlwt.easyxf('pattern: pattern solid, fore_colour light_green')
# 写入数据
for row_idx, row_data in enumerate(report_data, start=1):
# 判断该行是否需要高亮
diff_pct = row_data[4] # 第5列(索引4)是差异百分比
if isinstance(diff_pct, (int, float)):
if diff_pct > 10:
style = red_style
elif diff_pct < -10:
style = green_style
else:
style = normal_style
else:
style = normal_style
# 写入一行中的每个单元格
for col_idx, value in enumerate(row_data):
ws.write(row_idx, col_idx, value, style)
```
这样修改后,每个单元格只写入一次,避免了重复写入的问题。
另外,我们还需要注意:在之前的代码中,我们在写入标题行时已经使用了`header_style`,所以标题行不受影响。
完整修改后的`generate_comparison_report`函数(仅修改Excel写入部分)如下:
```python
# 创建Excel工作簿
try:
wb = xlwt.Workbook(encoding='utf-8')
ws = wb.add_sheet('存储对比')
# 设置列宽
ws.col(0).width = 256 * 60 # 路径列宽
for i in range(1, 5):
ws.col(i).width = 256 * 15 # 其他列宽
# 设置标题行
headers = ['路径', '机器1大小(KB)', '机器2大小(KB)', '差值(KB)', '差异百分比(%)']
header_style = xlwt.easyxf('font: bold on')
for col, header in enumerate(headers):
ws.write(0, col, header, header_style)
# 创建数据行样式
normal_style = xlwt.easyxf() # 普通样式
red_style = xlwt.easyxf('pattern: pattern solid, fore_colour rose')
green_style = xlwt.easyxf('pattern: pattern solid, fore_colour light_green')
# 写入数据
for row_idx, row_data in enumerate(report_data, start=1):
# 判断该行是否需要高亮
diff_pct = row_data[4] # 第5列(索引4)是差异百分比
if isinstance(diff_pct, (int, float)):
if diff_pct > 10:
style = red_style
elif diff_pct < -10:
style = green_style
else:
style = normal_style
else:
style = normal_style
# 写入一行中的每个单元格
for col_idx, value in enumerate(row_data):
ws.write(row_idx, col_idx, value, style)
# 保存文件
wb.save(output_xlsx)
return "对比报告已成功生成: {}".format(output_xlsx)
```
这个修改应该能解决“Attempt to overwrite cell”错误。
注意:由于我们不再分别写入两次,所以高亮逻辑也改为整行高亮(而不是之前只高亮差异百分比列)。这样更直观。
如果问题仍然存在,请检查是否还有其他地方重复写入同一个单元格,但根据代码逻辑,现在每个单元格只写入一次。
请尝试使用修改后的代码运行。</think>### 解决Excel写入冲突错误
错误信息 `Attempt to overwrite cell: sheetname=u'存储对比' rowx=2 colx=0` 表示在Excel写入过程中尝试覆盖已存在的单元格。以下是完整的修复方案:
```python
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import re
import sys
import xlwt
from collections import defaultdict
def parse_du_file(file_path):
"""解析du命令输出文件"""
data = {}
try:
with open(file_path, 'r') as f:
for line in f:
if 'Permission denied' in line or 'No such file' in line or not line.strip():
continue
match = re.match(r'(\d+\.?\d*)\s*([KMG]?)[Bb]?\s+(.*)', line.strip())
if match:
size, unit, path = match.groups()
size = float(size)
# 单位转换
if unit == 'M': size *= 1024
elif unit == 'G': size *= 1024*1024
elif unit == '': size = size/1024
data[path] = round(size, 2)
except IOError as e:
print("警告: 无法读取文件 {}: {}".format(file_path, str(e)))
return data
def generate_comparison_report(folder1, folder2, output_xlsx):
"""生成存储对比报告"""
# 验证文件夹是否存在
for folder in [folder1, folder2]:
if not os.path.exists(folder):
print("错误: 目录不存在 - {}".format(folder))
return "目录 {} 不存在,请检查路径".format(folder)
if not os.path.isdir(folder):
print("错误: 路径不是目录 - {}".format(folder))
return "{} 不是有效目录".format(folder)
machine1_data = defaultdict(float)
machine2_data = defaultdict(float)
# 收集数据
for folder_path, data_dict in [(folder1, machine1_data), (folder2, machine2_data)]:
print("处理目录: {}".format(folder_path))
try:
for file in os.listdir(folder_path):
if file.endswith('.txt'):
file_path = os.path.join(folder_path, file)
print("解析文件: {}".format(file_path))
data_dict.update(parse_du_file(file_path))
except OSError as e:
print("目录访问错误: {}".format(str(e)))
return "无法访问目录 {}: {}".format(folder_path, str(e))
# 准备对比数据
all_paths = set(machine1_data.keys()) | set(machine2_data.keys())
report_data = []
for path in all_paths:
size1 = machine1_data.get(path, 0.0)
size2 = machine2_data.get(path, 0.0)
diff = size2 - size1
if size1 != 0:
diff_pct = (diff / size1) * 100
else:
diff_pct = float('inf') if diff != 0 else 0.0
report_data.append([
path,
size1,
size2,
diff,
diff_pct
])
# 创建Excel工作簿
try:
wb = xlwt.Workbook(encoding='utf-8')
ws = wb.add_sheet('存储对比')
# 设置列宽
ws.col(0).width = 256 * 60 # 路径列宽
for i in range(1, 5):
ws.col(i).width = 256 * 15 # 其他列宽
# 设置标题行
headers = ['路径', '机器1大小(KB)', '机器2大小(KB)', '差值(KB)', '差异百分比(%)']
header_style = xlwt.easyxf('font: bold on')
for col, header in enumerate(headers):
ws.write(0, col, header, header_style)
# 设置单元格样式
normal_style = xlwt.easyxf() # 普通样式
red_style = xlwt.easyxf('pattern: pattern solid, fore_colour rose')
green_style = xlwt.easyxf('pattern: pattern solid, fore_colour light_green')
# 写入数据 - 修复单元格覆盖问题
for row_idx, row_data in enumerate(report_data, start=1):
# 确定整行样式
diff_pct = row_data[4]
if isinstance(diff_pct, (int, float)):
if diff_pct > 10:
row_style = red_style
elif diff_pct < -10:
row_style = green_style
else:
row_style = normal_style
else:
row_style = normal_style
# 写入整行数据,使用统一样式
for col_idx, value in enumerate(row_data):
ws.write(row_idx, col_idx, value, row_style)
# 保存文件
wb.save(output_xlsx)
return "对比报告已成功生成: {}".format(output_xlsx)
except Exception as e:
return "生成Excel文件时出错: {}".format(str(e))
if __name__ == "__main__":
# 使用当前目录下的相对路径
report = generate_comparison_report(
folder1='./moscow', # 当前目录下的moscow文件夹
folder2='./tacoof', # 当前目录下的tacoof文件夹
output_xlsx='moscow_compare.xlsx'
)
print report
```
### 主要修复内容:
1. **解决单元格覆盖问题**:
```python
# 修复前(导致覆盖错误)
for col_idx, value in enumerate(row_data):
ws.write(row_idx, col_idx, value)
if col_idx == 4: # 差异百分比列
# 尝试重新写入单元格导致覆盖错误
# 修复后(统一写入一次)
# 确定整行样式
diff_pct = row_data[4]
if isinstance(diff_pct, (int, float)):
if diff_pct > 10:
row_style = red_style
elif diff_pct < -10:
row_style = green_style
else:
row_style = normal_style
else:
row_style = normal_style
# 写入整行数据,使用统一样式
for col_idx, value in enumerate(row_data):
ws.write(row_idx, col_idx, value, row_style)
```
2. **优化样式应用**:
- 预先定义三种样式:普通、红色高亮、绿色高亮
- 根据差异百分比确定整行样式
- 每个单元格只写入一次,避免重复写入
3. **添加普通样式**:
```python
normal_style = xlwt.easyxf() # 普通样式
```
### 使用说明:
1. 将脚本保存为`storage.py`
2. 确保当前目录下有`moscow`和`tacoof`两个文件夹
3. 运行命令:
```bash
python storage.py
```
4. 输出文件将保存在`moscow_compare.xlsx`
### 如果问题仍然存在:
1. **添加唯一标识符**:
```python
# 在report_data中添加唯一ID
for idx, path in enumerate(all_paths):
report_data.append([
idx, # 唯一ID列
path,
size1,
size2,
diff,
diff_pct
])
# 写入时使用ID作为第一列
ws.write(row_idx, 0, row_data[0]) # ID
```
2. **检查路径唯一性**:
```python
# 确保路径唯一
all_paths = sorted(set(machine1_data.keys()) | set(machine2_data.keys()))
```
3. **添加调试信息**:
```python
# 在写入前打印行数据
print("写入行 {}: {}".format(row_idx, row_data))
```