goland check file type for xlsx

Viewed 74

Go standard library facility to check file type for xlsx file gives something like this

import (
    "fmt"
    "log"
    "net/http"
    "os"
)

func main() {
    f, err := os.Open("file_c.xlsx")
    if err != nil {
        log.Fatal(err.Error())
    }
    defer f.Close()
    buf := make([]byte, 512)
    _, err = f.Read(buf)
    if err != nil {
        log.Fatal(err.Error())
    }
    contentType := http.DetectContentType(buf)
    fmt.Println(contentType)
}

and that prints:

application/zip

This package -> https://github.com/h2non/filetype

import (
    "fmt"
    "io/ioutil"
    "net/http"
    "os"

    "github.com/h2non/filetype"
)

func main() {
    buf, _ := ioutil.ReadFile("file_c.xlsx")
    kind, _ := filetype.Match(buf)
    if kind == filetype.Unknown {
        fmt.Println("unknown")
        return
    }
    fmt.Printf("file type %s. MIME %s\n", kind.Extension, kind.MIME.Value)
}

prints:

file type xlsx. MIME application/vnd.openxmlformats-officedocument.spreadsheetml.sheet

However when I have code like this:

// where file is of type *multipart.FileHeader
mpf, err := file.Open()
    if err != nil {
        wlog.Errorf("could not open %s file", file.Filename)
    } else {
        defer mpf.Close()
    }
buf := make([]byte, 512)
    _, err = mpf.Read(buf)
    if err != nil {
        wlog.Error("failed to read file")
    } else {
        kind, _ := filetype.Match(buf)
        if kind == filetype.Unknown {
            wlog.Info("unknown file type")
        } else {
            wlog.Infof("file type %s. MIME %s\n", kind.Extension, kind.MIME.Value)
        }
    }

prints:

file type zip. MIME application/zip

so information about xlsx file is lost somewhere in the middle even when I use this external code -> https://github.com/h2non/filetype Do you have any idea why or what am I doing wrong?

2 Answers

This

buf, _ := ioutil.ReadFile("file_c.xlsx")
kind, _ := filetype.Match(buf)

works because it gets to scan the entire file. This

buf := make([]byte, 512)
// ...
kind, _ := filetype.Match(buf)

does not because it only gets to see the first 512 bytes, which is not enough to identify the file definitively as XLSX. An XLSX file is just a zip file with a certain pattern of contents, so it defaults to the more generic ZIP type (which is technically also correct).

You can view the implementation to see just how much data it's scanning through to detect file type - up to several kilobytes.

This is now really an answer but I've found another problem with all those "libraries" which suppose to recognize type of file.

buf, _ := ioutil.ReadFile("exe_file_with_csv_extension.csv")
kind, _ := filetype.Match(buf)

fmt.Printf("file type %s. MIME %s\n", kind.Extension, kind.MIME.Value)
fmt.Println(http.DetectContentType(buf))

this will print:

file type exe. MIME application/vnd.microsoft.portable-executable
application/octet-stream

which is wrong because it is executable file with extension changed to csv but for "real" csv file first library returns "unknown" so are there any more reliable tools for this job?

Related