背景描述
1,前端使用vue2, 后端使用ABP
2, 前端请求后端从数据库中获取二进制图片数据
3,后端获取到数据后,希望能够保存为本地文件
前端代码如下
async getMapImage() {
await GetMapImage(state.form.floor, state.form.libraryId).then((res) => {
if (res.result.list.length > 0) {
var libraryMap = res.result.list[0] // 获取数据库图片
const { mapImage } = libraryMap
var raw = window.atob(mapImage)
var rawLength = raw.length
var uInt8Array = new Uint8Array(rawLength)
for (var i = 0; i < rawLength; ++i) {
uInt8Array[i] = raw.charCodeAt(i)
}
var blob = new Blob([uInt8Array], { type: 'image/png' }) // 转成blog形式
// 保存图片
var aLink = document.createElement('a') // 创建一个超连接,用来挂载图片url
var evt = document.createEvent('HTMLEvents') // 自定义事件
evt.initEvent('click', true, true)
aLink.download = state.form.libraryId + '_' + state.form.floor + '.png' // 保存图片的名称
aLink.href = URL.createObjectURL(blob) // 挂载图片
aLink.click() // 触发超连接的点击事件
URL.revokeObjectURL(aLink.href)
} else {
state.printStyle = ''
}
})
},
效果如下
但是,我不想让它弹框,我想实现的效果是:在代码中指定路径,直接保存。
我百度了很久,都没有找到合适的方案
我尝试过,那怕使用file-saver也是有弹框,也是一样让你选择保存路径。
我的问题:
针对这种情形,请教大家有没有比较好的的方案?期待大家的指点,谢谢!
这个是web浏览器的安全策略限制,不能直接操作本地文件,你的需求涉及到操作本地文件,web方式肯定无法实现的,只能尽量考虑贴近满足你的需求的方式,或者考虑使用桌面软件辅助实现。
为了实现将从数据库中获取的二进制图片数据保存为本地文件,需要在后端代码中进行相应的操作。以下是一个可能的方案:
1、在后端代码中,设置一个API接口来处理前端请求,并从数据库中获取二进制图片数据。
2、对于获取到的二进制图片数据,可以使用Node.js内置的文件系统库(fs)来进行文件的写入操作,将其保存为本地文件。示例代码如下:
const fs = require('fs');
// 接收前端请求并从数据库中获取二进制图片数据的代码...
let imageData = ... // 获取到的二进制图片数据
// 将图片数据保存为本地文件
fs.writeFile('/path/to/save/image.jpg', imageData, (err) => {
if (err) throw err;
console.log('Image file saved successfully!');
});
```
3、在上述代码中,/path/to/save/代表要保存文件的路径,image.jpg代表要保存的文件名。你可以根据需要更改这些值。
4、在Vue前端代码中,使用axios等HTTP库向该API接口发送请求即可。注意要确保请求中包含必要的参数(如查询条件等),以便在后端正确地获取到所需的数据。
需要注意的是,保存文件的过程涉及到文件读写操作,并且需要进行一定的权限控制和错误处理,因此需要仔细编写代码以确保安全和可靠性。
看我文章
import FileSaver from "file-saver";
export default class fileSave {
/**
* 导出Excel文件
* @param {*} res 文件流
* @param {*} name 文件名
*/
static getExcel(res, name) {
let blob = new Blob([res], {
type: "application/vnd.ms-excel"
});
FileSaver.saveAs(blob, name + ".xlsx");
}
/**
* 导出CSV文件
* @param {*} res 文件流
* @param {*} name 文件名
*/
static getCsv(res, name) {
let blob = new Blob([res], {
type: "application/vnd.ms-excel"
});
FileSaver.saveAs(blob, name + ".csv");
}
/**
* 导出图片1
* @param {*} url 图片地址
* @param {*} name 文件名
*/
static getImgURLs(url, name) {
let last = url.substring(url.lastIndexOf("."), url.length);
FileSaver.saveAs(url, `${name}${last}`);
}
/**
* 导出图片2
* @param {*} res 文件流
* @param {*} name 文件名
*/
static downLoadImg(res, filename) {
let blob = new Blob([res], {
type: "image/jpeg"
});
FileSaver.saveAs(blob, `${filename}.jpg`);
}
}
在前端中,由于浏览器的安全性限制,无法直接将 Blob 数据保存到指定的路径下,而是需要通过浏览器提供的下载功能来实现保存操作。这就导致了弹框选择保存路径的问题。
如果你希望在前端指定保存路径并实现保存功能,可以考虑以下两种方案:
这些API仍然处于实验阶段,并且兼容性有限。因此,使用这些API可能需要检查浏览器是否支持,并进行相应的兼容处理。
以下是使用File System Access API的简单示例代码:
javascript
async function saveBlobToFile(blob) {
const handle = await window.showSaveFilePicker(); // 请求用户选择保存路径
const writable = await handle.createWritable(); // 创建可写文件句柄
await writable.write(blob); // 将 Blob 数据写入文件
await writable.close(); // 关闭文件句柄
}
在你的情况下,后端使用的是 ABP 框架,你可以在后端编写相应的接口,接收前端发送的 Blob 数据,并将其保存到指定路径。在前端代码中,将 Blob 数据通过 API 发送给后端即可。
后端示例代码(使用Node.js和Express):
javascript
const fs = require('fs');
// 后端接口
app.post('veBlob', (req, res) => {
const blob = req.body.blob; // 假设前端通过请求体发送 Blob 数据
const filePath = '/path/tove/file.png'; // 指定保存路径
fs.writeFile(filePath, blob, (err) => {
if (err) {
console.error(err);
res.status(500).send('Failed to save the file.');
} else {
res.send('File saved successfully.');
}
});
});
前端示例代码:
javascript
async function saveBlobToServer(blob) {
const url = 'veBlob'; // 后端接口URL
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/octet-stream',
},
body: blob,
});
if (response.ok) {
console.log('File saved successfully on the server.');
} else {
console.error('Failed to save the file on the server.');
}
}
通过将保存操作放在后端处理,你可以更加灵活地控制文件保存的逻辑,并且不受前端浏览器的限制。。
该回答引用ChatGPTJavaScript
var blob = new Blob([uInt8Array], { type: 'image/png' });
var url = window.URL.createObjectURL(blob);
var a = document.createElement('a');
a.href = url;
a.download = 'filename.png'; // 指定下载文件名
a.click();
window.URL.revokeObjectURL(url);
以下答案由GPT-3.5大模型与博主波罗歌共同编写:
在JavaScript中,浏览器端是无法直接写入文件的,因为这涉及到安全问题。因此,如果想要保存文件到指定路径,需要通过前端向后端发送一个保存请求,由后端来进行文件的保存操作。
对于这个问题,你可以考虑在前端通过 AJAX 或者 Fetch API 向后端发送保存请求,后端接收到请求后将文件保存到指定路径。前端代码如下:
async getMapImage() {
await GetMapImage(state.form.floor, state.form.libraryId).then((res) => {
if (res.result.list.length > 0) {
var libraryMap = res.result.list[0] // 获取数据库图片
const { mapImage } = libraryMap
var raw = window.atob(mapImage)
var rawLength = raw.length
var uInt8Array = new Uint8Array(rawLength)
for (var i = 0; i < rawLength; ++i) {
uInt8Array[i] = raw.charCodeAt(i)
}
var blob = new Blob([uInt8Array], { type: 'image/png' }) // 转成blog形式
// 向后端发送保存请求
fetch('/saveFile', {
method: 'POST',
body: blob,
headers: {
'Content-Type': 'application/octet-stream'
}
})
.then(response => {
// 处理响应结果
})
.catch(error => {
// 处理错误信息
});
} else {
state.printStyle = ''
}
})
},
后端代码如下:
[HttpPost]
public async Task<IActionResult> SaveFile()
{
var stream = new MemoryStream();
await Request.Body.CopyToAsync(stream);
var filePath = "指定的路径及文件名";
using var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write);
await stream.CopyToAsync(fileStream);
return Ok();
}
这个示例中,我们使用了 fetch 函数来发送 POST 请求,请求的参数是文件 blob。由于文件是二进制数据,因此需要设置 Content-Type 为 application/octet-stream。在后端接收到请求后,先使用 MemoryStream 类型来接收文件流,然后将流保存到指定路径。注意,这里的实际保存路径需要修改为你自己需要保存的路径。
如果我的回答解决了您的问题,请采纳!