javascript - 将内存流中的文件提供给 Bokeh 应用程序
问题描述
我正在尝试向 Bokeh webapp 的用户提供文件下载(.csv 和 .png)。目前,这是通过在本地保存文件的副本并执行读取该文件的 Javascript 来实现的(根据此示例和此 SO 问题):
def save_file(self, save_function, file_name):
"""
:param save_function: callable that takes a single argument: the file path to save to
:param file_name: default name for the downloaded file
"""
js_download = """
fetch(local_path, {cache: "no-store"}).then(response => response.blob())
.then(blob => {
//addresses IE
if (navigator.msSaveBlob) {
navigator.msSaveBlob(blob, save_name);
}
else {
const link = document.createElement('a')
link.href = URL.createObjectURL(blob)
link.download = save_name
link.target = '_blank'
link.style.visibility = 'hidden'
link.dispatchEvent(new MouseEvent('click'))
}
return response.text();
});
"""
# Make a tempory file name to avoid conflicts
temp_name = next(tempfile._get_candidate_names())
temp_path = f'static/{temp_name}.tmp'
save_function(temp_path)
self.exectute_js(CustomJS(args=dict(local_path='/AzDataTools/' + temp_path,
save_name=file_name), code=js_download))
def exectute_js(self, custom_js):
# Setup a dummy plot to trigger the javascript
dummy = self.get_any_figure().circle([1], [2], alpha=0)
dummy.glyph.js_on_change('size', custom_js)
dummy.glyph.size = 1
理想情况下,我希望通过保存到内存流来跳过本地文件步骤。我的尝试看起来像:
def save_file_via_memory(self, save_function, file_name):
"""
:param save_function: callable that takes a single argument: the file path to save to
:param file_name: default name for the downloaded file
"""
js_download = """
var blob = new Blob(data)
//addresses IE
if (navigator.msSaveBlob) {
navigator.msSaveBlob(blob, save_name);
}
else {
const link = document.createElement('a')
link.href = URL.createObjectURL(blob)
link.download = save_name
link.target = '_blank'
link.style.visibility = 'hidden'
link.dispatchEvent(new MouseEvent('click'))
};
"""
with io.BytesIO() as data:
save_function(data)
self.exectute_js(CustomJS(args=dict(data=data, save_name=file_name), code=js_download))
但是,这会产生错误,指示字节流不能被序列化。有人知道如何将字节流传递给 JavaScript 吗?(JavaScript也可能不正确,这是我第一次使用它...)
解决方案
我最终得到的解决方法是将文件转换为文本字符串。对于 csvs 和图像,这看起来像:
def save_text_file(self, text, file_name):
"""
:param text: text to save
:param file_name: default name for the downloaded file
"""
js_download = """
const blob = new Blob([text_string], { type: 'text/csv;charset=utf-8;' })
//addresses IE
if (navigator.msSaveBlob) {
navigator.msSaveBlob(blob, file_name)
} else {
const link = document.createElement('a')
link.href = URL.createObjectURL(blob)
link.download = file_name
link.target = '_blank'
link.style.visibility = 'hidden'
link.dispatchEvent(new MouseEvent('click'))
}
"""
self.exectute_js(CustomJS(args=dict(text_string=text, file_name=file_name), code=js_download))
def image_to_png_string(image_bytes):
data_uri = base64.b64encode(image_bytes).decode('utf-8')
return 'data:image/png;base64,' + data_uri
def save_image_file(self, image, file_name):
"""
:param image: image bytes to save
:param file_name: default name for the downloaded file
"""
js_download = """
fetch(image_string, {cache: "no-store"}).then(response => response.blob())
.then(blob => {
//addresses IE
if (navigator.msSaveBlob) {
navigator.msSaveBlob(blob, file_name);
}
else {
const link = document.createElement('a')
link.href = URL.createObjectURL(blob)
link.download = file_name
link.target = '_blank'
link.style.visibility = 'hidden'
link.dispatchEvent(new MouseEvent('click'))
}
return response.text();
});
"""
self.exectute_js(CustomJS(args=dict(image_string=image_to_png_string(image), file_name=file_name),
code=js_download))
推荐阅读
- java - [CORS][SpringSecurity] PreFlight request not handle
- flutter - Flutter:RangeError(索引):无效值:不在0..14范围内,包括:15
- python - 使用 GEKKO 的 MPC 中的可变边界
- javascript - Why are my array elements being reported as undefined?
- angular - 错误:formGroup 需要一个 FormGroup 实例。请传递一个。无法获取数据
- angular - Initial transform in runtime angular cdk drag and drop
- php - Using wordpress shortcode to add html attributes
- python-2.7 - How to use mock_open with pickle.load
- python - Missing location of warnings and occurrences in Spyder 4
- javascript - JavaScript 编号不会显示