# Envía archivos y streams al cliente

> Sirve un archivo del disco con $.file(), fuerza un nombre de descarga, envía contenido generado con $.stream() y responde 404 cuando el archivo no existe.

Framework: total5
Product: Total.js 5 (total5@0.0.19)
Language: es
Content-SHA256: 8a6fed90d1d32d829d28062fa3811e058612a12808cf590c1484d06bea1b7e18
Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c
Sources: total5-installed@total5@0.0.19
Review: not-recorded

`$.file(path, [download])` envía un archivo del disco. El `content-type` sale de la extensión. Pasa `true` como segundo argumento para que el navegador descargue el archivo con su propio nombre, o una cadena para elegir el nombre (`attachment; filename*=...` se establece por ti, seguro con UTF-8). Una ruta que no existe termina con la página 404.

`$.stream(type, stream, [download])` envía cualquier stream legible con el content type indicado: un archivo generado, la respuesta de otro servidor o una exportación de base de datos. No fija la longitud, así que la respuesta va por chunks. `PATH.public()`, `PATH.private()` y `PATH.tmp()` construyen rutas absolutas hacia las carpetas del proyecto; los archivos de `public/` ya se sirven sin ninguna ruta, así que usa `$.file()` para los archivos que deben seguir siendo privados o que requieren una comprobación previa.

```js controllers/download.js
const Fs = require('fs');

exports.install = function() {
	ROUTE('GET /report/', report);
	ROUTE('GET /report/save/', report_save);
	ROUTE('GET /export/', export_csv);
	ROUTE('GET /missing/', missing);
};

function filepath() {
	var filename = PATH.tmp('report.txt');
	Fs.writeFileSync(filename, 'Total.js report\n');
	return filename;
}

function report($) {
	$.file(filepath());
}

function report_save($) {
	$.file(filepath(), 'my report.txt');
}

function export_csv($) {
	var stream = Fs.createReadStream(filepath());
	$.stream('text/csv', stream, 'export.csv');
}

function missing($) {
	$.file(PATH.tmp('does-not-exist.txt'));
}
```
