Last_Node_Standing
Last_Node_Standing

Reputation: 429

Trouble getting content type of file in Go

I have a function in which I take in a base64 string and get the content of it (PDF or JPEG). I read in the base64 content, convert it to bytes and decode it into the file that it is. I then create a file where I will output the decoded file (JPEG or PDF). Then I write the bytes to it. Then I call my GetFileContentType on it and it returns to me an empty string. If I run the functions separately, as in I first the first function to create the decoded file, and end it. And then call the second function to get the content type, it works and returns it as JPEG or PDF. What am I doing wrong here? And is there a better way to do this?

func ConvertToJPEGBase64(
    src string,
    dst string,
) error {

    b, err := ioutil.ReadFile(src)
    if err != nil {
        return err
    }
    str := string(b)

    byteArray, err := base64.StdEncoding.DecodeString(str)
    if err != nil {
        return err
    }

    f, err := os.Create(dst)
    if err != nil {
        return err
    }

    if _, err := f.Write(byteArray); err != nil {
        return err
    }

    f.Sync()
    filetype, err := client.GetFileContentType(f)
    if err != nil {
        return err
    }
    if strings.Contains(filetype, "jpeg") {
             // do something
    } else {
            // do something else
    }

    return nil
}

// GetFileContentType tells us the type of file
func GetFileContentType(out *os.File) (string, error) {

    // Only the first 512 bytes are used to sniff the content type.
    buffer := make([]byte, 512)
    _, err := out.Read(buffer)
    if err != nil {
        return "", err
    }
    contentType := http.DetectContentType(buffer)

    return contentType, nil
}

Upvotes: 0

Views: 862

Answers (1)

Thundercat
Thundercat

Reputation: 120979

The problem is that GetFileContentType reads from the end of the file. Fix this be seeking back to the beginning of the file before calling calling GetFileContentType:

 if _, err := f.Seek(io.SeekStart, 0); err != nil {
     return err
 }

A better fix is to use the file data that's already in memory. This simplifies the code to the point where there's no need for the GetFileContentType function.

func ConvertToJPEGBase64(
    src string,
    dst string,
) error {

    b, err := ioutil.ReadFile(src)
    if err != nil {
        return err
    }
    str := string(b)

    byteArray, err := base64.StdEncoding.DecodeString(str)
    if err != nil {
        return err
    }

    f, err := os.Create(dst)
    if err != nil {
        return err
    }
    defer f.Close() // <-- Close the file on return.

    if _, err := f.Write(byteArray); err != nil {
        return err
    }

    fileType := http.DetectContentType(byteArray) // <-- use data in memory
    if strings.Contains(fileType, "jpeg") {
             // do something
    } else {
            // do something else
    }

    return nil
}

More code can be eliminated by using ioutil.WriteFile:

func ConvertToJPEGBase64(src, dst string) error {
    b, err := ioutil.ReadFile(src)
    if err != nil {
        return err
    }

    byteArray, err := base64.StdEncoding.DecodeString(string(b))
    if err != nil {
        return err
    }

    if err := ioutil.WriteFile(dst, byteArray, 0666); err != nil {
        return err
    }

    fileType := http.DetectContentType(byteArray)
    if strings.Contains(fileType, "jpeg") {
        // do something
    } else {
        // do something else
    }

    return nil
}

Upvotes: 3

Related Questions