How can I write a string to a binary file? - go

such as, I write 'A' but in file it is '1000001' ,
how can I do ?
I have tried
buf := new(bytes.Buffer)
data := []int8{65, 80}
for _, i := range data {
binary.Write(buf, binary.LittleEndian, i)
fp.Write(buf.Bytes())
}
but I got string 'AP' in file not a binary code

I didn't really understand the question, but perhaps you want something like:
package main
import (
"fmt"
"log"
"os"
)
func main() {
f, err := os.OpenFile("out.txt", os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0600)
if err != nil {
log.Fatal(err)
}
for _, v := range "AP" {
fmt.Fprintf(f, "%b\n", v)
}
f.Close()
}
which gives:
$ cat out.txt
1000001
1010000

Related

Find byte offset of a pattern in Golang

We can find the byte offset of a pattern from file by
"grep -ob pattern filename";
However, grep is not utf8 safe.
How do I find byte offset of a pattern in Go? The file is process log, which can be in TB.
This is what I want to get in Go:
$ cat fname
hello world
findme
hello 世界
findme again
...
$ grep -ob findme fname
12:findme
32:findme
FindAllStringIndex(s string, n int) returns byte start/finish indexes (i.e., slices) of all successive matches of the expression:
package main
import "fmt"
import "io/ioutil"
import "regexp"
func main() {
fname := "C:\\Users\\UserName\\go\\src\\so56798431\\fname"
b, err := ioutil.ReadFile(fname)
if err != nil {
panic(err)
}
re, err := regexp.Compile("findme")
if err != nil {
// handle error
}
fmt.Println(re.FindAllStringIndex(string(b), -1))
}
Output:
[[12 18] [32 38]]
Note: I did this on Microsoft Windows, but saved the file in UNIX format (linefeed); if input file saved in Windows format (carriage return & linefeed) the byte offsets would increment to 13 and 35, respectively.
UPDATE: for large files, use bufio.Scanner; for example:
package main
import (
"bufio"
"fmt"
"log"
"os"
"regexp"
)
func main() {
fname, err := os.Open("C:\\Users\\UserName\\go\\src\\so56798431\\fname")
if err != nil {
log.Fatal(err)
}
defer fname.Close()
re, err := regexp.Compile("findme")
if err != nil {
// handle error
}
scanner := bufio.NewScanner(fname)
bytesRead := 0
for scanner.Scan() {
b := scanner.Text()
//fmt.Println(b)
results := re.FindAllStringIndex(b, -1)
for _, result := range results {
fmt.Println(bytesRead + result[0])
}
// account for UNIX EOL marker
bytesRead += len(b) + 1
}
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
}
Output:
12
32

Get JSON paths to value from JSON

I'm trying to write a func to get all paths to values from a yaml file and I don't know know how that possible, here is my code:
func getpath(fileyaml) string {
if _, err := os.Stat(fileyaml); err == nil {
bfile, err := ioutil.ReadFile(fileyaml)
bjson, err := yaml.YAMLToJSON(bfile)
if err != nil {
fmt.Printf("YAMLToJSON err: %v\n", err)
}
json := string(bjson)
println json
paths := ? // don't know
return path
here my yaml file :
sentinel:
number: 3
server:
number: 7
config:
fere_size: 5
lcmea:
eza_ze: all
my function will convert it to a json: {"config":{"fere_size":5},"lcmea":{"eza_hooks":"all"},"sentinel":{"number":3},"server":{"number":7}}
the output that i want :
sentinel.number=3, server.number=3,config.fere_size=5,lcmea.eza_ze=all
how to parse this json in order to get this desired output?
I'm using "github.com/tidwall/gjson" to read the yaml and convert it to json
This is an example of how you could do it: https://play.golang.org/p/7yLq_PDLdXF
It is pretty naive and definitely could be improved, but it may give you an idea about how to parse the yaml file and then print the output in your desired format:
package main
import (
"fmt"
"log"
"strings"
"github.com/go-yaml/yaml"
)
var data = `
sentinel:
number: 3
server:
number: 7
config:
fere_size: 5
lcmea:
eza_ze: all
`
func main() {
m := make(map[string]map[string]interface{})
err := yaml.Unmarshal([]byte(data), &m)
if err != nil {
log.Fatalf("error: %v", err)
}
out := []string{}
for k, v := range m {
for j, i := range v {
out = append(out, fmt.Sprintf("%s.%v=%v", k, j, i))
}
}
fmt.Println(strings.Join(out, ", "))
}
It will return:
$ go run main.go
sentinel.number=3, server.number=7, config.fere_size=5, lcmea.eza_ze=all
It is using https://github.com/go-yaml/yaml, check more examples on the README.md

Weird channel behavior in go

package main
import (
"encoding/json"
"fmt"
"/something/models"
"os"
"path/filepath"
"runtime"
)
func WriteDeviceToFile(d chan *models.Device, fileName string) {
_, b, _, _ := runtime.Caller(0)
basepath := filepath.Dir(b)
filePath := basepath + "/dataFile/" + fileName
var f *os.File
var err error
f, _ = os.OpenFile(filePath, os.O_APPEND|os.O_WRONLY, 0600)
defer f.Close()
for device := range d {
deviceB, err := json.Marshal(device)
fmt.Println(string(deviceB))
if err == nil {
if _, err = f.WriteString(string(deviceB)); err != nil {
panic(err)
}
} else {
panic(err)
}
}
}
func main() {
deviceChan := make(chan *models.Device)
go WriteDeviceToFile(deviceChan, "notalive.txt")
d := models.NewDevice("12346", "")
deviceChan <- d
d = models.NewDevice("abcd", "")
deviceChan <- d
close(deviceChan)
}
This only works with at least two devices sent to channel. With only one device in deviceChan, the function does not receive anything. Is the channel gone before the WriteDeviceToFile gets to it?
The program exits when main returns. Nothing prevents main from exiting before the files are written

In Golang I'm getting the record through exe command. how to print it line by line?

I want to print the results line by line.
I'm getting the record's data through exe command.
Here is the code:
package main
import (
"bufio"
"fmt"
"os/exec"
)
func main() {
app := "df"
//app := "buah"
arg0 := "-h"
cmd := exec.Command(app, arg0)
stdout, err := cmd.Output()
if err != nil {
println(err.Error())
return
}
// bytes, _ := ioutil.ReadAll(stdout)
s := bufio.NewScanner(stdout)
fmt.Println(s)
}
Thanks in advance.
Any help is greatly appreciated.
It is simple:
a := []string{}
for s.Scan() {
a = append(a, s.Text())
}
And You have a slice of strings.

Golang, is there a better way read a file of integers into an array?

I need to read a file of integers into an array. I have it working with this:
package main
import (
"fmt"
"io"
"os"
)
func readFile(filePath string) (numbers []int) {
fd, err := os.Open(filePath)
if err != nil {
panic(fmt.Sprintf("open %s: %v", filePath, err))
}
var line int
for {
_, err := fmt.Fscanf(fd, "%d\n", &line)
if err != nil {
fmt.Println(err)
if err == io.EOF {
return
}
panic(fmt.Sprintf("Scan Failed %s: %v", filePath, err))
}
numbers = append(numbers, line)
}
return
}
func main() {
numbers := readFile("numbers.txt")
fmt.Println(len(numbers))
}
The file numbers.txt is just:
1
2
3
...
ReadFile() seems too long (maybe because of the error handing).
Is there a shorter / more Go idiomatic way to load a file?
Using a bufio.Scanner makes things nice. I've also used an io.Reader rather than taking a filename. Often that's a good technique, since it allows the code to be used on any file-like object and not just a file on disk. Here it's "reading" from a string.
package main
import (
"bufio"
"fmt"
"io"
"strconv"
"strings"
)
// ReadInts reads whitespace-separated ints from r. If there's an error, it
// returns the ints successfully read so far as well as the error value.
func ReadInts(r io.Reader) ([]int, error) {
scanner := bufio.NewScanner(r)
scanner.Split(bufio.ScanWords)
var result []int
for scanner.Scan() {
x, err := strconv.Atoi(scanner.Text())
if err != nil {
return result, err
}
result = append(result, x)
}
return result, scanner.Err()
}
func main() {
tf := "1\n2\n3\n4\n5\n6"
ints, err := ReadInts(strings.NewReader(tf))
fmt.Println(ints, err)
}
I would do it like this:
package main
import (
"fmt"
"io/ioutil"
"strconv"
"strings"
)
// It would be better for such a function to return error, instead of handling
// it on their own.
func readFile(fname string) (nums []int, err error) {
b, err := ioutil.ReadFile(fname)
if err != nil { return nil, err }
lines := strings.Split(string(b), "\n")
// Assign cap to avoid resize on every append.
nums = make([]int, 0, len(lines))
for _, l := range lines {
// Empty line occurs at the end of the file when we use Split.
if len(l) == 0 { continue }
// Atoi better suits the job when we know exactly what we're dealing
// with. Scanf is the more general option.
n, err := strconv.Atoi(l)
if err != nil { return nil, err }
nums = append(nums, n)
}
return nums, nil
}
func main() {
nums, err := readFile("numbers.txt")
if err != nil { panic(err) }
fmt.Println(len(nums))
}
Your solution with fmt.Fscanf is fine. There are certainly a number of other ways to do though, depending on your situation. Mostafa's technique is one I use a lot (although I might allocate the result all at once with make. oops! scratch that. He did.) but for ultimate control you should learn bufio.ReadLine. See go readline -> string for some example code.

Resources