Why is the file empty after writing to it with bufio.Writer? - go

file, err := os.OpenFile("filename.db", os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
log.Fatal(err)
}
defer file.Close()
res := 0
writer := bufio.NewWriter(file)
for _, data := range manager {
bin, err := json.Marshal(data)
if err != nil {
log.Println(err)
return
}
res++
if debug {
log.Println(res)
}
fmt.Printf("%s\n", bin)
_, err = writer.Write(bin)
if err != nil {
log.Println(err)
}
_, _ = writer.WriteRune('\n')
}
playground
full code
The file filename.db is created (if didn't exist), but ...is empty...
Why could this happen?
Why is the file empty?
I tried this both on my home pc and a linux server
And in both cases it's empty

As per the suggestion from comment using writer.Flush results in foo and bar values being written in to the document filename.db.
package main
import (
"bufio"
"encoding/json"
"fmt"
"log"
"os"
)
type Valuable struct {
Value string `json:"value"`
}
var debug = true
var manager []Valuable
func main() {
manager = append(manager, Valuable{"foo"}, Valuable{"bar"})
file, err := os.OpenFile("filename.db", os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
log.Fatal(err)
}
defer file.Close()
res := 0
writer := bufio.NewWriter(file)
defer writer.Flush()
for _, data := range manager {
bin, err := json.Marshal(data)
if err != nil {
log.Println(err)
return
}
res++
if debug {
log.Println(res)
}
fmt.Printf("%s\n", bin)
_, err = writer.Write(bin)
if err != nil {
log.Println(err)
}
_, _ = writer.WriteRune('\n')
}
}

Related

How do I copy a file without overwriting an existing file in Go?

How to create a new file with the given name if the file exists
eg : if word_destination.txt exists copy content to word_destination(1).txt
Any help would be appreciated...
package main
import (
"fmt"
"io/ioutil"
"os"
)
func main() {
src := ./word_source.txt
desti := ./folder/word_destination.txt
//if file exists want to copy it to the word_destination(1).txt
if _, err := os.Stat(desti); err == nil {
// path/to/whatever exists
fmt.Println("File Exists")
} else {
fmt.Println("File does not Exists")
bytesRead, err := ioutil.ReadFile(src)
if err != nil {
log.Fatal(err)
}
func tryCopy(src, dst string) error {
in, err := os.Open(src)
if err != nil {
return err
}
defer in.Close()
out, err := os.OpenFile(dst, os.O_CREATE| os.O_EXCL, 0644)
if err != nil {
return err
}
defer out.Close()
_, err = io.Copy(out, in)
if err != nil {
return err
}
return out.Close()
}
// ......
if _, err := os.Stat(desti); err == nil {
// path/to/whatever exists
fmt.Println("File Exists")
for i := 1; ; i++ {
ext := filepath.Ext(desti)
newpath := fmt.Sprintf("%s(%d)%s", strings.TrimSuffix(desti, ext), i, ext)
err := tryCopy(desti, newpath)
if err == nil {
break;
}
if os.IsExists(err) {
continue;
} else {
return err;
}
}
}

reading golang websocket returns random bytes

My program:
package main
import (
"fmt"
"io"
"log"
"net"
"github.com/gobwas/ws"
)
func HandleConn(conn net.Conn) {
for {
header, err := ws.ReadHeader(conn)
if err != nil {
log.Fatal(err)
}
buf := make([]byte, header.Length)
_, err = io.ReadFull(conn, buf)
if err != nil {
log.Fatal(err)
}
fmt.Println(buf)
fmt.Println(string(buf))
}
}
func main() {
ln, err := net.Listen("tcp", "localhost:8080")
if err != nil {
log.Fatal(err)
}
for {
conn, err := ln.Accept()
if err != nil {
log.Fatal(err)
}
_, err = ws.Upgrade(conn)
if err != nil {
log.Fatal(err)
}
go HandleConn(conn)
}
}
I do in browser console:
let socket = new WebSocket("ws://127.0.0.1:8080")
socket.send("Hello world")
I see random bytes in the my terminal. Each call to socket.send("Hello world") return different bytes. But the length of the byte array is always equal to the length of the string. Where does golang get these random bytes? How can I fix this? My program is an example from the docs.
If you are going to not use the wsutil you need to unmask the payload:
buff := make([]byte, header.Length)
_, err = io.ReadFull(conn, buff)
if err != nil {
// handle error
}
if header.Masked {
ws.Cipher(buff, header.Mask, 0)
}
fmt.Println(string(buff))

Having issues with multipart.NewWriter using io.pipe

I'm having issues with requests being sent randomly empty. It doesn't always happen, but sometimes out of the blue, it will not send any of the multipart fields. I thought it might have to do with the upload server, so I created a local upload server to print out the request that's being sent, and it comes out empty.
I have added error checks everywhere, but no errors are being returned.
I tried to run the code with -race, but no race condition has been reported.
Edit: Update the code to use CloseWithError()
package main
import (
"fmt"
"io"
"log"
"mime/multipart"
"net/http"
"os"
)
var (
upload_url string = "https://upload.imagekit.io/api/v1/files/upload"
file_name string = "favicon-516140983.ico"
api_secret_key string = "PRIVATE_KEY"
)
func UploadMultipartFile(client *http.Client, uri, key, path string) (*http.Response, error) {
body, writer := io.Pipe()
req, err := http.NewRequest(http.MethodPost, uri, body)
if err != nil {
log.Println(err)
return nil, err
}
mwriter := multipart.NewWriter(writer)
req.Header.Add("Content-Type", mwriter.FormDataContentType())
req.SetBasicAuth(api_secret_key, "")
go func() {
var err error
defer func() {
if err != nil {
writer.CloseWithError(err)
} else {
writer.Close()
}
}()
var file *os.File
file, err = os.Open(path)
if err != nil {
return
}
defer file.Close()
if err = mwriter.WriteField("fileName", file_name); err != nil {
return
}
var w io.Writer
w, err = mwriter.CreateFormFile("file", path)
if err != nil {
return
}
var written int64
if written, err = io.Copy(w, file); err != nil {
err = fmt.Errorf("error copying %s (%d bytes written): %v", path, written, err)
return
}
if err = mwriter.Close(); err != nil {
return
}
}()
resp, err := client.Do(req)
if err != nil {
return nil, err
}
return resp, nil
}
func main() {
path, _ := os.Getwd()
path += "/" + file_name
client := &http.Client{}
resp, err := UploadMultipartFile(client, upload_url, "file", path)
if err != nil {
log.Println(err)
} else {
fmt.Println(resp.StatusCode)
fmt.Println(resp.Header)
_, err := io.Copy(os.Stdout, resp.Body)
if err != nil {
log.Fatal(err)
}
resp.Body.Close()
}
}

No output to error file

I'm coding a little Go program.
It reads files in a directory line by line, it only reads lines with a certain prefix, normalizes the data and outputs to one of two files, depending on whether the normalized record has certain number of elements.
Data is being outputted to the Data file, but errors are not being outputted to the Errors file.
Debugging I see no issue.
Any help is much appreciated.
Thanks,
Martin
package main
import (
"bufio"
"fmt"
"io/ioutil"
"log"
"os"
"strings"
)
func main() {
//Output file - Data
if _, err := os.Stat("allData.txt"); os.IsNotExist(err) {
var file, err = os.Create("allData.txt")
if err != nil {
fmt.Println(err)
return
}
defer file.Close()
}
file, err := os.OpenFile("allData.txt", os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
panic(err)
}
w := bufio.NewWriter(file)
//Output file - Errors
if _, err := os.Stat("errorData.txt"); os.IsNotExist(err) {
var fileError, err = os.Create("errorData.txt")
if err != nil {
fmt.Println(err)
return
}
defer fileError.Close()
}
fileError, err := os.OpenFile("errorData.txt", os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
panic(err)
}
z := bufio.NewWriter(fileError)
//Read Directory
files, err := ioutil.ReadDir("../")
if err != nil {
log.Fatal(err)
}
//Build file path
for _, f := range files {
fName := string(f.Name())
sPath := string("../" + fName)
sFile, err := os.Open(sPath)
if err != nil {
fmt.Println(err)
return
}
//Create scanner
scanner := bufio.NewScanner(sFile)
scanner.Split(bufio.ScanLines)
var lines []string
// This is the buffer now
for scanner.Scan() {
lines = append(lines, scanner.Text())
}
for _, line := range lines {
sRecordC := strings.HasPrefix((line), "DATA:")
if sRecordC {
splitted := strings.Split(line, " ")
splittedNoSpaces := deleteEmpty(splitted)
if len(splittedNoSpaces) == 11 {
splittedString := strings.Join(splittedNoSpaces, " ")
sFinalRecord := string(splittedString + "\r\n")
if _, err = fmt.Fprintf(w, sFinalRecord); err != nil {
}
}
if len(splittedNoSpaces) < 11 {
splitted := strings.Split(line, " ")
splittedNoSpaces := deleteEmpty(splitted)
splittedString := strings.Join(splittedNoSpaces, " ")
sFinalRecord := string(splittedString + "\r\n")
if _, err = fmt.Fprintf(z, sFinalRecord); err != nil {
}
err = fileError.Sync()
if err != nil {
log.Fatal(err)
}
}
}
}
}
err = file.Sync()
if err != nil {
log.Fatal(err)
}
}
//Delete Empty array elements
func deleteEmpty(s []string) []string {
var r []string
for _, str := range s {
if str != "" {
r = append(r, str)
}
}
return r
}
Don't open the file multiple times, and don't check for the file's existence before creating it, just use the os.O_CREATE flag. You're also not deferring the correct os.File.Close call, because it's opened multiple times.
When using a bufio.Writer, you should always call Flush() to ensure that all data has been written to the underlying io.Writer.

Golang: fetching data from 1 CSV File to anthoer

I am new to golang, and I am trying to fetch 1 csv file to another new csv file, but i need only 2 records from the old csv file.
How would you fetch only the first two records of that file?
Here is what I have tried so far (also in the play.golang.org):
package main
import (
"encoding/csv"
"fmt"
"io"
"os"
)
func main() {
//SELECTING THE FILE TO EXTRACT.......
csvfile1, err := os.Open("data/sample.csv")
if err != nil {
fmt.Println(err)
return
}
defer csvfile1.Close()
reader := csv.NewReader(csvfile1)
for i := 0; i < 3; i++ {
record, err := reader.Read()
if err == io.EOF {
break
} else if err != nil {
fmt.Println(err)
return
}
csvfile2, err := os.Create("data/SingleColomReading.csv")
if err != nil {
fmt.Println(err)
return
}
defer csvfile2.Close()
records := []string{
record,
}
writer := csv.NewWriter(csvfile2)
//fmt.Println(writer)
for _, single := range records {
er := writer.Write(single)
if er != nil {
fmt.Println("error", er)
return
}
fmt.Println(single)
writer.Flush()
//fmt.Println(records)
//a:=strconv.Itoa(single)
n, er2 := csvfile2.WriteString(single)
if er2 != nil {
fmt.Println(n, er2)
}
}
}
}
Fixing your program,
package main
import (
"encoding/csv"
"fmt"
"io"
"os"
)
func main() {
csvfile1, err := os.Open("data/sample.csv")
if err != nil {
fmt.Println(err)
return
}
defer csvfile1.Close()
reader := csv.NewReader(csvfile1)
csvfile2, err := os.Create("data/SingleColomReading.csv")
if err != nil {
fmt.Println(err)
return
}
writer := csv.NewWriter(csvfile2)
for i := 0; i < 2; i++ {
record, err := reader.Read()
if err != nil {
if err == io.EOF {
break
}
fmt.Println(err)
return
}
err = writer.Write(record)
if err != nil {
fmt.Println(err)
return
}
}
writer.Flush()
err = csvfile2.Close()
if err != nil {
fmt.Println(err)
return
}
}
However, since you are only interested in copying records (lines) as a whole and not individual fields of a record, you could use bufio.Scanner, as #VonC suggested. For example,
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
csvfile1, err := os.Open("data/sample.csv")
if err != nil {
fmt.Println(err)
return
}
defer csvfile1.Close()
scanner := bufio.NewScanner(csvfile1)
csvfile2, err := os.Create("data/SingleColomReading.csv")
if err != nil {
fmt.Println(err)
return
}
writer := bufio.NewWriter(csvfile2)
nRecords := 0
for scanner.Scan() {
n, err := writer.Write(scanner.Bytes())
if err != nil {
fmt.Println(n, err)
return
}
err = writer.WriteByte('\n')
if err != nil {
fmt.Println(err)
return
}
if nRecords++; nRecords >= 2 {
break
}
}
if err := scanner.Err(); err != nil {
fmt.Println(err)
return
}
err = writer.Flush()
if err != nil {
fmt.Println(err)
return
}
err = csvfile2.Close()
if err != nil {
fmt.Println(err)
return
}
}
It owuld be easier to:
read your csv file into a string array (one line per element), for the two first lines only
var lines []string
scanner := bufio.NewScanner(file)
nblines := 0
for scanner.Scan() {
lines = append(lines, scanner.Text())
if nblines++; nblines >= 2 {
break
}
}
Then you can use a range lines to write those two lines in the destination file.
lines includes at most 2 elements.

Resources