JavaScript es un lenguaje que posee un buen manejo de strings, pero debido a que inicialmente fue diseñado para el manejo de documentos HTML, no es muy bueno en el manejo de data binaria, de hecho JavaScript no posee un tipo de dato binario como tal, solo contiene números o tipos estructurados.
Como ya sabemos Node.js está basado en JavaScript y el mismo puede manejar protocolos de texto como HTTP, donde además puedes utilizar esto para establecer la comunicación con Bases de Datos, manipular imágenes e incluso manejar la manipulación de archivos y debido a lo que comentamos hacer esto con solo strings puede ser bastante complicado.
Pero para hacer estas tareas de manipulación de binarios mucho más sencillas, Node.js incluye una implementación de buffer binario, el cual nos permite obtener y setear los bytes de un buffer creado sin mucho problema.
Creación del buffer
Para la creación de un buffer, es tan sencillo como que hagamos una nueva instancia a la clase Buffer(). Veamos como creamos un buffer sencillo en base a una codificación UTF-8 de la siguiente forma:
var buf = new Buffer('Hola mundo!'); console.log(buf);Vamos a ejecutar nuestro ejemplo por consola para ver la respuesta que nos da Node.js en cuanto a la creación de nuestro buffer:
Como vemos si imprimimos nuestra variable buf, la respuesta no es quizá la que estábamos esperando, pero debemos recordar que estamos creando una instancia de Buffer y lo que hace esta clase es encodear su contenido de acuerdo a codificación de caracteres en específico.
También podemos crear un buffer de strings con otros encodings, el cual será válido siempre y cuando especifiquemos el mismo como segundo argumento, veamos:
var buf2 = new Buffer('9b38kte610la', 'base64'); console.log(buf2);Como vemos podemos especificar sin ningún problema el encoding, veamos entonces que tipos de encoding son aceptados y sus respectivos identificadores:
Adicionalmente, si no tenemos el contenido inicial para nuestro buffer y necesitamos crear uno podemos hacerlo especificando la capacidad del mismo, para ello lo hacemos de la siguiente forma:
var buf = new Buffer(1024);Con esto lo que hacemos es crear un buffer de 1024 bytes para nuestras operaciones a futuro.
Manejo de bytes en el buffer
Luego que hemos creado o recibido el buffer, quizá queremos inspeccionar el mismo y cambiar su contenido. Primero para acceder a los bytes dentro del mismo podemos usar los corchetes de la siguiente forma:
var buf = new Buffer('aqui esta el contenido de mi buffer'); console.log(buf[10]);Si ejecutamos nuestro ejemplo obtendremos la décima posición del buffer, incluso podemos cambiar a la novena posición del buffer y ver el resultado, veamos como luce:
Como vemos obtenemos bytes aleatorios para las posiciones de nuestro buffer, incluso si necesitamos manipular el contenido de cualquier posición en el mismo podemos hacer algo como lo siguiente:
var buf = new Buffer('aqui esta el contenido de mi buffer nuevo'); buf[2] = 110; buf[6] = 180; buf[10] = 90; console.log(buf[2]); console.log(buf[6]); console.log(buf[10]);Veamos la respuesta por consola de nuestro ejemplo:
Como vimos pudimos modificar el contenido de ciertas posiciones dentro de nuestro buffer sin mucho problema, además de esto podemos obtener el tamaño de nuestro buffer con la propiedad length de la siguiente forma:
var buf = new Buffer(100); console.log(buf.length);Si somos observadores podremos ver que la respuesta de nuestra consola será 100, donde luego de obtener este valor, lo podemos utilizar para iterar sobre nuestro buffer y de esa forma manipular cada posición para obtener el valor de la misma o setear algún valor en específico, veamos un ejemplo sencillo de esto:
var buf = new Buffer(100); for(var i = 0; i < buf.length; i++) { buf[i] = i; } console.log(buf);Lo que hicimos en este ejemplo fue crear un nuevo buffer con una capacidad de 100 bytes y luego seteamos cada byte con un valor empezando desde 0 hasta 99, por último veamos la respuesta de la consola cuando ejecutamos nuestro ejemplo:
Extracción de data del buffer
Otra de las características interesantes del buffer, una vez que lo hemos creado o recibido, es poder extraer una porción del mismo. Podemos “picarlo” por decirlo de alguna forma y crear otro buffer más pequeño con esa porción que hemos picado, sin olvidar especificar desde y hasta donde picaremos el mismo, veamos un ejemplo para ilustrar lo que hemos explicado:
var buffer_completo = new Buffer("este es el contenido de mi buffer que vamos a picar"); var buffer_small = buffer_completo.slice(26, 55); console.log(buffer_small.toString());Como vemos primero creamos la instancia de nuestro buffer con el contenido inicial, luego con la función slice() especificamos desde y hasta donde vamos a obtener el contenido, asignamos lo que obtenemos a una nueva variable y por último decodificamos el contenido para poder visualizar el contenido de nuestro segundo buffer, veamos la respuesta por consola al ejecutar el ejemplo:
Es importante mencionar que cuando cortamos un nuevo buffer no estamos utilizando nueva memoria del sistema, este nuevo buffer usa la memoria del padre ya que solo referencia al mismo pero con un inicio y un final diferentes. Esto puede ocasionar algunos problemas si no somos cuidadosos ya que estamos trabajando sobre el mismo buffer, para ello recomendamos trabajar con el método copy para evitar los problemas, el cual veremos a continuación.
Copiando un buffer
Como mencionamos, al cortar un buffer podemos obtener algunos problemas sino somos cuidadosos, pero para ello tenemos el método copy, el cual nos permite copiar el contenido de un buffer en un buffer nuevo, utilizando una nueva instancia y un nuevo espacio de memoria, veamos:
var buffer1 = new Buffer("Contenido buffer numero 1, contenido a copiar"); var buffer2 = new Buffer(20); var objInicio = 0; var fuenteInicio = 26; var fuenteFin = 50; buffer1.copy(buffer2, objInicio, fuenteInicio, fuenteFin); console.log(buffer2.toString());Como vemos creamos dos buffer distintos, donde el primero tendrá el contenido y el segundo solo tendrá el tamaño, especificamos el inicio para nuestro segundo buffer, y de igual forma indicamos el inicio y el final para el nuevo buffer que copiaremos, veamos la respuesta de la consola al ejecutar el ejemplo:
Decodificando un buffer
Como vimos en ejemplos anteriores, pudimos imprimir el contenido original de nuestro buffer al utilizar el método toString(), esto lo que se llama es decodificar el buffer, donde al igual que la instancia de la clase Buffer() si no especificamos nada, por defecto lo decodificamos a UTF-8.
Incluso podemos hacer una transcodificación de un string UTF-8 a base64 por mencionar un caso, veamos:
var cadenautf8 = 'mi cadena nueva'; var buf = new Buffer(cadenautf8); var cadenabase64 = buf.toString('base64') console.log(cadenabase64);Por último veamos cómo hemos transcodificado nuestra cadena original:
Con esto finalizamos este tutorial donde aprendimos las maneras de lidiar con data binaria en Node.js gracias a la clase Buffer, la cual nos permite manipular la misma desde su lectura, escritura, obtener pequeños pedazos de ella, copiar la misma a nuevas instancias e incluso transformar ese buffer a nuevos tipos de encoding para su manipulación en nuestros programas.
Buen tutorial, gracias.