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

Python解析大PDF传Go时cmd.Output()报错求助

问题根源分析
  1. 运行时恐慌直接原因:Go代码中WriteString的错误处理块误用了未定义的变量err2,这会触发invalid memory address类型的运行时恐慌。
  2. 大PDF处理失败原因:cmd.Output()会将子进程的所有标准输出一次性加载到内存,超大文本会导致内存占用过高;同时管道缓冲区存在大小限制,子进程可能因无法继续写入stdout而阻塞退出,返回exit status 1。

修复与优化方案

先修复基础错误的Go代码

解决恐慌问题并完善错误处理:

func parsePdf(path string) string {
    cmd := exec.Command("python", "pdf_parser.py", path)
    output, err := cmd.Output() 
    if err != nil {
        fmt.Println("执行Python脚本出错:", err)
        return ""
    }
    f, err := os.Create("go-pdf-output.txt")
    if err != nil {
        fmt.Println("创建文件出错:", err)
        return string(output)
    }
    defer f.Close() // 确保文件资源被释放
    _, err = f.WriteString(string(output))
    if err != nil {
        fmt.Println("写入文件出错:", err)
    }
    return string(output)
}

针对大PDF的优化方案

方案一:流式读取输出(推荐)

通过管道实时读取子进程输出并写入文件,避免一次性加载全部文本到内存,彻底解决管道缓冲区和内存过载问题:

import (
    "fmt"
    "io"
    "os"
    "os/exec"
)

func parsePdf(path string) error {
    cmd := exec.Command("python", "pdf_parser.py", path)
    
    // 创建stdout管道
    stdout, err := cmd.StdoutPipe()
    if err != nil {
        return fmt.Errorf("创建stdout管道失败: %w", err)
    }
    
    // 启动子进程
    if err := cmd.Start(); err != nil {
        return fmt.Errorf("启动Python脚本失败: %w", err)
    }
    
    // 创建输出文件
    f, err := os.Create("go-pdf-output.txt")
    if err != nil {
        return fmt.Errorf("创建输出文件失败: %w", err)
    }
    defer f.Close()
    
    // 流式复制输出到文件
    _, err = io.Copy(f, stdout)
    if err != nil {
        return fmt.Errorf("读取输出失败: %w", err)
    }
    
    // 等待子进程执行完成
    if err := cmd.Wait(); err != nil {
        return fmt.Errorf("Python脚本执行失败: %w", err)
    }
    
    return nil
}

方案二:Python直接写入文件,Go读取结果

让Python脚本直接将解析后的文本写入文件,绕过进程间管道传递的限制:
修改Python脚本:

import fitz
import sys

path = sys.argv[1]
output_path = "pdf-output.txt"  # 可通过命令行参数动态指定路径
doc = fitz.open(path)

with open(output_path, "w", encoding="utf-8") as f:
    for page in doc:
        text = page.get_text("text")
        f.write(text + " ")

修改Go代码:

import (
    "fmt"
    "os"
    "os/exec"
)

func parsePdf(path string) error {
    cmd := exec.Command("python", "pdf_parser.py", path)
    err := cmd.Run()
    if err != nil {
        return fmt.Errorf("执行Python脚本失败: %w", err)
    }
    
    // 读取Python生成的文件
    content, err := os.ReadFile("pdf-output.txt")
    if err != nil {
        return fmt.Errorf("读取输出文件失败: %w", err)
    }
    
    // 写入目标文件
    f, err := os.Create("go-pdf-output.txt")
    if err != nil {
        return fmt.Errorf("创建目标文件失败: %w", err)
    }
    defer f.Close()
    _, err = f.Write(content)
    return err
}

额外建议

  • 处理超大文件时,优先采用流式处理逻辑,避免在内存中存储完整文本。
  • 给Python脚本添加错误处理(如文件不存在、PDF损坏等),并将错误信息输出到stderr,Go可通过cmd.StderrPipe()捕获错误信息用于调试。

内容的提问来源于stack exchange,提问作者Harsh Vardhan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 03:15:48