Có thể ghi dữ liệu vào tệp chỉ bằng JavaScript không?


190

Tôi muốn ghi dữ liệu vào tệp hiện có bằng JavaScript. Tôi không muốn in nó trên bàn điều khiển. Tôi thực sự muốn ghi dữ liệu vào abc.txt. Tôi đọc nhiều câu trả lời nhưng mọi nơi họ đang in trên bàn điều khiển. tại một số nơi họ đã đưa ra mã nhưng nó không hoạt động. Vì vậy, xin vui lòng bất cứ ai có thể giúp tôi Làm thế nào để thực sự ghi dữ liệu vào tập tin.

Tôi đã giới thiệu mã nhưng nó không hoạt động: lỗi đưa ra:

Uncaught TypeError: Xây dựng bất hợp pháp

trên chrome và

SecurityError: Hoạt động không an toàn.

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

Vì vậy, chúng ta thực sự có thể ghi dữ liệu vào tệp chỉ bằng Javascript hay KHÔNG?



Câu trả lời:


89

Một số gợi ý cho việc này -

  1. Nếu bạn đang cố gắng viết một tệp trên máy khách, Bạn không thể thực hiện việc này theo bất kỳ cách nào trên nhiều trình duyệt. IE có các phương thức để cho phép các ứng dụng "đáng tin cậy" sử dụng các đối tượng ActiveX để đọc / ghi tệp.
  2. Nếu bạn đang cố lưu nó trên máy chủ của mình thì chỉ cần truyền dữ liệu văn bản đến máy chủ của bạn và thực thi mã viết tệp bằng một số ngôn ngữ phía máy chủ.
  3. Để lưu trữ một số thông tin về phía khách hàng nhỏ đáng kể, bạn có thể đi tìm cookie.
  4. Sử dụng API HTML5 cho Bộ nhớ cục bộ.

27
API HTML5 chỉ đạt tối đa 5 mb.
Pacerier

Có, bạn không thể ghi vào tệp hệ thống mà không chọn nó. Đọc tài liệu chính thức: w3.org/TR/file-upload/#security-discussion
Manoj Ghediya

216

Bạn có thể tạo tập tin trong trình duyệt bằng BlobURL.createObjectURL. Tất cả các trình duyệt gần đây hỗ trợ này .

Bạn không thể trực tiếp lưu tệp bạn tạo, vì điều đó sẽ gây ra sự cố bảo mật lớn, nhưng bạn có thể cung cấp tệp đó dưới dạng liên kết tải xuống cho người dùng. Bạn có thể đề xuất tên tệp thông qua downloadthuộc tính của liên kết, trong các trình duyệt hỗ trợ thuộc tính tải xuống. Như với bất kỳ tải xuống nào khác, người dùng tải xuống tệp sẽ có tiếng nói cuối cùng về tên tệp.

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

Đây là một ví dụ sử dụng kỹ thuật này để lưu văn bản tùy ý từ a textarea.

Nếu bạn muốn bắt đầu tải xuống ngay lập tức thay vì yêu cầu người dùng nhấp vào liên kết, bạn có thể sử dụng các sự kiện chuột để mô phỏng nhấp chuột vào liên kết như câu trả lời của Lifecube đã làm. Tôi đã tạo một ví dụ cập nhật sử dụng kỹ thuật này.

  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 Phần nào không hoạt động, bạn có bị lỗi không? Việc tạo tệp và liên kết sẽ hoạt động trong Safari 7+ (Tôi tin rằng công cụ đó cũng sẽ hoạt động khi sử dụng trong Safari 6 nếu bạn sử dụng phiên bản tiền tố của URL). Đặt tên tệp sẽ không hoạt động trong Safari vì nó vẫn chưa triển khai downloadthuộc tính .
Mã vô dụng

1
Tôi đã dùng thử trên Safari 5.1 :)
Máu đầu tiên

1
ký tự dòng mới bị thiếu trong tài liệu đã lưu
Benny

1
@Benny các nhân vật dòng mới đang ở đó. JS sử dụng ký tự dòng mới \nđể biểu diễn các dòng mới như các chương trình UNIX làm. Bạn có thể đang xem nó trong một chương trình Windows, chẳng hạn như Notepad, không hiển thị \nký tự dưới dạng một dòng mới . Nếu bạn muốn các dòng mới được hiển thị chính xác trong Notepad và một số chương trình Windows khác, trước khi đưa văn bản vào Blobthay thế từng dòng \nbằng \r\n: text = text.replace(/\n/g, '\r\n').
Mã vô dụng

2
@ user3241111 Không thực sự, nó sẽ hoạt động. Những thứ như thế không phải là bất thường. Tôi đã thấy các cách thức hackyer để thực hiện nó ;-) Trước đây tôi cũng đã từng tạo ra tệp trên mouseoverliên kết, nhưng tùy thuộc vào mức độ xử lý của nó mà nó có thể không hoạt động tốt.
Mã vô dụng

41

Nếu bạn đang nói về javascript trình duyệt, bạn không thể ghi dữ liệu trực tiếp vào tệp cục bộ vì lý do bảo mật. API mới HTML 5 chỉ có thể cho phép bạn đọc tệp.

Nhưng nếu bạn muốn ghi dữ liệu và cho phép người dùng tải xuống dưới dạng tệp sang cục bộ. đoạn mã sau hoạt động:

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

để dùng nó:

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


Thật tuyệt vời, Lifecube. Tôi thực sự cần chức năng đó, mặc dù tôi không muốn người dùng biết rằng bất kỳ tệp nào đang được tải xuống, tôi muốn nó bị ẩn hoàn toàn khỏi người dùng vì nó có thể khiến người dùng hoảng sợ khi thấy một số tệp đang được tải xuống tự động khi thực hiện một số hành động trên một trang web, mặc dù chúng tôi chỉ sử dụng nó cho mục đích thu thập dữ liệu tiếp thị, bạn có thể chia sẻ cách tải xuống tệp mà không hiển thị cho người dùng không?
Just_another_developer

1
các giải pháp trên là loại lỗi thời. Bạn có thể cần phải xem xét lib lib javascript html 5. github.com/eligrey/FileSaver.js
Lifecube

@Lifecube sử dụng FileSaver.js, có cách nào để tự động lưu văn bản vào một tệp mà không có sự tương tác của người dùng không? Cảm ơn! Mới đối với JS; tất cả sự giúp đỡ của bạn đều được đánh giá cao
Nathan

2
Đối với một số câu hỏi về việc lưu tệp mà người dùng không biết: Hành vi như vậy chỉ là những gì được thiết kế tránh. Điều đó sẽ mở ra một hộp các mối đe dọa bảo mật dễ sử dụng của Pandora. Cookies là để thu thập dữ liệu cho mục đích tiếp thị.
Ari Okkonen

Lưu ý Tôi không thể tải xuống tệp html này dưới dạng .html trong firefox v76 trên Windows 10. Tải xuống có .pdf được thêm vào cuối của nó.
CSchwarz

23

Câu trả lời trên là hữu ích, nhưng tôi đã tìm thấy mã giúp bạn tải xuống tệp văn bản trực tiếp khi nhấp vào nút. Trong mã này, bạn cũng có thể thay đổi filenamenhư bạn muốn. Đó là chức năng javascript thuần túy với HTML5. Làm việc cho tôi!

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
Thông minh. Làm việc cho tôi trên Opera. Ngoại trừ việc cần phải thay thế chức năng chưa biết: "killClickyEuity" bằng câu lệnh "document.body.removeChild (event.target)"
steveOw

3
Bạn cần cẩn thận khi sử dụng createObjectURL. Không giống như hầu hết mọi thứ trong JS, các đối tượng bạn tạo với nó không tự động được thu thập rác khi không có thêm các tham chiếu đến chúng; chúng chỉ là rác được thu thập khi đóng trang. Vì bạn không sử dụng URL.revokeObjectURL()mã này để giải phóng bộ nhớ được sử dụng bởi cuộc gọi cuối cùng, nên bạn bị rò rỉ bộ nhớ; nếu người dùng gọi saveTextFilenhiều lần, họ sẽ tiếp tục tiêu thụ nhiều bộ nhớ hơn vì bạn không bao giờ giải phóng nó.
Mã vô dụng


6

Trong trường hợp không thể sử dụng Blobgiải pháp mới , chắc chắn đó là giải pháp tốt nhất trong trình duyệt hiện đại, vẫn có thể sử dụng phương pháp đơn giản hơn, có giới hạn về kích thước tệp theo cách:

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

Sử dụng mã bởi người dùng @ vô dụng - mã ở trên ( https://stackoverflow.com/a/21016088/327386 ) để tạo tệp. Nếu bạn muốn tải xuống tệp tự động, hãy chuyển tệp textFilevừa được tạo cho chức năng này:

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
Không biết tại sao điều này đã bỏ phiếu xuống. Nó làm việc cho tôi. Những người xuống bỏ phiếu ít nhất nên để lại một bình luận về lý do tại sao điều này đã được bỏ phiếu!
RPM

5
Tôi đã không downvote, nhưng thực sự bình luận về bỏ phiếu là trực tiếp không được khuyến khích. Người dùng nên bình luận về nội dung của bài đăng và bỏ phiếu về nội dung của bài đăng, nhưng họ không nên bình luận về phiếu bầu của mình. Nếu ai đó bỏ phiếu mà không bình luận, bạn có thể hiểu là "câu trả lời này hữu ích" hoặc "câu trả lời này không hữu ích" tùy thuộc vào phiếu bầu.

Điều này không hoạt động .. Nó không tải tập tin. Nó chỉ tạo một iframe bị ẩn. Tôi đã thử nghiệm trên chrome & firefox
NaiveCoder

2

Tôi tìm thấy câu trả lời tốt ở đây, nhưng cũng tìm thấy một cách đơn giản hơn.

Nút để tạo blob và liên kết tải xuống có thể được kết hợp trong một liên kết, vì thành phần liên kết có thể có thuộc tính onclick. (Điều ngược lại dường như là không thể, thêm a href vào nút không hoạt động.)

Bạn có thể định kiểu liên kết dưới dạng nút bằng cách sử dụng bootstrapjavascript thuần túy, ngoại trừ kiểu dáng.

Kết hợp nút và liên kết tải xuống cũng làm giảm mã, vì cần ít getElementByIdcuộc gọi xấu hơn .

Ví dụ này chỉ cần một nút bấm để tạo blob văn bản và tải xuống:

<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

Có, nó có thể ở đây mã là

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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.