javascript como - Cree un archivo en la memoria para que el usuario lo descargue, no a través del servidor




una object (15)

¿Hay alguna manera de que pueda crear un archivo de texto en el lado del cliente y pedirle al usuario que lo descargue, sin ninguna interacción con el servidor? Sé que no puedo escribir directamente en su máquina (seguridad y todo), pero ¿puedo crear y pedirles que lo guarden?


Answers

Si el archivo contiene datos de texto, una técnica que utilizo es colocar el texto en un elemento de área de texto y hacer que el usuario lo seleccione (haga clic en área de texto y luego en ctrl-A) luego copie y luego pegue en un editor de texto.


Como se mencionó anteriormente, filesaver es un gran paquete para trabajar con archivos en el lado del cliente. Pero, no se hace bien con archivos grandes. StreamSaver.js es una solución alternativa (que se señala en FileServer.js) que puede manejar archivos grandes:

const fileStream = streamSaver.createWriteStream('filename.txt', size);
const writer = fileStream.getWriter();
for(var i = 0; i < 100; i++){
    var uint8array = new TextEncoder("utf-8").encode("Plain Text");
    writer.write(uint8array);
}
writer.close()

Felizmente estoy usando FileSaver.js . Su compatibilidad es bastante buena (IE10 + y todo lo demás), y es muy simple de usar:

var blob = new Blob(["some text"], {
    type: "text/plain;charset=utf-8;",
});
saveAs(blob, "thing.txt");

Todas las soluciones anteriores no funcionaron en todos los navegadores. Esto es lo que finalmente funciona en IE 10+, Firefox y Chrome (y sin jQuery o cualquier otra biblioteca):

save: function(filename, data) {
    var blob = new Blob([data], {type: 'text/csv'});
    if(window.navigator.msSaveOrOpenBlob) {
        window.navigator.msSaveBlob(blob, filename);
    }
    else{
        var elem = window.document.createElement('a');
        elem.href = window.URL.createObjectURL(blob);
        elem.download = filename;        
        document.body.appendChild(elem);
        elem.click();        
        document.body.removeChild(elem);
    }
}

Tenga en cuenta que, dependiendo de su situación, es posible que también desee llamar a URL.revokeObjectURL después de eliminar elem . De acuerdo con los documentos para URL.createObjectURL :

Cada vez que llama a createObjectURL (), se crea una nueva URL de objeto, incluso si ya ha creado una para el mismo objeto. Cada uno de estos debe liberarse llamando a URL.revokeObjectURL () cuando ya no los necesite. Los navegadores los liberarán automáticamente cuando se descargue el documento; Sin embargo, para obtener un rendimiento óptimo y el uso de la memoria, si hay momentos seguros en los que puede descargarlos explícitamente, debe hacerlo.


var element = document.createElement('a');
element.setAttribute('href', 'data:text/text;charset=utf-8,' +      encodeURI(data));
element.setAttribute('download', "fileName.txt");
element.click();

Solución simple para navegadores listos para HTML5 ...

function download(filename, text) {
  var element = document.createElement('a');
  element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
  element.setAttribute('download', filename);

  element.style.display = 'none';
  document.body.appendChild(element);

  element.click();

  document.body.removeChild(element);
}
form * {
  display: block;
  margin: 10px;
}
<form onsubmit="download(this['name'].value, this['text'].value)">
  <input type="text" name="name" value="test.txt">
  <textarea name="text"></textarea>
  <input type="submit" value="Download">
</form>

Uso

download('test.txt', 'Hello world!');

Puede utilizar URI de datos. El soporte del navegador varía; ver Wikipedia . Ejemplo:

<a href="data:application/octet-stream;charset=utf-16le;base64,//5mAG8AbwAgAGIAYQByAAoA">text file</a>

El octet-stream es forzar un aviso de descarga. De lo contrario, probablemente se abrirá en el navegador.

Para CSV, puede utilizar:

<a href="data:application/octet-stream,field1%2Cfield2%0Afoo%2Cbar%0Agoo%2Cgai%0A">CSV Octet</a>

Prueba la demo jsFiddle .


Solución que funciona en IE10: (necesitaba un archivo csv, pero es suficiente para cambiar el tipo y el nombre de archivo a txt)

var csvContent=data; //here we load our csv data 
var blob = new Blob([csvContent],{
    type: "text/csv;charset=utf-8;"
});

navigator.msSaveBlob(blob, "filename.csv")


Todos los ejemplos anteriores funcionan bien en Chrome e IE, pero fallan en Firefox. Por favor, considere agregar un ancla al cuerpo y quitarlo después de hacer clic.

var a = window.document.createElement('a');
a.href = window.URL.createObjectURL(new Blob(['Test,Text'], {type: 'text/csv'}));
a.download = 'test.csv';

// Append anchor to body.
document.body.appendChild(a);
a.click();

// Remove anchor from body
document.body.removeChild(a);

Si solo desea convertir una cadena para que esté disponible para su descarga, puede intentarlo utilizando jQuery.

$('a.download').attr('href', 'data:application/csv;charset=utf-8,' + encodeURI(data));

Para mí esto funcionó perfectamente, con el mismo nombre de archivo y la extensión que se descargan

<a href={"data:application/octet-stream;charset=utf-16le;base64," + file64 } download={title} >{title}</a>

'título' es el nombre del archivo con la extensión ie, sample.pdf , waterfall.jpg , etc.

'file64' es el contenido de base 64 o menos así decir, Ww6IDEwNDAsIFNsaWRpbmdTY2FsZUdyb3VwOiAiR3JvdXAgQiIsIE1lZGljYWxWaXNpdEZsYXRGZWU6IDM1LCBEZW50YWxQYXltZW50UGVyY2VudGFnZTogMjUsIFByb2NlZHVyZVBlcmNlbnQ6IDcwLKCFfSB7IkdyYW5kVG90YWwiOjEwNDAsIlNsaWRpbmdTY2FsZUdyb3VwIjoiR3JvdXAgQiIsIk1lZGljYWxWaXNpdEZsYXRGZWUiOjM1LCJEZW50YWxQYXltZW50UGVyY2VudGFnZSI6MjUsIlByb2NlZHVyZVBlcmNlbnQiOjcwLCJDcmVhdGVkX0J5IjoiVGVycnkgTGVlIiwiUGF0aWVudExpc3QiOlt7IlBhdGllbnRO



Esta solución se extrae directamente del repositorio github de tiddlywiki (tiddlywiki.com). He usado tiddlywiki en casi todos los navegadores y funciona a la perfección:

function(filename,text){
    // Set up the link
    var link = document.createElement("a");
    link.setAttribute("target","_blank");
    if(Blob !== undefined) {
        var blob = new Blob([text], {type: "text/plain"});
        link.setAttribute("href", URL.createObjectURL(blob));
    } else {
        link.setAttribute("href","data:text/plain," + encodeURIComponent(text));
    }
    link.setAttribute("download",filename);
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
}

Repo de Github: Descargar módulo de ahorro


Llego tarde a la fiesta, pero pondré esto aquí si alguien más quisiera saber mi solución:

Tuve una verdadera lucha con este problema exacto, pero encontré una solución viable utilizando iframes (lo sé, lo sé. Es terrible, pero funciona para un problema simple que tuve)

Tuve una página html que lanzó una secuencia de comandos php separada que generó el archivo y luego lo descargué. En la página html, usé el siguiente jquery en el encabezado html (también necesitarás incluir una biblioteca de jquery):

<script>
    $(function(){
        var iframe = $("<iframe>", {name: 'iframe', id: 'iframe',}).appendTo("body").hide();
        $('#click').on('click', function(){
            $('#iframe').attr('src', 'your_download_script.php');
        });
        $('iframe').load(function(){
            $('#iframe').attr('src', 'your_download_script.php?download=yes'); <!--on first iframe load, run script again but download file instead-->
            $('#iframe').unbind(); <!--unbinds the iframe. Helps prevent against infinite recursion if the script returns valid html (such as echoing out exceptions) -->
        });
    });
</script>

En your_download_script.php, tenga lo siguiente:

function downloadFile($file_path) {
    if (file_exists($file_path)) {
        header('Content-Description: File Transfer');
        header('Content-Type: text/csv');
        header('Content-Disposition: attachment; filename=' . basename($file_path));
        header('Expires: 0');
        header('Cache-Control: must-revalidate');
        header('Pragma: public');
        header('Content-Length: ' . filesize($file_path));
        ob_clean();
        flush();
        readfile($file_path);
        exit();
    }
}


$_SESSION['your_file'] = path_to_file; //this is just how I chose to store the filepath

if (isset($_REQUEST['download']) && $_REQUEST['download'] == 'yes') {
    downloadFile($_SESSION['your_file']);
} else {
    *execute logic to create the file*
}

Para desglosar esto, jquery primero inicia su script php en un iframe. El iframe se carga una vez que se genera el archivo. Luego, jquery vuelve a iniciar el script con una variable de solicitud que le indica al script que descargue el archivo.

La razón por la que no puede realizar la descarga y la generación de archivos de una sola vez se debe a la función php header (). Si usa header (), está cambiando el script a algo que no sea una página web y jquery nunca reconocerá el script de descarga como "cargado". Sé que esto no necesariamente detecta cuando un navegador recibe un archivo, pero su problema sonaba similar al mío.





javascript file web-applications client-side