¿Es posible escribir datos en un archivo usando solo JavaScript?

192

Quiero escribir datos en un archivo existente usando JavaScript. No quiero imprimirlo en la consola. Quiero escribir datos en realidad abc.txt. Leí muchas preguntas respondidas, pero en todas partes están imprimiendo en la consola. en algún lugar han dado código pero no funciona. Entonces, ¿alguien puede ayudarme? Cómo escribir datos en un archivo.

Remití el código pero no funciona: está dando un error:

TypeError no capturado: constructor ilegal

en cromo y

SecurityError: la operación es insegura.

en Mozilla

var f = "sometextfile.txt";

writeTextFile(f, "Spoon")
writeTextFile(f, "Cheese monkey")
writeTextFile(f, "Onion")

function writeTextFile(afilename, output)
{
  var txtFile =new File(afilename);
  txtFile.writeln(output);
  txtFile.close();
}

Entonces, ¿podemos realmente escribir datos en el archivo usando solo Javascript o NO?

pareshm
fuente

Respuestas:

90

Algunas sugerencias para esto:

  1. Si está intentando escribir un archivo en la máquina del cliente, no puede hacerlo de ninguna manera entre navegadores. IE tiene métodos para permitir que las aplicaciones "confiables" usen objetos ActiveX para leer / escribir archivos.
  2. Si está tratando de guardarlo en su servidor, simplemente pase los datos de texto a su servidor y ejecute el código de escritura del archivo usando algún lenguaje del lado del servidor.
  3. Para almacenar alguna información del lado del cliente que sea considerablemente pequeña, puede utilizar cookies.
  4. Uso de la API HTML5 para almacenamiento local.
Sujit Agarwal
fuente
27
HTML5 API tiene un máximo de solo 5 mb.
Pacerier
Sí, no puede escribir en el archivo del sistema sin seleccionarlo. Lea los documentos oficiales: w3.org/TR/file-upload/#security-discussion
Manoj Ghediya
217

Puede crear archivos en el navegador usando Bloby URL.createObjectURL. Todos los navegadores recientes lo admiten .

No puede guardar directamente el archivo que crea, ya que eso causaría problemas de seguridad masivos, pero puede proporcionarlo como un enlace de descarga para el usuario. Puede sugerir un nombre de archivo a través del downloadatributo del enlace, en navegadores que admitan el atributo de descarga. Al igual que con cualquier otra descarga, el usuario que descargue el archivo tendrá la última palabra sobre el nombre del archivo.

var textFile = null,
  makeTextFile = function (text) {
    var data = new Blob([text], {type: 'text/plain'});

    // If we are replacing a previously generated file we need to
    // manually revoke the object URL to avoid memory leaks.
    if (textFile !== null) {
      window.URL.revokeObjectURL(textFile);
    }

    textFile = window.URL.createObjectURL(data);

    // returns a URL you can use as a href
    return textFile;
  };

Aquí hay un ejemplo que usa esta técnica para guardar texto arbitrario de a textarea.

Si desea iniciar inmediatamente la descarga en lugar de requerir que el usuario haga clic en un enlace, puede usar eventos del mouse para simular un clic del mouse en el enlace como lo hizo la respuesta de Lifecube . He creado un ejemplo actualizado que usa esta técnica.

  var create = document.getElementById('create'),
    textbox = document.getElementById('textbox');

  create.addEventListener('click', function () {
    var link = document.createElement('a');
    link.setAttribute('download', 'info.txt');
    link.href = makeTextFile(textbox.value);
    document.body.appendChild(link);

    // wait for the link to be added to the document
    window.requestAnimationFrame(function () {
      var event = new MouseEvent('click');
      link.dispatchEvent(event);
      document.body.removeChild(link);
    });

  }, false);
Código inútil
fuente
1
@FirstBlood ¿Qué parte no funciona? ¿Recibes un error? La creación de archivos y enlaces debería funcionar en Safari 7+ (creo que las cosas también deberían funcionar en Safari 6 si usa la versión prefijada de URL). Establecer el nombre del archivo no funcionará en Safari porque aún no ha implementado el downloadatributo .
Código inútil el
1
Lo estaba probando en Safari 5.1 :)
First Blood
1
falta el nuevo carácter de línea en el documento guardado
Benny
1
@Benny los personajes de nueva línea están ahí. JS usa el carácter de nueva línea \npara representar nuevas líneas como lo hacen los programas UNIX. Probablemente lo esté viendo en un programa de Windows, como el Bloc de notas, que no representa el \ncarácter como una nueva línea . Si desea que las nuevas líneas que se representan correctamente en el Bloc de notas y algunos otros programas de Windows, antes de poner el texto en el Blobreemplazar cada \ncon \r\n: text = text.replace(/\n/g, '\r\n').
Código inútil
2
@ user3241111 En realidad no, debería funcionar. Cosas así no son tan inusuales. He visto formas de hackyer de hacerlo ;-) En el pasado también me salí con la suya generando el archivo mouseoveren el enlace, pero dependiendo de cuánto procesamiento esté haciendo eso podría no funcionar muy bien.
Código inútil
41

Si está hablando de JavaScript del navegador, no puede escribir datos directamente en el archivo local por razones de seguridad. La nueva API HTML 5 solo puede permitirle leer archivos.

Pero si desea escribir datos, y permitir que el usuario descargue como un archivo local. funciona el siguiente código:

    function download(strData, strFileName, strMimeType) {
    var D = document,
        A = arguments,
        a = D.createElement("a"),
        d = A[0],
        n = A[1],
        t = A[2] || "text/plain";

    //build download link:
    a.href = "data:" + strMimeType + "charset=utf-8," + escape(strData);


    if (window.MSBlobBuilder) { // IE10
        var bb = new MSBlobBuilder();
        bb.append(strData);
        return navigator.msSaveBlob(bb, strFileName);
    } /* end if(window.MSBlobBuilder) */



    if ('download' in a) { //FF20, CH19
        a.setAttribute("download", n);
        a.innerHTML = "downloading...";
        D.body.appendChild(a);
        setTimeout(function() {
            var e = D.createEvent("MouseEvents");
            e.initMouseEvent("click", true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
            a.dispatchEvent(e);
            D.body.removeChild(a);
        }, 66);
        return true;
    }; /* end if('download' in a) */



    //do iframe dataURL download: (older W3)
    var f = D.createElement("iframe");
    D.body.appendChild(f);
    f.src = "data:" + (A[2] ? A[2] : "application/octet-stream") + (window.btoa ? ";base64" : "") + "," + (window.btoa ? window.btoa : escape)(strData);
    setTimeout(function() {
        D.body.removeChild(f);
    }, 333);
    return true;
}

para usarlo:

download('the content of the file', 'filename.txt', 'text/plain');

Lifecube
fuente
Increíble, Lifecube. Realmente necesitaba esa funcionalidad, aunque no quiero que el usuario sepa que se está descargando ningún archivo, lo quiero completamente oculto para el usuario, ya que podría asustar al usuario al ver que algún archivo se descarga automáticamente al realizar alguna acción en un sitio web, aunque lo estamos utilizando solo con fines de recopilación de datos de marketing, ¿podría compartir cómo descargar el archivo sin hacerlo visible para el usuario?
Just_another_developer
1
la solución anterior está un poco desactualizada. Es posible que deba tener en cuenta el html 5 javascript lib. github.com/eligrey/FileSaver.js
Lifecube
@Lifecube usando FileSaver.js, ¿hay alguna manera de guardar automáticamente el texto en un archivo sin la interacción del usuario? ¡Gracias! Nuevo en JS; toda su ayuda es apreciada
Nathan
3
A varias preguntas sobre cómo guardar un archivo sin que el usuario lo sepa: Tal comportamiento es justo lo que evita el diseño. Eso abriría una caja de Pandora de amenazas de seguridad fáciles de usar. Las cookies son para recopilar datos con fines de marketing.
Ari Okkonen
Tenga en cuenta que no puedo obtener esto para descargar un archivo html como .html en firefox v76 en Windows 10. La descarga tiene .pdf adjunto al final.
CSchwarz
23

La respuesta anterior es útil, pero encontré un código que te ayuda a descargar el archivo de texto directamente al hacer clic en el botón. En este código también puede cambiar filenamelo que desee. Es pura función de JavaScript con HTML5. ¡Funciona para mi!

function saveTextAsFile()
{
    var textToWrite = document.getElementById("inputTextToSave").value;
    var textFileAsBlob = new Blob([textToWrite], {type:'text/plain'});
    var fileNameToSaveAs = document.getElementById("inputFileNameToSaveAs").value;
      var downloadLink = document.createElement("a");
    downloadLink.download = fileNameToSaveAs;
    downloadLink.innerHTML = "Download File";
    if (window.webkitURL != null)
    {
        // Chrome allows the link to be clicked
        // without actually adding it to the DOM.
        downloadLink.href = window.webkitURL.createObjectURL(textFileAsBlob);
    }
    else
    {
        // Firefox requires the link to be added to the DOM
        // before it can be clicked.
        downloadLink.href = window.URL.createObjectURL(textFileAsBlob);
        downloadLink.onclick = destroyClickedElement;
        downloadLink.style.display = "none";
        document.body.appendChild(downloadLink);
    }

    downloadLink.click();
}
Niraj
fuente
2
Excelente. Funciona para mí en Opera. Excepto la necesidad de reemplazar la función desconocida: "destroyClickedElement" por la declaración "document.body.removeChild (event.target)"
steveOw
3
Debe tener cuidado al usarlo createObjectURL. A diferencia de la mayoría de las cosas en JS, los objetos que crea con él no se recolectan automáticamente cuando no hay más referencias a ellos; solo se recolectan cuando se cierra la página. Como no está utilizando URL.revokeObjectURL()este código para liberar la memoria utilizada por la última llamada, tiene una pérdida de memoria; Si el usuario llama saveTextFilevarias veces, continuará consumiendo más y más memoria porque nunca la liberó.
Código inútil
20

Tratar

let a = document.createElement('a');
a.href = "data:application/octet-stream,"+encodeURIComponent("My DATA");
a.download = 'abc.txt';
a.click();

Kamil Kiełczewski
fuente
6

En el caso de que no sea posible usar la nueva Blobsolución, esa es sin duda la mejor solución en el navegador moderno, aún es posible usar este enfoque más simple, que tiene un límite en el tamaño del archivo por cierto:

function download() {
                var fileContents=JSON.stringify(jsonObject, null, 2);
                var fileName= "data.json";

                var pp = document.createElement('a');
                pp.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(fileContents));
                pp.setAttribute('download', fileName);
                pp.click();
            }
            setTimeout(function() {download()}, 500);

$('#download').on("click", function() {
  function download() {
    var jsonObject = {
      "name": "John",
      "age": 31,
      "city": "New York"
    };
    var fileContents = JSON.stringify(jsonObject, null, 2);
    var fileName = "data.json";

    var pp = document.createElement('a');
    pp.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(fileContents));
    pp.setAttribute('download', fileName);
    pp.click();
  }
  setTimeout(function() {
    download()
  }, 500);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="download">Download me</button>

loretoparisi
fuente
3

Use el código del usuario @ useless-code anterior ( https://stackoverflow.com/a/21016088/327386 ) para generar el archivo. Si desea descargar el archivo automáticamente, pase el textFileque se acaba de generar a esta función:

var downloadFile = function downloadURL(url) {
    var hiddenIFrameID = 'hiddenDownloader',
    iframe = document.getElementById(hiddenIFrameID);
    if (iframe === null) {
        iframe = document.createElement('iframe');
        iframe.id = hiddenIFrameID;
        iframe.style.display = 'none';
        document.body.appendChild(iframe);
    }
    iframe.src = url;
}
RPM
fuente
55
No sé por qué esto obtuvo un voto negativo. Esto funciona para mi. ¡Las personas que rechazan el voto deberían al menos dejar un comentario sobre por qué se votó negativamente!
RPM
55
No voté en contra, pero en realidad se desaconseja comentar sobre la votación. El usuario debe comentar sobre el contenido de una publicación y votar sobre el contenido de una publicación, pero no debe comentar sobre sus votos. Si alguien vota sin comentar, puede tomarlo como "esta respuesta es útil" o "esta respuesta no es útil" dependiendo del voto emitido.
Esto no funciona. No descarga el archivo. Simplemente crea un iframe que está oculto.
Probé
2

Encontré buenas respuestas aquí, pero también encontré una manera más simple.

El botón para crear el blob y el enlace de descarga se pueden combinar en un enlace, ya que el elemento de enlace puede tener un atributo onclick. (Lo contrario parece imposible, agregar un href a un botón no funciona).

Puede bootstrapdiseñar el enlace como un botón utilizando , que todavía es JavaScript puro, excepto por el estilo.

La combinación del botón y el enlace de descarga también reduce el código, ya que getElementByIdse necesitan menos de esas llamadas feas .

Este ejemplo solo necesita hacer clic en un botón para crear el blob de texto y descargarlo:

<a id="a_btn_writetofile" download="info.txt" href="#" class="btn btn-primary" 
   onclick="exportFile('This is some dummy data.\nAnd some more dummy data.\n', 'a_btn_writetofile')"
>
   Write To File
</a>

<script>
    // URL pointing to the Blob with the file contents
    var objUrl = null;
    // create the blob with file content, and attach the URL to the downloadlink; 
    // NB: link must have the download attribute
    // this method can go to your library
    function exportFile(fileContent, downloadLinkId) {
        // revoke the old object URL to avoid memory leaks.
        if (objUrl !== null) {
            window.URL.revokeObjectURL(objUrl);
        }
        // create the object that contains the file data and that can be referred to with a URL
        var data = new Blob([fileContent], { type: 'text/plain' });
        objUrl = window.URL.createObjectURL(data);
        // attach the object to the download link (styled as button)
        var downloadLinkButton = document.getElementById(downloadLinkId);
        downloadLinkButton.href = objUrl;
    };
</script>
Roland
fuente
0

Sí, es posible Aquí el código es

const fs = require('fs') 
let data = "Learning how to write in a file."
fs.writeFile('Output.txt', data, (err) => { 
      
    // In case of a error throw err. 
    if (err) throw err; 
}) 

SM Turag
fuente