Estoy trabajando en una pequeña aplicación web en Go que está destinada a utilizarse como herramienta en la máquina de un desarrollador para ayudar a depurar sus aplicaciones / servicios web. La interfaz del programa es una página web que incluye no solo HTML, sino algo de JavaScript (para funcionalidad), imágenes y CSS (para estilo). Estoy planeando abrir esta aplicación, por lo que los usuarios simplemente deberían poder ejecutar un Makefile y todos los recursos irán donde necesiten ir. Sin embargo, también me gustaría poder distribuir simplemente un ejecutable con la menor cantidad posible de archivos / dependencias. ¿Existe una buena manera de agrupar HTML / CSS / JS con el ejecutable, de modo que los usuarios solo tengan que descargar y preocuparse por un archivo?
En este momento, en mi aplicación, entregar un archivo estático se parece un poco a esto:
// 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
}
Entonces, es bastante simple: si el archivo solicitado existe en mi directorio estático, invoque el controlador, que simplemente abre el archivo e intenta establecer un bien Content-Type
antes de servir. Mi pensamiento era que no hay razón para que esto deba basarse en el sistema de archivos real: si hubiera recursos compilados, simplemente podría indexarlos por el URI de solicitud y servirlos como tales.
Si no hay una buena manera de hacer esto, o estoy ladrando al árbol equivocado al intentar hacer esto, avíseme. Supuse que el usuario final apreciaría la menor cantidad posible de archivos para administrar.
Si hay etiquetas más apropiadas que Vamos, no dude en agregarlos o hágamelo saber.
go generate
con una pequeña utilidad de línea de comandos (empaquetada con mi código fuente) para convertir los archivos en[]byte
porciones que están incrustadas como variables en el código, similar a cómo sestringer
hace (ver blog.golang.org / generar ).Respuestas:
El paquete go-bindata parece que podría ser lo que le interesa.
https://github.com/go-bindata/go-bindata
Le permitirá convertir cualquier archivo estático en una llamada de función que se puede incrustar en su código y devolverá un segmento de bytes del contenido del archivo cuando se llame.
fuente
Incrustar archivos de texto
Si hablamos de archivos de texto, se pueden incrustar fácilmente en el código fuente. Simplemente use las comillas inversas para declarar el
string
literal de esta manera:Consejo de optimización:
Dado que la mayoría de las veces solo necesitará escribir el recurso en un
io.Writer
, también puede almacenar el resultado de una[]byte
conversión:Lo único con lo que debe tener cuidado es que los literales de cadena sin formato no pueden contener el carácter de comillas inversas (`). Los literales de cadena sin formato no pueden contener secuencias (a diferencia de los literales de cadena interpretados), por lo que si el texto que desea incrustar contiene comillas inversas, debe romper el literal de cadena sin procesar y concatenar comillas inversas como literales de cadena interpretados, como en este ejemplo:
El rendimiento no se ve afectado, ya que el compilador ejecutará estas concatenaciones.
Incrustar archivos binarios
Almacenar como un segmento de bytes
Para archivos binarios (por ejemplo, imágenes) más compacto (con respecto al binario nativo resultante) y más eficiente sería tener el contenido del archivo como
[]byte
en su código fuente. Esto puede ser generado por bibliotecas / herramientas de terceros como go-bindata .Si no desea utilizar una biblioteca de terceros para esto, aquí hay un fragmento de código simple que lee un archivo binario y genera el código fuente de Go que declara una variable de tipo
[]byte
que se inicializará con el contenido exacto del archivo:Salida de ejemplo si el archivo contendría bytes de 0 a 16 (pruébelo en Go Playground ):
Almacenar como base64
string
Si el archivo no es "demasiado grande" (la mayoría de las imágenes / iconos cumplen los requisitos), también existen otras opciones viables. Puede convertir el contenido del archivo a Base64
string
y almacenarlo en su código fuente. Al iniciar la aplicación (func init()
) o cuando sea necesario, puede decodificarla con el[]byte
contenido original . Go tiene un buen soporte para la codificación Base64 en elencoding/base64
paquete.Convertir un archivo (binario) a base64
string
es tan simple como:Almacene la cadena resultante en base64 en su código fuente, por ejemplo, como un archivo
const
.Decodificarlo es solo una llamada de función:
Almacenando como cotizado
string
Más eficiente que almacenar como base64, pero puede ser más largo en el código fuente es almacenar el literal de cadena entre comillas de los datos binarios. Podemos obtener la forma citada de cualquier cadena usando la
strconv.Quote()
función:Para datos binarios que contienen valores desde 0 hasta 64, así es como se vería la salida (pruébelo en 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:;<=>?"
(Tenga en cuenta que le
strconv.Quote()
añade y antepone una comilla).Puede utilizar directamente esta cadena entre comillas en su código fuente, por ejemplo:
Está listo para usar, no es necesario decodificarlo; la eliminación de comillas la realiza el compilador Go, en el momento de la compilación.
También puede almacenarlo como un segmento de bytes si lo necesita así:
fuente
sh
archivo a un ejecutable de Go?También hay una forma exótica: uso el complemento maven para construir proyectos GoLang y permite usar el preprocesador JCP para incrustar bloques binarios y archivos de texto en las fuentes. En el caso, el código se ve como la línea de abajo ( y se puede encontrar un ejemplo aquí )
fuente
sh
ejecutable como el anteriorsh
archivo? No estoy seguro de lo que quieres decir. Si desea que todo en un directorio esté incrustado, esto es algo con lo que he hechogo-bindata
. Por ejemplo, si coloco//go:generate $GOPATH/bin/go-bindata -prefix=data/ -pkg=$GOPACKAGE data/
un archivo go (no generado),go generate ./...
ejecutaré go-bindata en el directorio del paquete, incrustando todo en un subdirectorio de datos pero sin el prefijo 'data /'.Como una alternativa popular a lo
go-bindata
mencionado en otra respuesta, mjibson / esc también incrusta archivos arbitrarios, pero maneja árboles de directorios de manera particularmente conveniente.fuente