Windows下监控网络文件夹CSV转XML遇PermissionError权限问题求助
问题:Windows下监控网络文件夹CSV转XML时触发PermissionError
我编写了Python脚本用于监控网络文件夹中的CSV文件,将其转换为SEPA Pain.001格式的XML文件。脚本在macOS上运行正常,但在Windows环境下执行时,抛出PermissionError: [Errno 13] Permission denied错误。已尝试以管理员身份运行程序,且确认目标网络文件夹具备读写权限,问题仍未解决。
脚本代码
def on_created(self, event): if event.is_directory or not event.src_path.endswith(".csv"): return csv_file_path = event.src_path print(f"CSV-Dateipfad: {csv_file_path}") self.process_csv_file(csv_file_path) logging.info(self.process_csv_file(csv_file_path)) def process_csv_file(self, csv_file_path): # Erzeuge einen XML-Dateinamen basierend auf dem CSV-Dateinamen csv_filename = os.path.basename(csv_file_path) xml_filename = os.path.splitext(csv_filename)[0] + ".xml" # Erstelle den vollständigen Pfad für die XML-Datei xml_file_path = os.path.join(self.output_folder, xml_filename) # Konvertiere CSV in XML self.convert_csv_to_xml(csv_file_path, xml_file_path) print(self.convert_csv_to_xml(csv_file_path, xml_file_path)) logging.info(self.convert_csv_to_xml(csv_file_path, xml_file_path)) logging.info(f"CSV-Datei konvertiert: {csv_file_path} -> {xml_file_path}") def convert_csv_to_xml(self, csv_file_path, xml_file_path): with open(csv_file_path, 'r', newline="") as file: csv_reader = csv.DictReader(file, delimiter=";") namespaces = { 'xmlns:xsi': "http://www.w3.org/2001/XMLSchema-instance", 'xmlns:xsd': "http://www.w3.org/2001/XMLSchema", 'xmlns': "urn:iso:std:iso:20022:tech:xsd:pain.001.001.03" } # Create the SEPA Pain.001 XML structure document = ET.Element("Document", attrib=namespaces) cct_init = ET.SubElement(document, "CstmrCdtTrfInitn") # Group Header grp_header = ET.SubElement(cct_init, "GrpHdr") msg_id = ET.SubElement(grp_header, "MsgId") msg_id.text = "SEPA_PAYMENT-04254" # Set a custom message ID cre_dt_tm = ET.SubElement(grp_header, "CreDtTm") cre_dt_tm.text = datetime.now().strftime("%Y-%m-%dT%H:%M:%S") nb_of_txs = ET.SubElement(grp_header, "NbOfTxs") ctrl_sum = ET.SubElement(grp_header, "CtrlSum") initg_pty = ET.SubElement(grp_header, "InitgPty") ET.SubElement(initg_pty, "Nm").text = "YOUR_INITIATOR_NAME" # For Loop to put the Payment Information for row in csv_reader: # Debitor Information nb_of_txs.text = str(int(nb_of_txs.text or "0") + 1) ctrl_sum.text = row["Bruttobetrag (gesamt) [Zahlungsdaten]"].replace(',', '.') # Payment Information PmtInf = ET.SubElement(cct_init, "PmtInf") ET.SubElement(PmtInf, "PmtInfId").text = "YOUR_PAYMENT_INFO_ID" ET.SubElement(PmtInf, "PmtMtd").text = "TRF" ET.SubElement(PmtInf, "BtchBookg").text = "false" reqd_colltn_dt = ET.SubElement(PmtInf, "ReqdExctnDt") reqd_colltn_dt.text = datetime.strptime( row["Zahlungsziel [Zahlungsdaten]"], "%d.%m.%Y") .strftime("%Y-%m-%d") Dbtr = ET.SubElement(PmtInf, "Dbtr") ET.SubElement(Dbtr, "Nm").text = " " DbtrAcct = ET.SubElement(PmtInf, "DbtrAcct") ET.SubElement(DbtrAcct, "Id").text = " " DbtrAgt = ET.SubElement(PmtInf, "DbtrAgt") ET.SubElement(DbtrAgt, "FinInstnId").text = " " CdtTrfTxInf = ET.SubElement(PmtInf, "CdtTrfTxInf") PmtId = ET.SubElement(CdtTrfTxInf, "PmtId") ET.SubElement(PmtId, "EndToEndId").text = f"TRANSACTION-{csv_reader.line_num - 1}" Amt = ET.SubElement(CdtTrfTxInf, "Amt") ET.SubElement(Amt, "InstdAmt", Ccy="EUR").text = row[ "Bruttobetrag (gesamt) [Zahlungsdaten]"].replace(',', '.') CdtrAgt = ET.SubElement(CdtTrfTxInf, "CdtrAgt") BIC = ET.SubElement(CdtrAgt, "FinInstnId") ET.SubElement(BIC, "BIC").text = row["BIC [Zahlungsdaten]"] Cdtr = ET.SubElement(CdtTrfTxInf, "Cdtr") ET.SubElement(Cdtr, "Nm").text = row["Zahlungsempfaenger [Zahlungsdaten]"] CdtrAcct = ET.SubElement(CdtTrfTxInf, "CdtrAcct") IBAN = ET.SubElement(CdtrAcct, "Id") ET.SubElement(IBAN, "IBAN").text = row["IBAN [Zahlungsdaten]"] RmtInf = ET.SubElement(CdtTrfTxInf, "RmtInf") ET.SubElement(RmtInf, "Ustrd").text = row["Verwendungszweck [Zahlungsdaten]"] file.close() xml_tree = ET.ElementTree(document) xml_tree.write(xml_file_path, encoding="utf-8", xml_declaration=True) def start_csv_handler(output_folder): event_handler = CSVHandler(output_folder) observer = Observer() observer.schedule(event_handler, path=output_folder, recursive=False) observer.start() logging.info(f"Überwache den Ordner: {output_folder}") try: while True: root.update() except KeyboardInterrupt: observer.stop() observer.join() if __name__ == "__main__": root = tk.Tk() root.withdraw() # Wähle den Ausgabeordner für die XML-Dateien output_folder = filedialog.askdirectory() if not output_folder: logging.info("Kein Ausgabeordner ausgewählt.") exit() logging.basicConfig(filename="logfile.log", level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s") logging.info(f"Ausgebeordner ausgewählt: {output_folder}") thread = threading.Thread(target=start_csv_handler, args=(output_folder,)) thread.start() root.mainloop()
错误日志
Exception in thread Thread-2: Traceback (most recent call last): File "C:\ProgramFiles\WindowsApps\PythonSoftwareFoundation.Python.3.11_3.11.1264.0_x64__qbz5n2kfra8p0\Lib\threading.py", line 1038, in _bootstrap_inner self.run() File "C:\Users\Administrator.VERTRIEB-PC21\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\local-packages\Python311\site-packages\watchdog\observers\api.py", line 204, in run self.dispatch_events(self.event_queue) File "C:\Users\Administrator.VERTRIEB-PC21\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\local-packages\Python311\site-packages\watchdog\observers\api.py", line 380, in dispatch_events handler.dispatch(event) File "C:\Users\Administrator.VERTRIEB-PC21\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\local-packages\Python311\site-packages\watchdog\events.py", line 276, in dispatch { File "C:\Users\Administrator.VERTRIEB-PC21\Desktop\NeuerOrdner\Hdd.py", line 26, in on_created self.process_csv_file(csv_file_path) File "C:\Users\Administrator.VERTRIEB-PC21\Desktop\NeuerOrdner\Hdd.py", line 37, in process_csv_file self.convert_csv_to_xml(csv_file_path, xml_file_path) File "C:\Users\Administrator.VERTRIEB-PC21\Desktop\NeuerOrdner\Hdd.py", line 54, in convert_csv_to_xml with open(csv_file_path, 'r', newline="") as file: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PermissionError: [Errno 13] Permission denied: 'S:/SepaPain/ExportCSV\\DocuWare_Dokumentenpool_2023.06.20.csv'
排查与解决方案
1. 文件锁定问题(核心原因)
Windows系统中,当文件被写入工具(如DocuWare、上传程序)占用时,watchdog的on_created事件会立即触发,但此时文件处于锁定状态,Python无法读取。macOS文件系统处理机制不同,不会出现该问题。
解决:添加重试机制
修改convert_csv_to_xml函数,加入重试逻辑等待文件解锁:
import time def convert_csv_to_xml(self, csv_file_path, xml_file_path): max_retries = 5 retry_delay = 2 # 每次重试间隔2秒 for attempt in range(max_retries): try: with open(csv_file_path, 'r', newline="") as file: # 原有CSV转XML的处理逻辑 csv_reader = csv.DictReader(file, delimiter=";") # ... 后续代码保持不变 ... break except PermissionError: if attempt < max_retries - 1: time.sleep(retry_delay) logging.warning(f"读取文件失败,重试中({attempt+1}/{max_retries}): {csv_file_path}") else: logging.error(f"多次尝试后仍无法读取文件: {csv_file_path}") raise
2. 路径格式兼容问题
错误日志中的路径混合了斜杠和反斜杠,虽Python通常可处理,但Windows下可能存在隐性兼容问题。
解决:标准化路径格式
在获取文件路径后,使用os.path.normpath()统一格式:
csv_file_path = os.path.normpath(event.src_path)
3. 安全软件拦截
Windows Defender或第三方安全软件可能会扫描新创建的文件,临时锁定文件导致无法读取。
解决:
- 将监控文件夹和Python脚本加入安全软件白名单
- 临时关闭安全软件测试,确认是否为拦截导致
4. 网络驱动器权限限制
Windows网络共享的权限可能存在隐性限制,比如共享权限与NTFS权限不匹配,或文件夹的索引设置干扰。
解决:
- 检查网络共享的NTFS权限,确保当前用户拥有
读取和读取与执行权限 - 取消网络文件夹的“允许文件内容被索引”选项(右键文件夹→属性→高级→取消勾选)
脚本额外优化点
脚本中存在重复调用函数的问题,会导致重复处理文件,需修正:
# 原代码(重复执行两次process_csv_file) self.process_csv_file(csv_file_path) logging.info(self.process_csv_file(csv_file_path)) # 修改后(仅执行一次) process_result = self.process_csv_file(csv_file_path) logging.info(process_result)
同理convert_csv_to_xml也被重复调用三次,需同步优化。
内容的提问来源于stack exchange,提问作者Marehno
相关产品推荐
相关产品推荐

