草庐IT

go - 如何用马提尼输出 CSV?

coder 2024-07-12 原文

我想用 martini 将 CSV 数据打印到输出。目前,我一直使用 r.JSON(200, somestruct) 其中 r 是来自 github.com/的 render.Render马提尼贡献

现在我有一片结构,我想将它们打印为 CSV(将单个结构的每个字段串化并在一行中打印一个结构)。

目前,我是这样做的:

r.Data(200, []byte("id,Latitude,Longitude\n"))
for _, packet := range tour.Packets {
    r.Data(200, []byte(strconv.FormatInt(packet.Id, 10)+","+strconv.FormatFloat(packet.Latitude, 'f', 6, 64)+","+strconv.FormatFloat(packet.Longitude, 'f', 6, 64)+"\n"))
}

但我不喜欢我这样做的方式,原因如下:

  • 它是直接下载的,不会打印到屏幕上。
  • 我得到 http: multiple response.WriteHeader calls
  • 我不想手动创建它(该结构有更多字段,但所有字段都是 ìnt64float64time.Time.

如何以更简单的方式实现 CSV 导出选项?

最佳答案

使用标准库。没有反射(reflection)就没有通用的解决方案,但是你可以简化它。

func handler(rw http.ResponseWriter) {
    rw.Header().Add("Content-Type", "text/csv")
    wr := csv.NewWriter(rw)
    err := wr.Write([]string{"id", "Latitude", "Longitude"})
    if err != nil {
        ...
    }
    for _, packet := range tour.Packets {
        err := wr.Write([]string{
            strconv.FormatInt(packet.Id, 10),
            strconv.FormatFloat(packet.Latitude, 'f', 6, 64),
            strconv.FormatFloat(packet.Longitude, 'f', 6, 64),
        })
        if err != nil {
            ...
        }
    }
}

如果您需要任何结构的通用解决方案,则需要 reflect。 参见 here .

// structToStringSlice takes a struct value and
// creates a string slice of all the values in that struct
func structToStringSlice(i interface{}) []string {
    v := reflect.ValueOf(i)
    n := v.NumField()
    out := make([]string, n)
    for i := 0; i < n; i++ {
        field := v.Field(i)
        switch field.Kind() {
        case reflect.String:
            out[i] = field.String()
        case reflect.Int:
            out[i] = strconv.FormatInt(field.Int(), 10)
        // add cases here to support more field types.
        }
    }
    return out
}

// writeToCSV prints a slice of structs as csv to a writer
func writeToCSV(w io.Writer, i interface{}) {
    wr := csv.NewWriter(w)
    v := reflect.ValueOf(i)

    // Get slice's element type (some unknown struct type)
    typ := v.Type().Elem()
    numFields := typ.NumField()
    fieldSet := make([]string, numFields)
    for i := 0; i < numFields; i++ {
        fieldSet[i] = typ.Field(i).Name
    }
    // Write header row
    wr.Write(fieldSet)

    // Write data rows
    sliceLen := v.Len()
    for i := 0; i < sliceLen; i++ {
        wr.Write(structToStringSlice(v.Index(i).Interface()))
    }
    wr.Flush()
}

那么你的例子就是:

func handler(rw http.ResponseWriter) {
    ....
    writeToCSV(rw, tour.Packets)
}

我编写的函数仅适用于 int 或 string 字段。您可以通过将 case 添加到 structToStringSlice 中的开关来轻松地将其扩展到更多类型。参见 here用于反射(reflect)其他 Kinds 的文档。

关于go - 如何用马提尼输出 CSV?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29183152/

有关go - 如何用马提尼输出 CSV?的更多相关文章

  1. ruby - 用逗号、双引号和编码解析 csv - 2

    我正在使用ruby​​1.9解析以下带有MacRoman字符的csv文件#encoding:ISO-8859-1#csv_parse.csvName,main-dialogue"Marceu","Giveittohimóhe,hiswife."我做了以下解析。require'csv'input_string=File.read("../csv_parse.rb").force_encoding("ISO-8859-1").encode("UTF-8")#=>"Name,main-dialogue\r\n\"Marceu\",\"Giveittohim\x97he,hiswife.\"\

  2. ruby - 我可以使用 Ruby 从 CSV 中删除列吗? - 2

    查看Ruby的CSV库的文档,我非常确定这是可能且简单的。我只需要使用Ruby删除CSV文件的前三列,但我没有成功运行它。 最佳答案 csv_table=CSV.read(file_path_in,:headers=>true)csv_table.delete("header_name")csv_table.to_csv#=>ThenewCSVinstringformat检查CSV::Table文档:http://ruby-doc.org/stdlib-1.9.2/libdoc/csv/rdoc/CSV/Table.html

  3. ruby - 检查 "command"的输出应该包含 NilClass 的意外崩溃 - 2

    为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar

  4. ruby - 通过 erb 模板输出 ruby​​ 数组 - 2

    我正在使用puppet为ruby​​程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby​​不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这

  5. ruby - 如何进行排列以有效地定制输出 - 2

    这是一道面试题,我没有答对,但还是很好奇怎么解。你有N个人的大家庭,分别是1,2,3,...,N岁。你想给你的大家庭拍张照片。所有的家庭成员都排成一排。“我是家里的friend,建议家庭成员安排如下:”1岁的家庭成员坐在这一排的最左边。每两个坐在一起的家庭成员的年龄相差不得超过2岁。输入:整数N,1≤N≤55。输出:摄影师可以拍摄的照片数量。示例->输入:4,输出:4符合条件的数组:[1,2,3,4][1,2,4,3][1,3,2,4][1,3,4,2]另一个例子:输入:5输出:6符合条件的数组:[1,2,3,4,5][1,2,3,5,4][1,2,4,3,5][1,2,4,5,3][

  6. ruby CSV : How can I read a tab-delimited file? - 2

    CSV.open(name,"r").eachdo|row|putsrowend我得到以下错误:CSV::MalformedCSVErrorUnquotedfieldsdonotallow\ror\n文件名是一个.txt制表符分隔文件。我是专门做的。我有一个.csv文件,我转到excel,并将文件保存为.txt制表符分隔的文件。所以它是制表符分隔的。CSV.open不应该能够读取制表符分隔的文件吗? 最佳答案 尝试像这样指定字段分隔符:CSV.open("name","r",{:col_sep=>"\t"}).eachdo|row|

  7. ruby - 将 spawn() 的标准输出/标准错误重定向到 Ruby 中的字符串 - 2

    我想使用spawn(针对多个并发子进程)在Ruby中执行一个外部进程,并将标准输出或标准错误收集到一个字符串中,其方式类似于使用Python的子进程Popen.communicate()可以完成的操作。我尝试将:out/:err重定向到一个新的StringIO对象,但这会生成一个ArgumentError,并且临时重新定义$stdxxx会混淆子进程的输出。 最佳答案 如果你不喜欢popen,这是我的方法:r,w=IO.pipepid=Process.spawn(command,:out=>w,:err=>[:child,:out])

  8. ruby - 如何使用 Ruby 将 CSV 文件读入 HTML 表格? - 2

    我正在尝试将一个简单的CSV文件读入HTML表格以在浏览器中显示,但我遇到了麻烦。这就是我正在尝试的:Controller:defshow@csv=CSV.open("file.csv",:headers=>true)end查看:输出:NameStartDateEndDateQuantityPostalCode基本上我只获取标题,而不会读取和呈现CSV正文。 最佳答案 这最终成为最终解决方案:Controller:defshow#OpenaCSVfile,andthenreaditintoaCSV::Tableobjectforda

  9. ruby - Ruby 是否使用 $stdout 来写入 puts 和 return 的输出? - 2

    我想知道Ruby用来在命令行打印这些东西的输出流:irb(main):001:0>a="test"=>"test"irb(main):002:0>putsatest=>nilirb(main):003:0>a=>"test"$stdout是否用于irb(main):002:0>和irb(main):003:0>?而且,在这两次调用之间,$stdout的值是否有任何变化?另外,有人能告诉我打印/写入这些内容的Ruby源代码吗? 最佳答案 是的。而且很容易向自己测试/证明。在命令行试试这个:ruby-e'puts"foo"'>test.

  10. ruby-on-rails - 无法在 Rails 助手中捕获 block 的输出 - 2

    我在使用自定义RailsFormBuilder时遇到了问题,从昨天晚上开始我就发疯了。基本上我想对我的构建器方法之一有一个可选block,以便我可以在我的主要content_tag中显示其他内容。:defform_field(method,&block)content_tag(:div,class:'field')doconcatlabel(method,"Label#{method}")concattext_field(method)capture(&block)ifblock_given?endend当我在我的一个Slim模板中调用该方法时,如下所示:=f.form_field:e

随机推荐