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

如何在Go中动态切换gzip与csv Reader处理不同格式文件

解决动态切换gzip与普通Reader的作用域及代码复用问题

核心方案:利用io.Reader接口实现统一处理

因为gzip.Reader和*os.File(未压缩文件的读取器)都实现了Go标准库的io.Reader接口,我们可以通过声明一个通用的io.Reader变量,在条件分支中根据商家类型为其赋值,这样后续代码无需区分压缩/未压缩类型,直接使用这个通用变量即可——既解决了作用域问题,又避免了代码重复。

修改后的关键代码片段

// 定义需要使用gzip解压的商家Network_ID列表
var zipNetworks = []int{2}

// 提前声明通用的io.Reader变量
var reader io.Reader
var err error

in, err := os.Open("/tmp/feeds/" + fileID)
if err != nil {
    fmt.Printf("Failed to open feed file for merchant %d: %v\n", feed.MerchantID, err)
    return
}
defer in.Close()

// 根据商家类型选择对应的Reader
if slices.Contains(zipNetworks, merchant.Network_ID) {
    gzipReader, err := gzip.NewReader(in)
    if err != nil {
        fmt.Printf("Could not unzip feed %d: %v\n", feed.MerchantID, err)
        return
    }
    defer gzipReader.Close() // 确保gzip资源被正确释放
    reader = gzipReader
} else {
    // 未压缩文件直接用文件本身作为Reader
    reader = in
}

完整优化后的函数代码

func split(feed MerchantFeed, db *gorm.DB) {
    var merchant Merchant
    if err := db.First(&merchant, feed.MerchantID).Error; err != nil {
        fmt.Printf("Failed to fetch merchant %d: %v\n", feed.MerchantID, err)
        return
    }

    merchant.Title = strings.Replace(merchant.Title, ".", "_", -1)
    fileID := merchant.Title + "__" + fmt.Sprint(feed.MerchantID) + "__" + uniuri.NewLen(20)
    out, err := os.Create("/tmp/feeds/" + fileID)
    if err != nil {
        fmt.Printf("Failed to create temp feed file for merchant %d: %v\n", feed.MerchantID, err)
        return
    }
    defer out.Close()

    resp, err := http.Get(feed.Url)
    if err != nil {
        fmt.Printf("Feed download error for merchant %d: %v\n", feed.MerchantID, err)
        return
    }
    defer resp.Body.Close()

    bytes, err := io.Copy(out, resp.Body)
    if err != nil {
        fmt.Printf("Could not write feed to temp file for merchant %d: %v\n", feed.MerchantID, err)
        return
    }

    // --- 动态选择Reader的核心逻辑 ---
    var zipNetworks = []int{2}
    var reader io.Reader

    in, err := os.Open("/tmp/feeds/" + fileID)
    if err != nil {
        fmt.Printf("Failed to open temp feed file for merchant %d: %v\n", feed.MerchantID, err)
        return
    }
    defer in.Close()

    if slices.Contains(zipNetworks, merchant.Network_ID) {
        gzipReader, err := gzip.NewReader(in)
        if err != nil {
            fmt.Printf("Could not unzip feed %d: %v\n", feed.MerchantID, err)
            return
        }
        defer gzipReader.Close()
        reader = gzipReader
    } else {
        reader = in
    }
    // --- 核心逻辑结束 ---

    path := "/tmp/split/feed__" + fileID + "__.csv"
    csvfile, err := os.Create(path)
    if err != nil {
        fmt.Printf("Failed to create split CSV file for merchant %d: %v\n", feed.MerchantID, err)
        return
    }
    defer csvfile.Close()

    // 直接复制Reader内容到CSV文件,移除原代码中丢失前100字节的逻辑
    if _, err := io.Copy(csvfile, reader); err != nil {
        fmt.Printf("Could not write uncompressed feed to CSV for merchant %d: %v\n", feed.MerchantID, err)
        return
    }

    if fileID != "" {
        _, errx := splitter.Split(path, splitDir)
        if errx != nil {
            fmt.Printf("Failed to split CSV for merchant %d: %v\n", feed.MerchantID, errx)
        }

        if err := os.Remove(path); err != nil {
            fmt.Printf("Failed to remove temp split CSV for merchant %d: %v\n", feed.MerchantID, err)
        }
    }

    fmt.Printf("Size in MB (Feed %d): %d\n", feed.MerchantID, bytes/1024/1024)
    if bytes == 64 {
        fmt.Printf("Could not download feed from merchant %d (empty/invalid response)\n", feed.MerchantID)
        if err := os.Remove("/tmp/feeds/" + fileID); err != nil {
            log.Printf("Failed to remove invalid temp file for merchant %d: %v\n", feed.MerchantID, err)
        }
        return
    }
}

优化说明

  1. 作用域问题解决:提前声明io.Reader类型变量,确保在条件分支外可访问,避免块级作用域限制。
  2. 代码复用:后续的文件复制、拆分逻辑完全复用,无需为压缩/未压缩场景编写重复代码。
  3. 错误处理强化:修复原代码中大量忽略错误的问题,添加详细日志便于排查问题。
  4. 数据完整性修复:移除原代码中读取前100字节的逻辑,避免CSV文件开头数据丢失。
  5. 资源管理优化:为gzipReader添加defer Close(),确保压缩资源被正确释放。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 04:25:39