You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 14:15:02