js 写入文件存到本地,可用于抓取接口数据
工作中有时需要通过 JavaScript 保存文件到本地,我们都知道 JavaScript 基于安全的考虑,是不允许直接操作本地文件的。
IE 可以通过 VB 插件的方式进行,而 Chrome 和 firefox 都不支持 JavaScript 向本地写入文件,所以 VB 插件的方式存在兼容性问题。
那有没有适合的方法呢?答案是肯定的,我们可以通过 FileSaver.js 这个小插件实现我们的需求。下面看一段具体的代码吧:
// 此处案例用来抓取阿里地图数据 function demo() { var id = '100000' var num = 0 var time = 0 // 如果使用for循环,文件过多,可能会丢失文件,故使用延迟 function bound(id) { setTimeout(() => { $.ajax({ url: 'https://datavmap-public.oss-cn-hangzhou.aliyuncs.com/areas/bound/' + id + '.json', success(res) { // num++ // console.log(num) // downloadTextFile(id, JSON.stringify(res)) } }) }, time) time += 200 } function children(id) { $.ajax({ url: 'https://datavmap-public.oss-cn-hangzhou.aliyuncs.com/areas/children/' + id + '.json', success(res) { // num++ // console.log(num) bound(id) // downloadTextFile(id, JSON.stringify(res)) if (res.features.length) { for (let i = 0; i < res.features.length; i++) { const adcode = res.features[i].properties.adcode if (!res.features[i].properties.childrenNum) { // 如果没有子集数据 bound(adcode) continue } if (adcode != id) { children(adcode) } } } } }) } children(id) } demo() /** * 下载文件 * name 文件名 * mobileCode 文件内容 */ var downloadTextFile = function (name, mobileCode) { if (!mobileCode) { mobileCode = '' } // 采用的字符编码格式为“UTF-8”,这样就避免的中文乱码的问题。 var file = new File([mobileCode], name + ".json", { type: "text/plain;charset=utf-8" }) saveAs(file) }
附 FileSaver.js 文件的完整源码:
/* FileSaver.js * A saveAs() FileSaver implementation. * 1.3.2 * 2016-06-16 18:25:19 * * By Eli Grey, http://eligrey.com * License: MIT * See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md */ /* global self */ /* jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */ /*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */ var saveAs = saveAs || (function (view) { 'use strict' // IE <10 is explicitly unsupported if (typeof view === 'undefined' || typeof navigator !== 'undefined' && /MSIE [1-9]\./.test(navigator.userAgent)) { return } var doc = view.document // only get URL when necessary in case Blob.js hasn't overridden it yet var get_URL = function () { return view.URL || view.webkitURL || view } var save_link = doc.createElementNS('http://www.w3.org/1999/xhtml', 'a') var can_use_save_link = 'download' in save_link var click = function (node) { var event = new MouseEvent('click') node.dispatchEvent(event) } var is_safari = /constructor/i.test(view.HTMLElement) || view.safari var is_chrome_ios = /CriOS\/[\d]+/.test(navigator.userAgent) var throw_outside = function (ex) { (view.setImmediate || view.setTimeout)(function () { throw ex }, 0) } var force_saveable_type = 'application/octet-stream' // the Blob API is fundamentally broken as there is no "downloadfinished" event to subscribe to var arbitrary_revoke_timeout = 1000 * 40 // in ms var revoke = function (file) { var revoker = function () { if (typeof file === 'string') { // file is an object URL get_URL().revokeObjectURL(file) } else { // file is a File file.remove() } } setTimeout(revoker, arbitrary_revoke_timeout) } var dispatch = function (filesaver, event_types, event) { event_types = [].concat(event_types) var i = event_types.length while (i--) { var listener = filesaver['on' + event_types[i]] if (typeof listener === 'function') { try { listener.call(filesaver, event || filesaver) } catch (ex) { throw_outside(ex) } } } } var auto_bom = function (blob) { // prepend BOM for UTF-8 XML and text/* types (including HTML) // note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF if (/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) { return new Blob([String.fromCharCode(0xFEFF), blob], { type: blob.type }) } return blob } var FileSaver = function (blob, name, no_auto_bom) { if (!no_auto_bom) { blob = auto_bom(blob) } // First try a.download, then web filesystem, then object URLs var filesaver = this var type = blob.type var force = type === force_saveable_type var object_url var dispatch_all = function () { dispatch(filesaver, 'writestart progress write writeend'.split(' ')) } // on any filesys errors revert to saving with object URLs var fs_error = function () { if ((is_chrome_ios || (force && is_safari)) && view.FileReader) { // Safari doesn't allow downloading of blob urls var reader = new FileReader() reader.onloadend = function () { var url = is_chrome_ios ? reader.result : reader.result.replace(/^data:[^;]*;/, 'data:attachment/file;') var popup = view.open(url, '_blank') if (!popup) view.location.href = url url = undefined // release reference before dispatching filesaver.readyState = filesaver.DONE dispatch_all() } reader.readAsDataURL(blob) filesaver.readyState = filesaver.INIT return } // don't create more object URLs than needed if (!object_url) { object_url = get_URL().createObjectURL(blob) } if (force) { view.location.href = object_url } else { var opened = view.open(object_url, '_blank') if (!opened) { // Apple does not allow window.open, see https://developer.apple.com/library/safari/documentation/Tools/Conceptual/SafariExtensionGuide/WorkingwithWindowsandTabs/WorkingwithWindowsandTabs.html view.location.href = object_url } } filesaver.readyState = filesaver.DONE dispatch_all() revoke(object_url) } filesaver.readyState = filesaver.INIT if (can_use_save_link) { object_url = get_URL().createObjectURL(blob) setTimeout(function () { save_link.href = object_url save_link.download = name click(save_link) dispatch_all() revoke(object_url) filesaver.readyState = filesaver.DONE }) return } fs_error() } var FS_proto = FileSaver.prototype var saveAs = function (blob, name, no_auto_bom) { return new FileSaver(blob, name || blob.name || 'download', no_auto_bom) } // IE 10+ (native saveAs) if (typeof navigator !== 'undefined' && navigator.msSaveOrOpenBlob) { return function (blob, name, no_auto_bom) { name = name || blob.name || 'download' if (!no_auto_bom) { blob = auto_bom(blob) } return navigator.msSaveOrOpenBlob(blob, name) } } FS_proto.abort = function () { } FS_proto.readyState = FS_proto.INIT = 0 FS_proto.WRITING = 1 FS_proto.DONE = 2 FS_proto.error = FS_proto.onwritestart = FS_proto.onprogress = FS_proto.onwrite = FS_proto.onabort = FS_proto.onerror = FS_proto.onwriteend = null return saveAs }( typeof self !== 'undefined' && self || typeof window !== 'undefined' && window || this.content )) // `self` is undefined in Firefox for Android content script context // while `this` is nsIContentFrameMessageManager // with an attribute `content` that corresponds to the window if (typeof module !== 'undefined' && module.exports) { module.exports.saveAs = saveAs } else if ((typeof define !== 'undefined' && define !== null) && (define.amd !== null)) { define('FileSaver.js', function () { return saveAs }) }