I am trying to write Student Marks to a csv file in GO .
It is printing the desired 10 result per page with Println
but is saving only the last value (not all 10) in csv .
This is what I am doing
Visitor visits studentmarks.com/page=1
Marks for 10 students are displayed and it is also saved in CSV
Visitor clicks next page and he is navigated to studentmarks.com/page=2
Marks for another 10 students are displayed and it is also saved in subsequent column/rows in the CSV
and so on
fmt.Fprintf(w, KeyTemplate, key.fname, key.marks, key.lname )
is working fine and displays all 10 results per page but I am unable to save all 10 results in the CSV (with my current code, only the last result is saved).
Here is my snippet of the code that is responsible for printing and saving the results.
func PageRequest(w http.ResponseWriter, r *http.Request) {
// Default page number is 1
if len(r.URL.Path) <= 1 {
r.URL.Path = "/1"
}
// Page number is not negative or 0
page.Abs(page)
if page.Cmp(one) == -1 {
page.SetInt64(1)
}
// Page header
fmt.Fprintf(w, PageHeader, pages, previous, next)
// Marks for UID
UID, length := compute(start)
for i := 0; i < length; i++ {
key := UID[i]
fmt.Fprintf(w, key.fname, key.marks, key.lname, key.remarks)
// Save in csv
csvfile, err := os.Create("marks.csv")
if err != nil {
fmt.Println("Error:", err)
return
}
defer csvfile.Close()
records := [][]string{{key.fname, key.marks, key.lname, , key.remarks}}
writer := csv.NewWriter(csvfile)
for _, record := range records {
err := writer.Write(record)
if err != nil {
fmt.Println("Error:", err)
return
}
}
writer.Flush()
// Page Footer
fmt.Fprintf(w, PageFooter, previous, next)
}
How can I print and save (in csv) all the 10 results using go language?
The basic problem is that you are calling os.Create. The documentation for os.Create says
Create creates the named file with mode 0666 (before umask), truncating it if it already exists. If successful, methods on the returned File can be used for I/O; the associated file descriptor has mode O_RDWR. If there is an error, it will be of type *PathError.
So each call to os.Create will remove all content from the file you passed. Instead what you want is probably os.OpenFile with the os.O_CREATE, os.O_WRONLY and os.O_APPEND flags. This will make sure that the file will be created, if it doesn't exists, but won't truncate it.
But there is another problem in your code. You are calling defer csvfile.Close()
inside the loop. A deferred function will only be executed once the function returns and not after the loop iteration. This can lead to problems, especially since you are opening the same file over and over again.
Instead you should open the file once before the loop so that you only need to close it once. Like this:
package main
import (
"encoding/csv"
"fmt"
"net/http"
"os"
)
func PageRequest(w http.ResponseWriter, r *http.Request) {
// Default page number is 1
if len(r.URL.Path) <= 1 {
r.URL.Path = "/1"
}
// Page number is not negative or 0
page.Abs(page)
if page.Cmp(one) == -1 {
page.SetInt64(1)
}
// Page header
fmt.Fprintf(w, PageHeader, pages, previous, next)
// Save in csv
csvfile, err := os.OpenFile("marks.csv", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
fmt.Println("Error:", err)
return
}
defer csvfile.Close()
writer := csv.NewWriter(csvfile)
defer writer.Flush()
// Marks for UID
UID, length := compute(start)
for i := 0; i < length; i++ {
key := UID[i]
fmt.Fprintf(w, key.fname, key.marks, key.lname, key.remarks)
records := [][]string{{key.fname, key.marks, key.lname, key.remarks}}
for _, record := range records {
err := writer.Write(record)
if err != nil {
fmt.Println("Error:", err)
return
}
}
}
// Page Footer
fmt.Fprintf(w, PageFooter, previous, next)
}