Чи можливо записувати дані у файл, використовуючи лише JavaScript?


191

Я хочу записати дані в існуючий файл за допомогою JavaScript. Я не хочу друкувати його на консолі. Я хочу насправді записувати дані abc.txt. Я читав багато відповідей на запитання, але там, де вони друкують на консолі. десь вони дали код, але він не працює. Тож будь ласка, будь-хто може допомогти мені Як насправді записати дані у файл.

Я вказав код, але він не працює: його помилка в наданні:

Uncaught TypeError: Незаконний конструктор

на хром і

SecurityError: Операція небезпечна.

на 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();
}

Тож чи можемо ми насправді записувати дані у файл, використовуючи лише Javascript або НЕ?


2
Перевірте це брат: stackoverflow.com/questions/585234 / ...
welbornio

Відповіді:


90

Деякі пропозиції щодо цього -

  1. Якщо ви намагаєтесь записати файл на клієнтській машині, ви не можете це зробити жодним крос-браузерним способом. IE має методи, що дозволяють "довіреним" програмам використовувати об'єкти ActiveX для читання / запису файлів.
  2. Якщо ви намагаєтеся зберегти їх на своєму сервері, просто передайте текстові дані на ваш сервер та виконайте код написання файлу, використовуючи мову сторони сервера.
  3. Щоб зберегти певну інформацію на стороні клієнта, яка значно мала, можна перейти до файлів cookie.
  4. Використання HTML5 API для локального зберігання.

27
API API HTML5 розміщується лише в 5 Мб.
Pacerier

Так, ви не можете записати в системний файл, не вибравши його. Читайте офіційні документи: w3.org/TR/file-upload/#security-discussion
Manoj Ghediya

216

Ви можете створювати файли в браузері за допомогою Blobі URL.createObjectURL. Усі останні веб-переглядачі підтримують це .

Ви не можете безпосередньо зберегти створений файл, оскільки це може спричинити великі проблеми із безпекою, але ви можете надати його як посилання для завантаження для користувача. Ви можете запропонувати ім'я файлу через downloadатрибут посилання у веб-переглядачах, які підтримують атрибут завантаження. Як і у випадку з будь-яким іншим завантаженням, користувач, який завантажує файл, має остаточно сказати ім'я файлу.

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;
  };

Ось приклад, який використовує цю техніку для збереження довільного тексту з а textarea.

Якщо ви хочете негайно почати завантаження , замість того , щоб вимагати від користувача натиснути на посилання, ви можете використовувати подія миші , щоб імітувати клацання миші по посиланню , як Lifecube «s відповідь зробив. Я створив оновлений приклад, який використовує цю техніку.

  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);

1
@FirstBlood Яка частина не працює, ви отримуєте помилку? Створення файлів та посилань має працювати в Safari 7+ (я вважаю, що матеріали також повинні працювати в Safari 6, якщо ви використовуєте попередньо встановлену версію URL). Налаштування імені файлу не працюватиме в Safari, оскільки він досі не реалізував downloadатрибут .
Марний код

1
Я пробував це на Safari 5.1 :)
Перша кров

1
новий символ рядка відсутній у збереженому документі
Бенні

1
@Benny символи нового рядка є. JS використовує символ нового рядка \nдля представлення нових ліній, як це роблять програми UNIX. Ви, ймовірно, переглядаєте його в програмі Windows, наприклад, Блокноті, яка не відображає \nсимвол як новий рядок . Якщо ви хочете , щоб нові рядки правильно відображаються в блокноті і деякі інші програми для Windows, перш ніж покласти текст в Blobзмінюють один \nз \r\n: text = text.replace(/\n/g, '\r\n').
Марний код

2
@ user3241111 Не дуже, це має працювати. Такі речі не все так незвично. Я бачив, як хакерські способи зробити це ;-) У минулому я також пішов із простого генерування файлу за mouseoverпосиланням, але залежно від того, скільки обробляється, це може не працювати.
Марний код

41

Якщо ви говорите про JavaScript браузера, ви не можете записати дані безпосередньо в локальний файл з міркувань безпеки. Новий API HTML 5 може дозволяти лише читати файли.

Але якщо ви хочете записати дані, і дозволити користувачеві завантажувати як файл в локальний. працює наступний код:

    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;
}

використовувати його:

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


Дивовижна, Lifecube. Мені дуже потрібна ця функціональність, хоча я не хочу, щоб користувач знав, що якийсь файл завантажується, я хочу його повністю приховати від користувача, оскільки він може відробити користувача, побачивши, що якийсь файл завантажується автоматично, виконуючи певні дії На веб-сайті, хоча ми використовуємо його лише для збору маркетингових даних, ви можете поділитися, як завантажити файл, не зробивши його видимим для користувача?
Just_another_developer

1
вищевказане рішення є дещо застарілим. Можливо, вам доведеться розглянути html 5 javascript lib. github.com/eligrey/FileSaver.js
Lifecube

@Lifecube за допомогою FileSaver.js, чи є спосіб автоматично зберігати текст у файл без взаємодії з користувачем? Дякую! Новачок у JS; вся ваша допомога вдячна
Натан

3
До кількох питань щодо збереження файлу, не знаючи цього користувача: Така поведінка - це саме те, чого дизайн уникає. Це відкриє скриньку Pandora прості у використанні загрози безпеці. Файли cookie призначені для збору даних для маркетингових цілей.
Арі Окконен

Примітка. Я не можу отримати це, щоб завантажити файл HTML у форматі .html у firefox v76 в Windows 10. Завантажений файл .pdf додається до кінця.
CSchwarz

23

Відповідь вище корисна, але я знайшов код, який допомагає завантажувати текстовий файл безпосередньо при натисканні кнопки. У цьому коді ви також можете змінювати filenameза своїм бажанням. Це чиста функція javascript з HTML5. Для мене працює!

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();
}

2
Відмінно. Працює для мене в Опері. Окрім необхідності замінити невідому функцію: "killClickedElement" на операцію "document.body.removeChild (event.target)"
steveOw

3
Потрібно бути обережним при використанні createObjectURL. На відміну від більшості речей у JS, об’єкти, які ви створюєте з нею, автоматично не збираються сміттям, коли на них більше немає посилань; вони є лише сміттям, зібраним, коли сторінка закривається. Оскільки ви не використовуєте URL.revokeObjectURL()в цьому коді для звільнення пам'яті, використаної для останнього дзвінка, у вас є витік пам'яті; якщо користувач дзвонить saveTextFileкілька разів, він буде продовжувати споживати все більше і більше пам’яті, оскільки ви його ніколи не випускали.
Марний код


6

У тому випадку, коли неможливо використовувати нове Blobрішення, тобто, безумовно, найкраще рішення в сучасному браузері, все-таки можна скористатися цим більш простим підходом, який до речі має обмеження у розмірі файлу:

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>


3

Використовуйте код користувачем @ useless-кодом вище ( https://stackoverflow.com/a/21016088/327386 ) для створення файлу. Якщо ви хочете завантажити файл автоматично, передайте textFileщойно створений файл цій функції:

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;
}

5
Не знаєте, чому це отримало голосування проти. Це працює для мене. Люди, які відмовились від голосу, повинні хоча б залишити коментар щодо того, чому за цей голос було відмовлено
RPM

5
Я не став голосом, але фактично коментувати голосування прямо не рекомендується. Користувач повинен коментувати зміст публікації та проголосувати за зміст повідомлення, але він не повинен коментувати свої голоси. Якщо хтось голосує, не коментуючи, ви можете вважати, що ця відповідь є корисною або "ця відповідь не корисна" залежно від голосування.

Це не працює. Він не завантажує файл. Він просто створює прихований кадр iframe. Я перевірив хром та firefox
NaiveCoder

2

Тут я знайшов хороші відповіді, але також знайшов більш простий спосіб.

Кнопку створення блобу та посилання для завантаження можна поєднати в одне посилання, оскільки елемент посилання може мати атрибут onclick. (Зворотний вигляд здається не можливим. Додавання href до кнопки не працює.)

Ви можете стилізувати посилання як кнопку, використовуючи bootstrap, що все ще є чистим JavaScript, за винятком стилів.

Поєднання кнопки та посилання для завантаження також зменшує код, оскільки потрібно менше таких негарних getElementByIdдзвінків.

Цей приклад потребує лише одного натискання кнопки, щоб створити текстовий фрагмент і завантажити його:

<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>

0

Так це можливо Тут код є

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; 
}) 

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.