1

I am trying to loop over a csv file and output text file titled after each row in the first column. Each text file is then be populated with data from the other rows for that column. I am able to print the contents of the csv to a text file, but I can not get the logic down using a for loop to grab the index of column one and use that to create/title a new .txt file.

package main

import (
    "fmt"
    "io"
    "io/ioutil"
    "log"
    "os"
)

func main() {
    fmt.Println("Enter file path to CSV: ")
    var csvFile string
    _, err := fmt.Scanln(&csvFile)
    if err != nil {
        log.Fatal("Cannot read input")
        return
    }
    //open file
    inFile, err := os.Open(csvFile)
    if err != nil {
        log.Fatal(err)
    }
    defer inFile.Close()

    readMe, _ := ioutil.ReadAll(inFile)

    blankFile, err := os.Create(`C:\temp\test.txt`)
    if err != nil {
        log.Fatal(err)
    }
    defer blankFile.Close()

    //write data to text file
    outFile, err := blankFile.Write(readMe)
    if err == io.EOF {
        log.Fatalln("Failed")
    } else if err != nil {
        log.Fatal(err)
    }
    //print bytes total
    fmt.Println(outFile, " bytes printed")

}
0

1 Answer 1

2

Take multiple columns from a csv and print each column to a new text file.

Loop over a csv and produce a new text file that will be titled after each column in row #1. Each text file will then be populated with data from the other rows for that column.


For example,

package main

import (
    "encoding/csv"
    "fmt"
    "io"
    "os"
    "path/filepath"
)

func CsvFileToTxtFiles(inFile string) error {
    in, err := os.Open(inFile)
    if err != nil {
        return err
    }
    defer in.Close()
    r := csv.NewReader(in)
    hdr, err := r.Read()
    if err != nil {
        return err
    }
    f := make([]*os.File, len(hdr))
    w := make([]*csv.Writer, len(hdr))
    pfx := filepath.Clean(inFile)
    pfx = pfx[:len(pfx)-len(filepath.Ext(pfx))]
    for i, col := range hdr {
        var err error
        f[i], err = os.Create(pfx + "." + col + ".txt")
        if err != nil {
            return err
        }
        defer f[i].Close()
        w[i] = csv.NewWriter(f[i])
        if err != nil {
            return err
        }
        defer w[i].Flush()
    }

    for {
        row, err := r.Read()
        if err != nil {
            if row == nil && err == io.EOF {
                break
            }
            return err
        }
        for i, col := range row {
            err := w[i].Write([]string{col})
            if err != nil {
                return err
            }
        }
    }

    for i := range hdr {
        var err error
        w[i].Flush()
        err = w[i].Error()
        if err != nil {
            return err
        }
        err = f[i].Close()
        if err != nil {
            return err
        }
    }

    return nil
}

func main() {
    if len(os.Args) <= 1 {
        usage := "usage: " + filepath.Base(os.Args[0]) + " FILE"
        fmt.Fprintln(os.Stderr, usage)
        return
    }
    inFile := os.Args[1]
    err := CsvFileToTxtFiles(inFile)
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        return
    }
}

Output:

$ cat ioj.test.csv
one,two,three
1,2,3
11,22,33
$ go run ioj.go ioj.test.csv
$ cat ioj.test.one.txt
1
11
$ cat ioj.test.two.txt
2
22
$ cat ioj.test.three.txt
3
33
$ 
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, this definitely put me on the right track to solve this problem.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.