vue如何将Blob保存在固定的路径下面

背景描述
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 = ''
      }
    })
  },

效果如下

img

但是,我不想让它弹框,我想实现的效果是:在代码中指定路径,直接保存。

我百度了很久,都没有找到合适的方案

我尝试过,那怕使用file-saver也是有弹框,也是一样让你选择保存路径。

我的问题:
针对这种情形,请教大家有没有比较好的的方案?期待大家的指点,谢谢!

这个是web浏览器的安全策略限制,不能直接操作本地文件,你的需求涉及到操作本地文件,web方式肯定无法实现的,只能尽量考虑贴近满足你的需求的方式,或者考虑使用桌面软件辅助实现。

  1. 你的需求不能实现
  2. 不能实现的原因,浏览器有安全策略,不能随意的操作系统本地文件
  3. 试想想,能这么干了,黑客写个 "chrome.exe"包含木马的文件,把你系统中的文件替换了怎么办?

为了实现将从数据库中获取的二进制图片数据保存为本地文件,需要在后端代码中进行相应的操作。以下是一个可能的方案:

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 数据保存到指定的路径下,而是需要通过浏览器提供的下载功能来实现保存操作。这就导致了弹框选择保存路径的问题。

如果你希望在前端指定保存路径并实现保存功能,可以考虑以下两种方案:

  1. 使用前端的文件操作API(仅限部分现代浏览器):
    某些现代浏览器提供了文件系统访问API,如File System Access API、Native File System API等。你可以使用这些API与用户进行交互,请求用户选择保存路径,并将 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(); // 关闭文件句柄
}
  1. 将保存操作放在后端处理:
    如果你无法通过前端实现指定保存路径并保存文件的需求,你可以将保存操作放在后端进行处理。前端将 Blob 数据发送给后端,后端负责保存文件到指定路径。

在你的情况下,后端使用的是 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.');
  }
}

通过将保存操作放在后端处理,你可以更加灵活地控制文件保存的逻辑,并且不受前端浏览器的限制。。

该回答引用ChatGPT
Vue本身并不能直接将Blob保存到本地固定路径下,因为这属于浏览器的安全限制。如果可以直接保存到本地固定路径下,那么网页页面就能够随意修改本地文件,对用户的计算机安全造成威胁。不过,你可以使用第三方插件html5-filerwriter或者electron这样的框架来实现本地文件系统操作。

如果你只是想避免弹出下载对话框,可以使用Blob的URL.createObjectURL()方法创建一个Blob URL,并将其作为超链接的href属性。这样,即使使用超链接下载文件,浏览器也不会弹出对话框,而是直接下载。具体代码如下:

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


其中,download属性指定下载文件名,a.click()方法模拟点击下载链接,执行下载操作。

以下答案由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 类型来接收文件流,然后将流保存到指定路径。注意,这里的实际保存路径需要修改为你自己需要保存的路径。
如果我的回答解决了您的问题,请采纳!