Estou trabalhando em um pequeno aplicativo da web em Go que deve ser usado como uma ferramenta na máquina de um desenvolvedor para ajudar a depurar seus aplicativos / serviços da web. A interface do programa é uma página da web que inclui não apenas o HTML, mas algum JavaScript (para funcionalidade), imagens e CSS (para estilização). Estou planejando abrir o código-fonte deste aplicativo, então os usuários devem simplesmente ser capazes de executar um Makefile e todos os recursos irão para onde precisam. No entanto, também gostaria de poder simplesmente distribuir um executável com o mínimo de arquivos / dependências possível. Existe uma boa maneira de agrupar o HTML / CSS / JS com o executável, de modo que os usuários só tenham que baixar e se preocupar com um arquivo?
Agora, em meu aplicativo, veicular um arquivo estático se parece um pouco com isto:
// called via http.ListenAndServe
func switchboard(w http.ResponseWriter, r *http.Request) {
// snipped dynamic routing...
// look for static resource
uri := r.URL.RequestURI()
if fp, err := os.Open("static" + uri); err == nil {
defer fp.Close()
staticHandler(w, r, fp)
return
}
// snipped blackhole route
}
Portanto, é muito simples: se o arquivo solicitado existe em meu diretório estático, invoque o manipulador, que simplesmente abre o arquivo e tenta definir um bom Content-Type
antes de servir. Meu pensamento era que não há razão para que isso precise ser baseado no sistema de arquivos real: se houvesse recursos compilados, eu poderia simplesmente indexá-los pelo URI de solicitação e servi-los como tal.
Se não houver uma boa maneira de fazer isso ou se eu estiver latindo na árvore errada ao tentar fazer isso, me avise. Achei que o usuário final gostaria de ter o mínimo de arquivos possível para gerenciar.
Se houver tags mais apropriadas do que ir, sinta-se à vontade para adicioná-los ou me avisar.
go generate
um pequeno utilitário de linha de comando (empacotado com meu código-fonte) para converter os arquivos em[]byte
fatias que são incorporadas como variáveis no código, semelhante a comostringer
faz (consulte blog.golang.org / gerar ).Respostas:
O pacote go-bindata parece ser o que você está interessado.
https://github.com/go-bindata/go-bindata
Isso permitirá que você converta qualquer arquivo estático em uma chamada de função que pode ser incorporada em seu código e retornará uma fatia de byte do conteúdo do arquivo quando chamada.
fonte
Incorporação de arquivos de texto
Se estamos falando de arquivos de texto, eles podem ser facilmente incorporados ao próprio código-fonte. Basta usar as aspas para declarar o
string
literal assim:Dica de otimização:
Como na maioria das vezes você só precisa gravar o recurso em um
io.Writer
, você também pode armazenar o resultado de uma[]byte
conversão:A única coisa com a qual você deve ter cuidado é que os literais de string bruta não podem conter o caractere de aspas invertidas (`). Literais de string bruta não podem conter sequências (ao contrário dos literais de string interpretados), portanto, se o texto que você deseja incorporar contiver aspas, você terá que quebrar o literal de string bruto e concatenar aspas invertidas como literais de string interpretados, como neste exemplo:
O desempenho não é afetado, pois essas concatenações serão executadas pelo compilador.
Incorporando arquivos binários
Armazenando como uma fatia de byte
Para arquivos binários (por exemplo, imagens) mais compactos (em relação ao binário nativo resultante) e mais eficiente seria ter o conteúdo do arquivo como um
[]byte
em seu código-fonte. Isso pode ser gerado por toos / bibliotecas de terceiros, como go-bindata .Se você não quiser usar uma biblioteca de terceiros para isso, aqui está um snippet de código simples que lê um arquivo binário e gera o código-fonte Go que declara uma variável do tipo
[]byte
que será inicializada com o conteúdo exato do arquivo:Exemplo de saída se o arquivo contiver bytes de 0 a 16 (experimente no Go Playground ):
Armazenando como base64
string
Se o arquivo não for "muito grande" (a maioria das imagens / ícones se qualificam), existem outras opções viáveis também. Você pode converter o conteúdo do arquivo em Base64
string
e armazená-lo em seu código-fonte. Na inicialização do aplicativo (func init()
) ou quando necessário, você pode decodificá-lo para o[]byte
conteúdo original . Go tem bom suporte para codificação Base64 noencoding/base64
pacote.Converter um arquivo (binário) em base64
string
é tão simples quanto:Armazene a string de resultado base64 em seu código-fonte, por exemplo, como um
const
.Decodificá-lo é apenas uma chamada de função:
Armazenando conforme citado
string
Mais eficiente do que armazenar como base64, mas pode ser mais longo no código-fonte é armazenar a string literal entre aspas dos dados binários. Podemos obter a forma entre aspas de qualquer string usando a
strconv.Quote()
função:Para dados binários contendo valores de 0 a 64, esta é a aparência da saída (experimente no Go Playground ):
"\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?"
(Observe que
strconv.Quote()
acrescenta e adiciona uma aspa.)Você pode usar diretamente esta string entre aspas em seu código-fonte, por exemplo:
Está pronto para usar, não há necessidade de decodificá-lo; o unquoting é feito pelo compilador Go, em tempo de compilação.
Você também pode armazená-lo como uma fatia de byte, caso precise desta forma:
fonte
sh
arquivo a um executável go?também há uma maneira exótica - eu uso o plugin maven para construir projetos GoLang e permite usar o pré - processador JCP para embutir blocos binários e arquivos de texto em fontes. No caso, o código é semelhante à linha abaixo ( e alguns exemplos podem ser encontrados aqui )
fonte
sh
ou um executável como acimash
arquivo? Não tenho certeza do que você quer dizer. Se você quiser que tudo em um diretório seja incorporado, eu fiz issogo-bindata
. Por exemplo, se eu colocar//go:generate $GOPATH/bin/go-bindata -prefix=data/ -pkg=$GOPACKAGE data/
um arquivo go (não gerado),go generate ./...
executarei go-bindata no diretório do pacote, incorporando tudo em um subdiretório de dados, mas com o prefixo 'data /' removido.Como uma alternativa popular ao
go-bindata
mencionado em outra resposta, mjibson / esc também incorpora arquivos arbitrários, mas lida com árvores de diretório de maneira particularmente conveniente.fonte