Generating File for Download from Server in golang

I have a requirement that I should be able to create a File with some random text on click of a button from Frontend. I am able to create the file in Backend but not able to download the file in the Client Machine from where it is requested. It always creates the files in the Server Machine.

package main

import (
    "bytes"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "os"
    "path/filepath"
    "strconv"
    "strings"
)

func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    http.ServeFile(w, r, r.URL.Path[1:])

    var slice = r.FormValue("slice")
    fmt.Printf("slice len %d", len(slice))

    if len(slice) > 0 {
        fmt.Println("inside split file")
        //splitfile(fullFileWithPath, slice)
    } else {

        file2, header2, err2 := r.FormFile("file2")
        file3, header3, err3 := r.FormFile("file3")
        if file2 != nil && file3 != nil {
            data2, dataerr2 := ioutil.ReadAll(file2)
            data3, dataerr3 := ioutil.ReadAll(file3)
            if dataerr2 != nil {
                panic(dataerr2)
            }
            if dataerr3 != nil {
                panic(dataerr3)
            }
            var joinfilesArray = header2.Filename + "," + header3.Filename
            if len(joinfilesArray) > 0 {
                joinfile(joinfilesArray, data2, data3)
            }

        }

        if err2 != nil {
            panic(err2)
        }
        if err3 != nil {
            panic(err2)
        }

    }

})
log.Fatal(http.ListenAndServe(":8081", nil))
}

func joinfile(fileArray string, x []byte, y []byte) {

fmt.Println("entering joinfile")
var files []string
files = strings.Split(fileArray, ",")
//check file types are same
if checkfileType(files) {
    var z []byte
    z = x
    var j int
    for j = 0; j < len(y); j++ {
        z = append(z, y[j])
    }
    var mergefileName = filepath.Dir(files[0]) + "\\files" + "\\Merge" + filepath.Ext(files[0])
    var tempfileName = filepath.Dir(files[0]) + "\\temp" + "\\Merge" + filepath.Ext(files[0])
    fmt.Printf("mergefileName:%s\n", mergefileName)
    os.Create(tempfileName)
    err := ioutil.WriteFile(tempfileName, z, 0644)

    downloadToFile("localhost:8081/", mergefileName, tempfileName)
    if err != nil {
        panic(err)
    }

} else {
    fmt.Println("No call")
}
}

func httpDownload(uri string, tmp string) ([]byte, error) {
    fmt.Printf("HTTPDownload From: %s.\n", uri)
    res, err := http.Get(uri)
    if err != nil {
        log.Fatal(err)
    }
    defer res.Body.Close()
    d, err := ioutil.ReadFile(tmp)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("ReadFile: Size of download: %d\n", len(d))
    return d, err
}

func writeFile(dst string, d []byte) error {
    fmt.Printf("WriteFile: Size of download: %d\n", len(d))
    err := ioutil.WriteFile(dst, d, 0444)
    if err != nil {
        log.Fatal(err)
    }
    return err
}

func downloadToFile(uri string, dst string, tmp string) {
    fmt.Printf("DownloadToFile From: %s.\n", uri)
    if d, err := httpDownload(uri, tmp); err == nil {
        fmt.Printf("downloaded %s.\n", uri)
        if writeFile(dst, d) == nil {
            fmt.Printf("saved %s as %s\n", uri, dst)
        }
    }
}
func checkfileType(files []string) bool {
    fmt.Println("entering checkfileType")
    var i int
    var result bool
    for i = 0; i < len(files); i++ {
        var extension = filepath.Ext(files[i])
        if i == 0 {
            continue
        } else {
            result = strings.HasSuffix(files[i-1], extension)
            if result == false {
                break
            }
        }
    }

    return result
}

func splitfile(fullFileWithPath string, slice string) {
    fmt.Println("entering splitfile")

    if len(fullFileWithPath) > 0 {

        b, err := ioutil.ReadFile(fullFileWithPath)
        if err != nil {
            panic(err)
        }
        var extension = filepath.Ext(fullFileWithPath)
        var directory = filepath.Dir(fullFileWithPath)
        var fileName = filepath.Base(fullFileWithPath)
        fileNameWithoutExt := strings.TrimSuffix(fileName, filepath.Ext(fileName))
        var counter int
        slices, _ := strconv.Atoi(slice)
        sz := len(b)
        fmt.Println(sz)
        var sliceCount int
        sliceSize := sz / slices
        copyOfSliceSize := sz / slices
        fmt.Println(sliceSize)
        for counter < slices {
            counter++
            var buffer bytes.Buffer
            buffer.WriteString(directory)
            buffer.WriteString("/")
            buffer.WriteString(fileNameWithoutExt)
            buffer.WriteString("_")
            t := strconv.Itoa(counter)
            buffer.WriteString(t)
            buffer.WriteString(extension)
            os.Create(buffer.String())
            song := b[sliceCount:(sliceSize)]
            sliceCount = sliceSize
            sliceSize += copyOfSliceSize
            err = ioutil.WriteFile(buffer.String(), song, 0644)
        }
    }
}

What happens instead?

I couldn’t figure out what the provided code intended to do, so I wrote an example that “creates a File with some random text” when a browser GETs some url from the server.

package main

import (
	"bytes"
	"io"
	"log"
	"math"
	"math/rand"
	"net/http"
	"time"
)

func main() {
	log.SetFlags(log.Lshortfile)
	http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
		modtime := time.Now()
		content := randomContent(modtime.UnixNano(), 1024)

		// ServeContent uses the name for mime detection
		const name = "random.txt"

		// tell the browser the returned content should be downloaded
		w.Header().Add("Content-Disposition", "Attachment")

		http.ServeContent(w, req, name, modtime, content)
	})

	log.Fatal(http.ListenAndServe(":8081", nil))
}

func randomContent(seed int64, length int) io.ReadSeeker {
	r := rand.New(rand.NewSource(seed))

	content := make([]byte, length, length)
	for i := range content {
		b := byte(r.Intn(math.MaxUint8))

		b = b%('~'-' ') + ' ' // make it a visible character

		content[i] = b
	}

	return bytes.NewReader(content)
}

Unlike ServeFile, ServeContent does not touch the disk (on the server).

Replace randomContent with whatever content generator you need.

3 Likes

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