Javascript 如何在本地存储中保存和恢复文件对象

Javascript 如何在本地存储中保存和恢复文件对象,javascript,html,local-storage,Javascript,Html,Local Storage,我有一个HTML5/javscript应用程序,它使用 <input type="file" accept="image/*;capture=camera" onchange="gotPhoto(this)"> 我可以对对象进行字符串化并保存它,但当我还原它时,它不再被识别为文件对象,因此无法用于获取文件内容 我觉得这是不可能的,但我愿意接受建议 FWIW我的解决方法是在存储时读取文件内容,并将完整内容保存到本地存储。这是可行的,但很快就会占用本地存储空间,因为每个文件都是一张1M

我有一个HTML5/javscript应用程序,它使用

<input type="file" accept="image/*;capture=camera" onchange="gotPhoto(this)">
我可以对对象进行字符串化并保存它,但当我还原它时,它不再被识别为文件对象,因此无法用于获取文件内容

我觉得这是不可能的,但我愿意接受建议


FWIW我的解决方法是在存储时读取文件内容,并将完整内容保存到本地存储。这是可行的,但很快就会占用本地存储空间,因为每个文件都是一张1MB以上的照片。

您可以使用此库:

然后做类似的事情:

//Set file
var baseFile = $.base64.encode(fileObject);
window.localStorage.setItem("file",basefile);

//get file
var outFile = window.localStorage.getItem("file");
另一个解决方案是使用json(我更喜欢这种方法) 使用:


无法序列化文件API对象。

不是说这有助于解决具体问题,而是。。。
虽然我没有使用过这个,但是如果你看一下,似乎有一些方法(尽管大多数浏览器还不支持)可以将脱机图像数据存储到一些文件中,以便在用户联机时恢复它们(而不是使用本地存储)

下面是我使用下面代码的一个解决方法。我知道您在编辑中提到了localStorage,但我想与大家分享一下我是如何实际实现该解决方案的。我喜欢将函数放在body上,这样即使之后通过AJAX添加了类,“change”命令仍然会触发事件

请参见我的示例:

如果两次运行JSFIDLE示例,您将看到它记住了图像

我的方法确实使用jQuery。这种方法也证明了图像实际上是存在的,以证明它是有效的

HTML:

<input class="classhere" type="file" name="logo" id="logo" />
<div class="imagearea"></div>
$(document).ready(function(){
  //You might want to do if check to see if localstorage set for theImage here
  var img = new Image();                
  img.src = localStorage.theImage;

  $('.imagearea').html(img);

  $("body").on("change",".classhere",function(){
      //Equivalent of getElementById
      var fileInput = $(this)[0];//returns a HTML DOM object by putting the [0] since it's really an associative array.
      var file = fileInput.files[0]; //there is only '1' file since they are not multiple type.

      var reader = new FileReader();
      reader.onload = function(e) {
           // Create a new image.
           var img = new Image();

           img.src = reader.result;
           localStorage.theImage = reader.result; //stores the image to localStorage
           $(".imagearea").html(img);
       }

       reader.readAsDataURL(file);//attempts to read the file in question.
    });
});
这种方法使用HTML5文件系统API读取图像并将其放入新的javascript img对象中。这里的关键是readAsDataURL。如果使用chrome inspector,您会注意到图像是以base64编码存储的


读卡器是异步的,这就是它使用onload回调函数的原因。因此,请确保任何需要图像的重要代码都在onLoad中,否则您可能会得到意外的结果

我认为没有一种直接的方法可以将字符串对象字符串化,然后反序列化为您感兴趣的对象。但是作为一种解决方法,您可以将图像路径存储在本地存储器中,并通过检索图像的URL来加载图像。这样做的好处是,您永远不会耗尽存储空间,并且可以在那里存储1000倍以上的文件。。将图像或任何其他文件保存为本地存储中的字符串从来都不是明智的决定

将其转换为base64,然后保存

function gotPhoto(element) {
   var file = element.files[0];
   var reader = new FileReader()
   reader.onload = function(base64) {
      localStorage["file"] = base64;
   }
   reader.readAsDataURL(file);
}
// Saved to localstorage

function getPhoto() {
   var base64 = localStorage["file"];
   var base64Parts = base64.split(",");
   var fileFormat = base64Parts[0].split(";")[1];
   var fileContent = base64Parts[1];
   var file = new File([fileContent], "file name here", {type: fileFormat});
   return file;
}
// Retreived file object

在全局作用域上创建对象

exp: var attmap = new Object();
完成文件选择后,将文件放入attmap变量中,如下所示

attmap[file.name] = attachmentBody;
JSON.stringify(attmap)
然后您可以通过输入隐藏等方式将其发送到控制器,并在反序列化后使用它

(Map<String, String>)JSON.deserialize(attachments, Map<String,String>.class);

仅供参考:此解决方案还将涵盖多个文件选择

您可以执行以下操作:

// fileObj = new File(); from file input
const buffer = Buffer.from(await new Response(fileObj).arrayBuffer());
const dataUrl = `data:${fileObj.type};base64,${buffer.toString("base64")}`;

localStorage.setItem('dataUrl', dataUrl);

然后你可以做:

document.getElementById('image').src = localStorage.getItem('dataUrl');

由于本地存储只支持字符串,因此必须将文件转换为base 64(或字符串的某种形式)。例如:我的建议是将dataURL添加到文件对象中,然后将其字符串化。因此,您拥有完整的文件对象,并且可以加载存储了dataURL的图像@pinoyyid因为实际上没有办法在JavaScript中实例化
文件
对象,所以你几乎不走运。最接近的替代方法是,在从本地存储还原字符串编码的文件时,创建一个
Blob
,该Blob从
file
继承。您可以使用
Blob
来处理大多数事情,否则您将使用
文件来处理这些事情。如果你认为这方面的例子有用,我会写下来。不过,这并不能真正解决你的问题,只是让你更接近你似乎真正想要的对象。@dandavis,谢谢,但和所有答案一样,这需要我保存一份图像内容的副本。我只是想把文件对象作为指向.jpg文件的指针存储在我的手机图库中。谢谢,但你没有抓住问题的关键。我不是问如何保存任意的通用对象。我想问的是,如何保存一个文件对象,使其在还原时可用作文件对象。谢谢链接。一旦文件系统API得到更好的支持,它可能会提供比indexeddb更好的替代方案。无论哪种方式,我最终都会得到该图像的第二份副本(画廊中的原件和保存在某处的副本),这正是我试图避免的。但遗憾的是,我认为“您无法序列化文件API对象”是正确的答案。尽管我认为您可以将其保存到javascript blob中,但我觉得使用隐藏的画布对象也会有所帮助,您可以在其中绘制图像数据,并在联机时从canvas.data获取图像数据。我想这幅画布可能在一个iframe中?它可以在需要时保持多久(以避免本地存储出现问题)。但是,同样,只要在javascript中有它,为什么还要将它也放在画布对象中呢?问题是页面/浏览器重新加载。如果用户卸载页面,我将丢失存储在内存中的所有内容。是的,我理解,这就是为什么您要将其永久存储在其他位置。我可以提到的另一件事是,为了获得更多的空间,您可以依次使用浏览器的所有可用空间。我的意思是,例如,您可以按顺序使用localstorage、flash存储、googlegears、ie userdata等(就像Persistjs一样,但并行使用),但这需要大量的编码。无论如何,希望你能找到答案。这是不可能的,因为存在明显的安全风险。如果允许您将文件对象作为字符串保存在本地存储中,您还可以修改该字符串,以便在用户不知道的情况下访问同一目录中的其他文件。感谢您发布解决方案,我相信这将对人们有所帮助。我希望没问题
EncodingUtil.base64Decode(CurrentMapValue);
// fileObj = new File(); from file input
const buffer = Buffer.from(await new Response(fileObj).arrayBuffer());
const dataUrl = `data:${fileObj.type};base64,${buffer.toString("base64")}`;

localStorage.setItem('dataUrl', dataUrl);

document.getElementById('image').src = localStorage.getItem('dataUrl');