Можно ли записать данные в файл, используя только JavaScript?


192

Я хочу записать данные в существующий файл, используя JavaScript. Я не хочу печатать это на консоли. Я хочу на самом деле записать данные в abc.txt. Я прочитал много ответов на вопросы, но каждый, где они печатают на консоли. в каком-то месте они дали код, но он не работает. Поэтому, пожалуйста, кто-нибудь может мне помочь Как записать данные в файл.

Я сослался на код, но он не работает: ошибка выдачи:

Uncaught TypeError: Неверный конструктор

на хром и

SecurityError: операция небезопасна.

на Мозилле

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
HTML5 API не более 5 МБ.
Pacerier

Да, вы не можете записать в системный файл без его выбора. Читайте Официальные документы: w3.org/TR/file-upload/#security-discussion
Манодж Гедия

217

Вы можете создавать файлы в браузере, используя 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
@ Бенни символы новой строки там. 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
Несколько вопросов о сохранении файла без ведома пользователя: такое поведение - это то, чего избегает дизайн. Это открыло бы ящик Пандоры простых в использовании угроз безопасности. Файлы cookie предназначены для сбора данных в маркетинговых целях.
Ари Окконен

Примечание. Я не могу получить это, чтобы загрузить html-файл в формате .html в Firefox v76 в Windows 10. К концу файла добавлен файл .pdf.
Чварц

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
Превосходно. У меня работает в Опере. Кроме необходимости заменить неизвестную функцию: "destroyClickedElement" на выражение «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-code выше ( 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, который скрыт. Я тестировал на Chrome и Firefox
NaiveCoder

2

Я нашел хорошие ответы здесь, но также нашел более простой способ.

Кнопка для создания большого двоичного объекта и ссылки для скачивания может быть объединена в одну ссылку, поскольку элемент ссылки может иметь атрибут onclick. (Обратное кажется невозможным, добавление ссылки к кнопке не работает.)

Вы можете стилизовать ссылку как кнопку, используя 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.