Reading binary file

Hi, all! I am trying to read binary file to string and besides some text I am getting “?” mostly “?” can anyone, please help/explain it? how do I read binary file and save its contents as a text? thank you!

Hey @sm3,

If I am understanding you correctly, you want to read using the binary package.

Here are some examples you can check out:

Here’s a better example probably better suited to what you asked, but also this line from the docs in mind.
Read reads structured binary data from r into data.:

Edit: I added the examples from below to my repo to make it easier for you: read and write binary files.

writefile.go (write a binary file with a float64 value):

package main

import (
	"encoding/binary"
	"log"
	"os"
)

func main() {
	f, err := os.Create("binaryfile")
	if err != nil {
		log.Fatalln(err)
	}
	defer func() {
		if err := f.Close(); err != nil {
			log.Fatalln(err)
		}
	}()

	b := []byte{0x18, 0x2d, 0x44, 0x54, 0xfb, 0x21, 0x09, 0x40}
	err = binary.Write(f, binary.LittleEndian, b)
	if err != nil {
		log.Fatalln(err)
	}

}

readfile.go (read a float64 value from a binary file):

package main

import (
	"encoding/binary"
	"fmt"
	"log"
	"os"
)

func main() {
	f, err := os.Open("binaryfile")
	if err != nil {
		log.Fatalln(err)
	}
	defer f.Close()

	var pi float64
	err = binary.Read(f, binary.LittleEndian, &pi)
	if err != nil {
		log.Fatalln(err)
	}

	fmt.Println(pi)
}
1 Like

thank you very much @radovskyb! :slight_smile: this code reads just one value. to make it read the entire file… do I use scanner in the loop? …something else?

No problem :slight_smile:

Anyway, since binary.Read reads structured binary data, if you know the format of the data, you can read more than one field in at once into a structured format (a struct in this case).

writefile.go (write a binary file with structured values):

package main

import (
	"encoding/binary"
	"log"
	"os"
)

type Integers struct {
	i1 uint16
	i2 int32
	i3 int64
}

func main() {
	f, err := os.Create("binaryfile")
	if err != nil {
		log.Fatalln(err)
	}
	defer func() {
		if err := f.Close(); err != nil {
			log.Fatalln(err)
		}
	}()

	i := Integers{i1: 16, i2: 32, i3: 64}
	err = binary.Write(f, binary.LittleEndian, i)
	if err != nil {
		log.Fatalln(err)
	}
}

readfile.go (read a binary file into a structured format):

package main

import (
	"encoding/binary"
	"fmt"
	"log"
	"os"
)

type Integers struct {
	I1 uint16
	I2 int32
	I3 int64
}

func main() {
	f, err := os.Open("binaryfile")
	if err != nil {
		log.Fatalln(err)
	}
	defer f.Close()

	i := Integers{}
	err = binary.Read(f, binary.LittleEndian, &i)
	if err != nil {
		log.Fatalln(err)
	}
	fmt.Println(i)
}
1 Like

But also, to answer what you probably wanted to know, you can also do this:

Edit: I added both this and the previous example in the folder here (https://github.com/radovskyb/go-packages/tree/master/encoding/binary) under read_and_write_multiple_values and read_and_write_structured_data.

package main

import (
	"encoding/binary"
	"fmt"
	"io"
	"log"
	"os"
)

func main() {
	f, err := os.Open("binaryfile")
	if err != nil {
		log.Fatalln(err)
	}
	defer f.Close()

	for {
		var val float64
		err = binary.Read(f, binary.LittleEndian, &val)
		if err != nil {
			if err == io.EOF {
				break
			}
			log.Fatalln(err)
		}
		fmt.Println(val)
	}
}
1 Like

Benjamin, thank you so much. “if you know format.” well… it is 3dm file produced by Rhinoceros package. it contains description of curves. it uses OpenNurbs libs. I have managed to compile cpp file, (supplied by opennurbs), which reads entire 3dm file to text, but ideally I would like this to be done by golang. this is just a part of what I am trying to do, as as soon 3dm file contents are converted to text, lines coordinates will be extracted out of it, sorted out and then inserted into text file, producing eventually gcode. speaking of format… I have no answer… most I could find is this: (http://modo.docs.thefoundry.co.uk/modo/801/help/pages/gettingstarted/copyright/opennurbs-license.txt): “OpenNURBS uses UNICODE to store text information in 3DM files. At the time of this release, support for UNICODE / ASCII conversion on UNIX platforms is spotty at best.” …not much… :frowning:

I have not personally heard of .3dm files before, but have you tried to simply see what the output looks like if you try something like this:

package main

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

func main() {
	data, err := ioutil.ReadFile("file.3dm")
	if err != nil {
		log.Fatalln(err)
	}
	fmt.Printf("%s", data)
}

Other than that, since I don’t really know anything about .3dm I probably can’t help you with that, but I hope my other replies can be helpful to you.

Benjamin, thank you very much - eventually I got some results!
3.816924002507374e+180
3.6841508083255655e+180
2.432084514973514e-152
1.8244329414232852e-76
7.0238060681e-312
7.347316541763758e+223
8.587780573809274e-53

I am trying to understand it… so, values produced by this program… are they literal translation of hex numbers in the file or representation of the original value stored in the binary format? as this file (if read by this cpp program) will look like this:
OpenNURBS Archive File: oval-el1-2-offset.3dm
Successfully read.
Model is valid.
Model summary:
File version: 50
File openNURBS version: 201412015
File length: 82039 bytes
Start section comments:
Rhinoceros 5.0 - English Commercial, build 0000-00-00 -
(compiled Aug 29 2016)
SDK Version: 201103025.201412015
OpenNURBS Version: 201412015
3dm Version: 5
Operating System: Apple Intel 64-bit Platform OS X
Version 10.11.6 (Build 15G1004)
3DM I/O processor: OpenNURBS toolkit version 201412015
(compiled on Aug 29 2016)

  Revision history:
    Created by: pascal
    Created on: Tuesday August 16 17:55:38 2005
    Last edited by: pascal
    Last edited on: Thursday September 29 17:04:13 2016
    Revision count: 41


(and below of this is what I actually need from this file)
Object table:
Object 0:
object name = ""
object uuid = C6DEC0C4-07BE-4247-81BF-F8B7303CE734
object mode = normal
object layer index = 2
object material index = -1
material source = layer material
ON_ArcCurve: domain = [1.31152,1.49705]
center = (4.3097045023593523, 13.94671016920293, 0)
radius = 6.2127
length = 0.185531
start = (5.3191840354325279, 7.8165767619200563, 0)
end = (5.5017725604722845, 7.8494519112966747, 0)

Hey @sm3,

Since I really have never worked with .3dm files, I don’t think I can be much help in this area.

However, one thing I can suggest is skimming through the source code of the C++ program that you are using to decode the .3dm file with currently and checking how it decodes it and then trying to write a similar solution with Go.

Based on what I’ve seen as the output, I’m not so sure if completely decoding it as binary is the right thing to do yet, but I can’t be sure.

If the source code for the decoder in C++ is not a very big program, you could link to it on Github or somewhere else and maybe I or some one else can point you in the right direction or help you understand it. (been a while since I’ve written any C++ :stuck_out_tongue:)

thank you, Benjamin - appreciate your help. yeah… I’ve been trying pretty much what you have suggested,
as of now, I think, I just use this c++ program as it and parse its output with golang. I am just running it with exec.Command in golang and it produces its output to separate txt file. it all works - just thought it would be better and “easier” to user golang for everything… but looks like not this time :slight_smile:

thank you for all your help.
cheers,
Slava

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.