Overview
En esta guía, aprenderá a almacenar y recuperar archivos grandes en MongoDB usando GridFS. GridFS es una especificación implementada por el controlador de Java que describe cómo dividir archivos en fragmentos al almacenarlos y reensamblarlos al recuperarlos. La implementación del controlador de GridFS es una abstracción que gestiona las operaciones y la organización del almacenamiento de archivos en su aplicación Java.
Utilice GridFS si el tamaño de sus archivos supera el límite de tamaño de documento BSON de 16MB. Para saber si GridFS es adecuado para su caso de uso, consulte la Referencia de GridFS en el manual del servidor MongoDB.
Las siguientes secciones describen las operaciones de GridFS y demuestran cómo realizar estas acciones con el controlador:
Tip
Configuración de tiempo de espera
Puede usar la configuración de tiempo de espera de operación del lado del cliente (CSOT) para limitar el tiempo que el servidor tarda en finalizar las operaciones de GridFS. Para obtener más información sobre el uso de esta configuración con GridFS, consulte SecciónGridFS de la guía Limitar el tiempo de ejecución del servidor.
Cómo funciona GridFS
GridFS organiza los archivos en un bucket, un grupo de colecciones de MongoDB que contiene los fragmentos de archivos y la información que los describe. El bucket contiene las siguientes colecciones, nombradas según la convención definida en la especificación de GridFS:
El
chunksLa colección almacena los fragmentos de archivos binarios.La colección
filesalmacena los metadatos del archivo.
Al crear un nuevo bucket de GridFS, el controlador crea las colecciones anteriores, con el prefijo como fs nombre predeterminado, a menos que se especifique otro. El controlador también crea un índice en cada colección para garantizar la recuperación eficiente de los archivos y los metadatos relacionados. El controlador solo crea el bucket de GridFS en la primera operación de escritura si aún no existe. El controlador solo crea índices si no existen y cuando el bucket está vacío. Para obtener más información sobre los índices de GridFS, consulte la página del manual del servidor sobre índices de GridFS.
Al almacenar archivos con GridFS, el controlador divide los archivos en fragmentos más pequeños, cada uno representado por un documento independiente en la colección chunks. También crea un documento en la colección files que contiene el ID, el nombre y otros metadatos del archivo. Puede cargar el archivo desde la memoria o desde un flujo de datos. Consulte el siguiente diagrama para ver cómo GridFS divide los archivos al cargarlos en un bucket.

Al recuperar archivos, GridFS obtiene los metadatos de la colección files en el depósito especificado y utiliza la información para reconstruir el archivo a partir de los documentos de la colección chunks. Puede leer el archivo en memoria o exportarlo a una secuencia.
Crear un bucket de GridFS
Para almacenar o recuperar archivos de GridFS, cree un bucket u obtenga una referencia a uno existente en una base de datos MongoDB. Llame al método auxiliar GridFSBuckets.create() con una instancia MongoDatabase como parámetro para instanciar un GridFSBucket. Puede usar la instancia GridFSBucket para ejecutar operaciones de lectura y escritura en los archivos de su bucket.
MongoDatabase database = mongoClient.getDatabase("mydb"); GridFSBucket gridFSBucket = GridFSBuckets.create(database);
Para crear o hacer referencia a un depósito con un nombre personalizado distinto del nombre predeterminado fs, pase el nombre del depósito como segundo parámetro al método create() como se muestra a continuación:
GridFSBucket gridFSBucket = GridFSBuckets.create(database, "myCustomBucket");
Nota
Al llamar a create(), MongoDB no crea el depósito si no existe. En su lugar, lo crea según sea necesario, por ejemplo, al subir el primer archivo.
Para obtener más información sobre las clases y métodos mencionados en esta sección, consulte la siguiente documentación de API:
Archivos Tienda
Para almacenar un archivo en un bucket GridFS, puede cargarlo desde una instancia de InputStream o escribir sus datos en un GridFSUploadStream.
Para cualquier proceso de carga, puede especificar información de configuración, como el tamaño del fragmento de archivo y otros pares de campo/valor para almacenar como metadatos. Establezca esta información en una instancia de GridFSUploadOptions, como se muestra en el siguiente fragmento de código:
GridFSUploadOptions options = new GridFSUploadOptions() .chunkSizeBytes(1048576) // 1MB chunk size .metadata(new Document("myField", "myValue"));
Consulte la documentación de la API GridFSUploadOptions para obtener más información.
Importante
Utilice una MAYORÍA de escritura de inquietudes
Al almacenar archivos en un bucket de GridFS, asegúrese de usar la preocupación de escritura WriteConcern.MAJORITY. Si especifica una preocupación de escritura diferente, las elecciones del conjunto de réplicas que se producen durante la carga de un archivo de GridFS podrían interrumpir el proceso y provocar la pérdida de algunos fragmentos de archivo.
Para obtener más información acerca de las inquietudes de escritura, consulte la página Inquietud de escritura en el manual del servidor.
Subir un archivo usando un flujo de entrada
Esta sección muestra cómo subir un archivo a un bucket de GridFS mediante un flujo de entrada. El siguiente ejemplo de código muestra cómo usar un FileInputStream para leer datos de un archivo en el sistema de archivos y subirlos a GridFS mediante las siguientes operaciones:
Leer desde el sistema de archivos utilizando un
FileInputStream.Establezca el tamaño del fragmento utilizando
GridFSUploadOptions.Establezca un campo de metadatos personalizado llamado
typeen el valor "archivo zip".Sube un archivo llamado
project.zip, especificando el nombre del archivo GridFS como "myProject.zip".
String filePath = "/path/to/project.zip"; try (InputStream streamToUploadFrom = new FileInputStream(filePath) ) { // Defines options that specify configuration information for files uploaded to the bucket GridFSUploadOptions options = new GridFSUploadOptions() .chunkSizeBytes(1048576) .metadata(new Document("type", "zip archive")); // Uploads a file from an input stream to the GridFS bucket ObjectId fileId = gridFSBucket.uploadFromStream("myProject.zip", streamToUploadFrom, options); // Prints the "_id" value of the uploaded file System.out.println("The file id of the uploaded file is: " + fileId.toHexString()); }
Este ejemplo de código imprime el ID del archivo cargado después de que se guarda correctamente en GridFS.
Para obtener más información, consulte la documentación de la API sobre uploadFromStream().
Subir un archivo usando un flujo de salida
Esta sección muestra cómo subir un archivo a un bucket de GridFS escribiendo en un flujo de salida. El siguiente ejemplo de código muestra cómo escribir en un GridFSUploadStream para enviar datos a GridFS mediante las siguientes operaciones:
Lee un archivo llamado "project.zip" desde el sistema de archivos a una matriz de bytes.
Establezca el tamaño del fragmento utilizando
GridFSUploadOptions.Establezca un campo de metadatos personalizado llamado
typeen el valor "archivo zip".Escribe los bytes en un
GridFSUploadStreamy asigna el nombre de archivo "myProject.zip". El flujo lee los datos en un búfer hasta alcanzar el límite especificado en la configuraciónchunkSizey los inserta como un nuevo fragmento en la colecciónchunks.
Path filePath = Paths.get("/path/to/project.zip"); byte[] data = Files.readAllBytes(filePath); // Defines options that specify configuration information for files uploaded to the bucket GridFSUploadOptions options = new GridFSUploadOptions() .chunkSizeBytes(1048576) .metadata(new Document("type", "zip archive")); try (GridFSUploadStream uploadStream = gridFSBucket.openUploadStream("myProject.zip", options)) { // Writes file data to the GridFS upload stream uploadStream.write(data); uploadStream.flush(); // Prints the "_id" value of the uploaded file System.out.println("The file id of the uploaded file is: " + uploadStream.getObjectId().toHexString()); // Prints a message if any exceptions occur during the upload process } catch (Exception e) { System.err.println("The file upload failed: " + e); }
Este ejemplo de código imprime el ID del archivo cargado después de que se guarda correctamente en GridFS.
Nota
Si la carga de archivos no se realiza correctamente, la operación genera una excepción y los fragmentos cargados se convierten en fragmentos huérfanos. Un fragmento huérfano es un documento de una chunks colección GridFS que no hace referencia a ningún ID de archivo de la colección GridFS. Los fragmentos de files archivo pueden convertirse en fragmentos huérfanos cuando se interrumpe una operación de carga o eliminación. Para eliminar fragmentos huérfanos, debe identificarlos mediante operaciones de lectura y eliminarlos mediante operaciones de escritura.
Para obtener más información, consulte la documentación de la API en GridFSUploadStream.
Recuperar información del archivo
En esta sección, puedes aprender a recuperar metadatos de archivos almacenados en la colección files del depósito de GridFS. Los metadatos contienen información sobre el archivo al que se refieren, incluyendo:
El id del archivo
El nombre del archivo
La longitud/tamaño del archivo
La fecha y hora de carga
Un documento
metadataen el que puedes almacenar cualquier otra información
Para recuperar archivos de un bucket de GridFS, llame al método find() en la instancia GridFSBucket. El método devuelve un GridFSFindIterable desde el que puede acceder a los resultados.
El siguiente ejemplo de código muestra cómo recuperar e imprimir metadatos de archivos de todos tus archivos en un contenedor de GridFS. Entre las diferentes formas en las que puedes recorrer los resultados recuperados del GridFSFindIterable, el ejemplo utiliza una interfaz funcional Consumer para imprimir los siguientes resultados:
gridFSBucket.find().forEach(new Consumer<GridFSFile>() { public void accept(final GridFSFile gridFSFile) { System.out.println(gridFSFile); } });
El siguiente ejemplo de código muestra cómo recuperar e imprimir los nombres de todos los archivos que coinciden con los campos especificados en el filtro de consulta. El ejemplo también invoca sort() y limit() en el valor GridFSFindIterable devuelto para especificar el orden y el número máximo de resultados:
Bson query = Filters.eq("metadata.type", "zip archive"); Bson sort = Sorts.ascending("filename"); // Retrieves 5 documents in the bucket that match the filter and prints metadata gridFSBucket.find(query) .sort(sort) .limit(5) .forEach(new Consumer<GridFSFile>() { public void accept(final GridFSFile gridFSFile) { System.out.println(gridFSFile); } });
Dado que metadata es un documento incrustado, el filtro de consulta especifica el type campo dentro del documento mediante notación de puntos. Consulte la guía del manual del servidor sobre cómo realizar consultas en documentos incrustados o anidados para obtener más información.
Para obtener más información sobre las clases y métodos mencionados en esta sección, consulte los siguientes recursos:
Documentación de la API deGridFSFindIterable
Documentación de la APIGridFSBucket.find()
Descarga de archivos
Puedes descargar un archivo de GridFS directamente a una secuencia o guardarlo en la memoria desde una secuencia. Puedes especificar el archivo que deseas recuperar usando su ID o nombre.
Revisiones de archivos
Cuando su bucket contiene varios archivos con el mismo nombre, GridFS selecciona la última versión cargada del archivo de forma predeterminada. Para diferenciar cada archivo con el mismo nombre, GridFS les asigna un número de revisión, ordenado por fecha de carga.
El número de revisión del archivo original es "0" y el siguiente número de revisión más reciente es "1". También puede especificar valores negativos que corresponden a la fecha de la revisión. El valor de revisión "-1" hace referencia a la revisión más reciente y "-2" a la siguiente.
El siguiente fragmento de código muestra cómo puede especificar la segunda revisión de un archivo en una instancia de GridFSDownloadOptions:
GridFSDownloadOptions downloadOptions = new GridFSDownloadOptions().revision(1);
Para obtener más información sobre la enumeración de revisiones, consulte la documentación de la API de GridFSDownloadOptions.
Descargar un archivo a un flujo de salida
Puedes descargar un archivo de un bucket de GridFS a un flujo de salida. El siguiente ejemplo de código muestra cómo llamar al método downloadToStream() para descargar la primera revisión del archivo "myProject.zip" a un OutputStream.
GridFSDownloadOptions downloadOptions = new GridFSDownloadOptions().revision(0); // Downloads a file to an output stream try (FileOutputStream streamToDownloadTo = new FileOutputStream("/tmp/myProject.zip")) { gridFSBucket.downloadToStream("myProject.zip", streamToDownloadTo, downloadOptions); streamToDownloadTo.flush(); }
Para obtener más información sobre este método, consulte la documentación de la API downloadToStream().
Descargar un archivo a un flujo de entrada
Puedes descargar un archivo de un bucket de GridFS a la memoria mediante un flujo de entrada. Puedes llamar al método openDownloadStream() del bucket de GridFS para abrir un GridFSDownloadStream, un flujo de entrada desde el que puedes leer el archivo.
El siguiente ejemplo de código le muestra cómo descargar un archivo referenciado por la variable fileId en la memoria e imprimir su contenido como una cadena:
ObjectId fileId = new ObjectId("60345d38ebfcf47030e81cc9"); // Opens an input stream to read a file containing a specified "_id" value and downloads the file try (GridFSDownloadStream downloadStream = gridFSBucket.openDownloadStream(fileId)) { int fileLength = (int) downloadStream.getGridFSFile().getLength(); byte[] bytesToWriteTo = new byte[fileLength]; downloadStream.read(bytesToWriteTo); // Prints the downloaded file's contents as a string System.out.println(new String(bytesToWriteTo, StandardCharsets.UTF_8)); }
Para obtener más información sobre este método, consulte la documentación de la API openDownloadStream().
Cambiar nombre de archivos
Puedes actualizar el nombre de un archivo GridFS en tu bucket llamando al método rename(). Debes especificar el archivo a renombrar por su id de archivo en lugar de su nombre.
Nota
El método rename() solo permite actualizar el nombre de un archivo a la vez. Para renombrar varios archivos, recupere del depósito una lista de archivos que coincidan con el nombre, extraiga los valores de ID de los archivos que desea renombrar y pase cada ID de archivo en llamadas separadas al método rename().
El siguiente ejemplo de código le muestra cómo actualizar el nombre del archivo al que hace referencia la variable fileId a "mongodbTutorial.zip":
ObjectId fileId = new ObjectId("60345d38ebfcf47030e81cc9"); // Renames the file that has a specified "_id" value to "mongodbTutorial.zip" gridFSBucket.rename(fileId, "mongodbTutorial.zip");
Para obtener más información sobre este método, consulte la documentación de la API rename().
Eliminar archivos
Puedes eliminar un archivo de tu bucket de GridFS llamando al método delete(). Debes especificar el archivo por su ID, no por su nombre.
Nota
El método delete() solo permite eliminar un archivo a la vez. Para eliminar varios, recupérelos del depósito, extraiga los valores de ID de los archivos que desea eliminar y pase cada ID de archivo en llamadas separadas al método delete().
El siguiente ejemplo de código le muestra cómo eliminar el archivo al que hace referencia la variable fileId:
ObjectId fileId = new ObjectId("60345d38ebfcf47030e81cc9"); // Deletes the file that has a specified "_id" value from the GridFS bucket gridFSBucket.delete(fileId);
Para obtener más información sobre este método, consulte la documentación de la API delete().
Eliminar un depósito GridFS
El siguiente ejemplo de código muestra cómo eliminar el bucket predeterminado de GridFS en la base de datos "mydb". Para referenciar un bucket con nombre personalizado, consulte la sección de esta guía sobre cómo crear un bucket personalizado.
MongoDatabase database = mongoClient.getDatabase("mydb"); GridFSBucket gridFSBucket = GridFSBuckets.create(database); gridFSBucket.drop();
Para obtener más información sobre este método, consulte la documentación de la API drop().
Información Adicional
Archivo ejecutable GridFSTour.java desde el repositorio de origen del controlador