iT邦幫忙

0

xlsx、xls轉換成csv code

  • 分享至 

  • xImage

各位前輩好 之前發問的資料庫整理到一個階段 目前用得不錯
先感謝各位前輩之前的教學

這幾天想寫cdoe把xlsx、xls轉換成csv檔案,並把這個轉成exe檔案使用
感謝有gpt的存在,都蠻順利的,但目前遇到一個問題卡了我一整天

我執行code跑出來的視窗 選擇xlsx檔案沒有什麼問題
https://ithelp.ithome.com.tw/upload/images/20240807/20168089Mhlra91C4r.jpg

但是當我選好xlsx進行到下一步,要選擇轉換成csv檔案後儲存的資料夾時,跑出這個畫面,但我點選的資料夾裡面已經有csv檔案了,我想要他可以顯示出來而不是只會顯示資料夾,但同時我點選儲存進行下一步的時候仍然是只能選擇資料夾。只是想要多一個可以顯示裡面的csv檔案
https://ithelp.ithome.com.tw/upload/images/20240807/20168089eGiLBJq0Qf.jpg

因為我看不到裡面原有的csv檔案有哪些 ,導致我只能多寫一個重複會跳出來視窗,但我想要前面視窗就可以看到裡面原有的csv檔案。

我問了gpt並修改非常多次仍然不行,如果要能看到csv檔案,就會變成只能選擇csv檔案,但這樣我就沒辦法儲存轉換過來的大量文件。

拜託各位前輩們能教教我,搞了一整天qqq

下列是我的code (使用vs code)

import os
import sys
import pandas as pd
from PyQt5.QtWidgets import QApplication, QFileDialog, QMessageBox, QDialog, QVBoxLayout, QLabel, QPushButton, QHBoxLayout
from PyQt5.QtCore import Qt, QDir
from concurrent.futures import ThreadPoolExecutor, as_completed

class ConflictSummaryDialog(QDialog):
def init(self, conflict_count, parent=None):
super(ConflictSummaryDialog, self).init(parent)
self.setWindowTitle("文件衝突摘要")
self.setWindowFlag(Qt.WindowContextHelpButtonHint, False)
self.layout = QVBoxLayout(self)
self.label = QLabel(f"總共有 {conflict_count} 個文件重複。")
self.layout.addWidget(self.label)

    self.replace_all_button = QPushButton("全部取代")
    self.cancel_button = QPushButton("取消")

    button_layout = QHBoxLayout()
    button_layout.addWidget(self.replace_all_button)
    button_layout.addWidget(self.cancel_button)

    self.layout.addLayout(button_layout)

    self.replace_all_button.clicked.connect(self.accept_replace_all)
    self.cancel_button.clicked.connect(self.reject)

    self.choice = None

def accept_replace_all(self):
    self.choice = "replace_all"
    self.accept()

def select_folder_with_csv_files():
folder_dialog = QFileDialog()
folder_dialog.setFileMode(QFileDialog.Directory)
folder_dialog.setOption(QFileDialog.ShowDirsOnly, False)
folder_dialog.setFilter(QDir.Files | QDir.AllDirs | QDir.Hidden)
folder_dialog.setViewMode(QFileDialog.Detail)
folder_dialog.setFileMode(QFileDialog.DirectoryOnly)

if folder_dialog.exec_() == QFileDialog.Accepted:
    folder = folder_dialog.selectedFiles()[0]
    if folder:
        csv_files = [f for f in os.listdir(folder) if f.endswith('.csv')]
        for csv_file in csv_files:
            print(f'找到 CSV 文件: {csv_file}')
        return folder
return None

def process_file(file, output_folder, overwrite_all):
try:
print(f'正在處理文件: {file}')
xls = pd.ExcelFile(file)
for sheet_name in xls.sheet_names:
df = pd.read_excel(file, sheet_name=sheet_name, dtype=str, header=0)
df.columns = df.columns.astype(str).str.strip()
df.fillna('', inplace=True)

        if df.columns.str.contains('^Unnamed').any():
            df.columns = ['' if 'Unnamed' in col else col for col in df.columns]

        csv_file = f"{os.path.splitext(os.path.basename(file))[0]}_{sheet_name}.csv"
        csv_path = os.path.join(output_folder, csv_file)

        if not overwrite_all and os.path.exists(csv_path):
            print(f'跳過文件: {csv_path}')
            continue

        df.to_csv(csv_path, index=False, encoding='utf-8-sig') 
        print(f'轉換完成: {file} -> {csv_path}')
except Exception as e:
    print(f'處理 {file} 時出錯: {e}')

def convert_xlsx_to_csv(files, output_folder, overwrite_all):
with ThreadPoolExecutor() as executor:
futures = [executor.submit(process_file, file, output_folder, overwrite_all) for file in files]
for future in as_completed(futures):
future.result()

if name == "main":
app = QApplication([])

files, _ = QFileDialog.getOpenFileNames(None, '選擇要轉換的 Excel 文件', '', 'Excel files (*.xlsx *.xls)')
if not files:
    print('未選擇任何文件,程序退出。')
    sys.exit()

output_folder = select_folder_with_csv_files()
if not output_folder:
    print('未選擇輸出文件夾,程序退出。')
    sys.exit()

conflict_files = []
for file in files:
    xls = pd.ExcelFile(file)
    for sheet_name in xls.sheet_names:
        csv_file = f"{os.path.splitext(os.path.basename(file))[0]}_{sheet_name}.csv"
        if os.path.exists(os.path.join(output_folder, csv_file)):
            conflict_files.append(csv_file)

if conflict_files:
    summary_dialog = ConflictSummaryDialog(len(conflict_files))
    if summary_dialog.exec_() == QDialog.Accepted:
        if summary_dialog.choice == "replace_all":
            overwrite_all = True
        else:
            sys.exit()  
    else:
        sys.exit()  
else:
    overwrite_all = True 

convert_xlsx_to_csv(files, output_folder, overwrite_all)

QMessageBox.information(None, '完成', '所有文件已成功轉換為 CSV 格式')
app.exec_()
froce iT邦大師 1 級 ‧ 2024-08-07 21:54:06 檢舉
https://forum.qt.io/topic/62138/qfiledialog-choose-directories-only-but-show-files-as-well/13

最後的回答:
I've tested on windows. It seems the only possible solution is to ignore native dialog.

windows的話好像只能用風格不統一的QT介面去做。不能用windows的原生介面。應該是windows本身的限制。

然後你
select_folder_with_csv_files()
裡有重複設定setFileMode
boby89421 iT邦新手 5 級 ‧ 2024-08-08 11:14:05 檢舉
好像真的只能用額外的去做,沒辦法用原生介面。感謝提醒還真得有重複設定!
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友回答

立即登入回答