Read Lines from a Text File into Slice of Structs

Hello fellow Gophers.

I am trying to read some text that includes first and last names into a Struct called Name that has a first and last name field.

I am a bit stuck. First and foremost, to get the strings in the text file to be recognized as firstName and lastName respectively, would I use “strings.split(” “)”? if I do this, this would essentially turn all lines of code into multiple slices thus making it harder to work with the slice of Names and I don’t want that. Here is what I have so far:

// Write a program which reads information from a file and represents it in a slice of structs.
// Assume that there is a text file which contains a series of names. Each line of the text file has
// a first name and a last name, in that order, separated by a single space on the line.
// Your program will define a name struct which has two fields, fname for the first name, and lname for
// the last name. Each field will be a string of size 20 (characters).
// Your program should prompt the user for the name of the text file. Your program will successively read
// each line of the text file and create a struct which contains the first and last names found in the file.
// Each struct created will be added to a slice, and after all lines have been read from the file,
// your program will have a slice containing one struct for each line in the file. After reading all
// lines from the file, your program should iterate through your slice of structs and print the first and
// last names found in each struct. Submit your source code for the program, “read.go”.

package main

import (
	"bufio"
	"fmt"
	"log"
	"os"
	"strings"
)

//Name Struct
type Name struct {
	fname string
	lname string
}

func main() {
	inputReader := bufio.NewReader(os.Stdin)
	names := make([]Name, 0, 3)

	fmt.Println("Welcome! Please enter the name of the text file:")
	fileName, err := inputReader.ReadString('\n')
	if err != nil {
		log.Fatal(err)
	}

	fileName = strings.Trim(fileName, "\n")

	file, err := os.Open(fileName)
	if err != nil {
		log.Fatal(err)
	}

	defer file.Close()

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		s := strings.Split(scanner.Text(), " ")
		var aName Name
		aName.fname, aName.lname = s[0], s[1]
		names = append(names, aName)

	}

	for _, v := range names {
		fmt.Println(v)
	}

}

Thanks in advance!

I forgot to mention that I am getting the following error: "panic: runtime error: index out of range

goroutine 1"

I believe it has something to do with my for loop where I state for scanner.Scan(). thanks!

So I made some modifications everything is almost working except for the fact that it does not return all the names now that are from the text file that should be in the slice of structs. I added a break in the for scanner.Scan() for loop:

// Write a program which reads information from a file and represents it in a slice of structs.
// Assume that there is a text file which contains a series of names. Each line of the text file has
// a first name and a last name, in that order, separated by a single space on the line.
// Your program will define a name struct which has two fields, fname for the first name, and lname for
// the last name. Each field will be a string of size 20 (characters).
// Your program should prompt the user for the name of the text file. Your program will successively read
// each line of the text file and create a struct which contains the first and last names found in the file.
// Each struct created will be added to a slice, and after all lines have been read from the file,
// your program will have a slice containing one struct for each line in the file. After reading all
// lines from the file, your program should iterate through your slice of structs and print the first and
// last names found in each struct. Submit your source code for the program, “read.go”.

package main

import (
	"bufio"
	"fmt"
	"log"
	"os"
	"strings"
)

//Name Struct
type Name struct {
	fname string
	lname string
}

func main() {
	inputReader := bufio.NewReader(os.Stdin)
	names := make([]Name, 0, 3)

	fmt.Println("Welcome! Please enter the name of the text file:")
	fileName, err := inputReader.ReadString('\n')
	if err != nil {
		log.Fatal(err)
	}

	fileName = strings.Trim(fileName, "\n")

	file, err := os.Open(fileName)
	if err != nil {
		log.Fatal(err)
	}

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		s := strings.Split(scanner.Text(), " ")
		if !scanner.Scan() {
			break
		}

		var aName Name
		aName.fname, aName.lname = s[0], s[1]
		names = append(names, aName)

	}

	file.Close()

	for _, v := range names {
		fmt.Println(v.fname, v.lname)
	}

}

However, instead of returning a list like:
Scott Summers
Bruce Banner
Danny Rand
Luke Cage
Peter Parker
Jessica Jones
Matt Murdock

I get a list like this:
Scott Summers
Danny Rand
Peter Parker

Why are names being truncated? Thanks!

scanner.Scan() is what advances to the next line. You’re calling it twice per loop now.

For your previous panic, check the length of the slice returned by Split() before trying to access elements in it.

1 Like

well i didn’t use the " bufio " to read name of file…instead used " fmt.Scan " and didn’t use
" if !scanner.Scan " and it just worked for me…

it displays all names from file now

//code here

package main

import “fmt”
import “os”
import “strings”
import “bufio”

type Name struct {

fname string
lname string

}

func main() {
slice := make([]Name, 0, 3)
fmt.Println(“Enter file name (same directory):”)

var fileName string
fmt.Scan(&fileName)

file, e := os.Open(fileName)
if e != nil {
	fmt.Println("Error is = ",e)
}

scanner := bufio.NewScanner(file)
for scanner.Scan() {

	s := strings.Split(scanner.Text(), " ")
	var namee Name
	namee.fname, namee.lname = s[0], s[1]
	slice = append(slice, namee)

}

file.Close()

fmt.Println("\n********************\n")

for _, v := range slice {
	fmt.Println(v.fname, v.lname)
}

}