Server-Side Scripting/Strings and Files/Go

routes/lesson5.go

edit
// This program reads a user-selected text file of Celsius
// temperatures and converts the temperatures to Fahrenheit.
//
// File format:
// Country,MaximumTemperature
// Bulgaria,45.2 °C
// Canada,45 °C
//
// References:
//  https://www.mathsisfun.com/temperature-conversion.html
//  https://golang.org/doc/
//  https://tutorialedge.net/golang/go-file-upload-tutorial/

package routes

import (
    "html/template"
    "io/ioutil"
    "net/http"
    "mime/multipart"
    "path/filepath"
	"strconv"
    "strings"
)

func Lesson5(response http.ResponseWriter, request *http.Request) {
	response.Header().Set("Content-Type", "text/html; charset=utf-8")

	type Data struct {
		Table  template.HTML
	}
	
	result := ""

    switch request.Method {
        case "GET":
            result = ""
        case "POST":
            result = "<h1>Temperature Conversion</h1>";
            file, handler, err := request.FormFile("file")
            if err != nil {
                result += err.Error()
            }
            result += "<h2>" + handler.Filename + "</h2>"
            result += processFile(file);
        default:
            result = "Unexpected request method: " + request.Method
    }

	data := Data{template.HTML(result)}
	path := filepath.Join("templates", "lesson5.html")
	parsed, _ := template.ParseFiles(path)
	parsed.Execute(response, data)
}

func processFile(file multipart.File) string {
    result := "<table><tr><th>Fahrenheit</th><th>Celsius</th></tr>"

    bytes, err := ioutil.ReadAll(file)
    if (err != nil) {
        return err.Error()
    }

    text := string(bytes)
    text = strings.TrimSpace(text)
    lines := strings.Split(text, "\n")
    for _, line := range lines {
        result += processLine(line)
    }
    result += "</table>"
    return result
}

func processLine(line string) string {
    // skip heading
    index := strings.Index(line, "Country,MaximumTemperature")
    if index >= 0 {
        return ""
    }

    start := strings.Index(line, ",")
    end := strings.Index(line, " °C")
    if start < 0 || end < 0 {
        return "Invalid file format: " + line + "<br>"
    }

    celsius, err := strconv.ParseFloat(line[start + 1:end], 64)
    if err != nil {
        return err.Error()
    }

    fahrenheit := celsius * 9 / 5 + 32
    result := "<tr><td>" + strconv.FormatFloat(celsius, 'f', 1, 64) + "</td>"
    result += "<td>" + strconv.FormatFloat(fahrenheit, 'f', 1, 64) + "</td></tr>"

    return result
}

templates/lesson5.html

edit
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Lesson 5</title>
    <link rel="stylesheet" href="styles.css">
    <style>
        p {
            min-height: 1em;
        }
    </style>
</head>

<body>
    <h1>Temperature Conversion</h1>
    <p>Select a file of Fahrenheit temperatures for conversion:</p>
    <form method="POST" enctype="multipart/form-data">
        <input type="hidden" name="MAX_FILE_SIZE" value="1048576" />
        <input type="file" id="file" name="file">
        <input type="submit">
    </form>
    {{.Table}}
</body>

</html>

Try It

edit

See Server-Side Scripting/Routes and Templates/Go to create a test environment.