เป็นไปได้ไหมที่จะเขียนข้อมูลลงไฟล์โดยใช้ 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. ในการจัดเก็บข้อมูลบางอย่างทางฝั่งไคลเอ็นต์ที่มีขนาดเล็กมากคุณสามารถไปหาคุกกี้ได้
  4. ใช้ HTML5 API สำหรับ Local Storage

27
HTML5 API สามารถขยายได้สูงสุด 5 mb เท่านั้น
Pacerier

ใช่คุณไม่สามารถเขียนลงในไฟล์ระบบโดยไม่ต้องเลือกมัน อ่านเอกสารอย่างเป็นทางการ: w3.org/TR/file-upload/#security-discussion
Manoj Ghediya

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
อักขระบรรทัดใหม่หายไปจากเอกสารที่บันทึก
Benny

1
@Benny มีอักขระขึ้นบรรทัดใหม่ JS ใช้อักขระขึ้นบรรทัดใหม่\nเพื่อแสดงบรรทัดใหม่เช่นโปรแกรม UNIX คุณอาจจะดูมันในโปรแกรม Windows เช่น Notepad, ซึ่งไม่ได้ทำให้\nตัวละครเป็นบรรทัดใหม่ หากคุณต้องการขึ้นบรรทัดใหม่ที่จะแสดงผลได้อย่างถูกต้องใน Notepad และบางส่วนโปรแกรมอื่น ๆ ของ 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
วิธีการแก้ปัญหาข้างต้นเป็นชนิดที่ล้าสมัย คุณอาจต้องพิจารณา lib HTML 5 จาวาสคริปต์ github.com/eligrey/FileSaver.js
Lifecube

@Lifecube ใช้ FileSaver.js มีวิธีบันทึกข้อความไปยังไฟล์โดยอัตโนมัติหรือไม่ ขอบคุณ! ใหม่สำหรับ JS; ความช่วยเหลือทั้งหมดของคุณได้รับการชื่นชม
นาธาน

3
สำหรับคำถามหลายข้อเกี่ยวกับการบันทึกไฟล์โดยที่ผู้ใช้ไม่ทราบ: พฤติกรรมดังกล่าวเป็นเพียงสิ่งที่หลีกเลี่ยงได้จากการออกแบบ นั่นจะเป็นการเปิดกล่องภัยคุกคามความปลอดภัยที่ใช้งานง่ายของ Pandora คุกกี้ใช้สำหรับรวบรวมข้อมูลเพื่อวัตถุประสงค์ทางการตลาด
Ari Okkonen

หมายเหตุฉันไม่สามารถดาวน์โหลดไฟล์ html นี้ในรูปแบบ. html ใน firefox v76 บน Windows 10 ได้การดาวน์โหลดนั้นมีไฟล์. pdf ต่อท้ายไฟล์
CSchwarz

23

คำตอบข้างต้นมีประโยชน์ แต่ฉันพบรหัสที่ช่วยให้คุณสามารถดาวน์โหลดไฟล์ข้อความได้โดยตรงจากการคลิกปุ่ม ในรหัสนี้คุณสามารถเปลี่ยนได้filenameตามที่คุณต้องการ มันเป็นฟังก์ชั่นจาวาสคริปต์ที่บริสุทธิ์ด้วย 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
ยอดเยี่ยม ทำงานได้ดีสำหรับฉันบน Opera ยกเว้นต้องเปลี่ยนฟังก์ชั่นที่ไม่รู้จัก: "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

ใช้รหัสโดย user @ 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 (ดูเหมือนว่าย้อนกลับเป็นไปไม่ได้การเพิ่ม href ในปุ่มไม่ทำงาน)

คุณสามารถจัดรูปแบบการเชื่อมโยงเป็นปุ่มโดยใช้bootstrapซึ่งยังคงเป็นจาวาสคริปต์ที่บริสุทธิ์ยกเว้นการจัดแต่งทรงผม

การรวมปุ่มและลิงค์ดาวน์โหลดยังช่วยลดรหัสเนื่องจากgetElementByIdจำเป็นต้องใช้การโทรที่น่าเกลียดน้อยลง

ตัวอย่างนี้ต้องการเพียงคลิกเดียวเพื่อสร้าง text-blob และดาวน์โหลด:

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.