如何在本地存储中保存和恢复 File 对象
Posted
技术标签:
【中文标题】如何在本地存储中保存和恢复 File 对象【英文标题】:How do I save and restore a File object in local storage 【发布时间】:2013-10-07 18:45:12 【问题描述】:我有一个使用
的 html5/javscript 应用程序<input type="file" accept="image/*;capture=camera" onchange="gotPhoto(this)">
捕捉相机图像。因为我的应用想要离线运行,我如何将 File (https://developer.mozilla.org/en-US/docs/Web/API/File) 对象保存在本地存储中,以便以后可以检索它以进行 ajax 上传?
我正在从 using ... 中获取文件对象
function gotPhoto(element)
var file = element.files[0];
//I want to save 'file' to local storage here :-(
我可以Stringify对象并保存它,但是当我恢复它时,它不再被识别为File对象,因此不能用于抓取文件内容。
我感觉无法完成,但愿意接受建议。
FWIW 我的解决方法是在存储时读取文件内容并将全部内容保存到本地存储。这可行,但会很快消耗本地存储,因为每个文件都是 1MB 以上的照片。
【问题讨论】:
由于本地存储只支持字符串,您必须将文件转换为base 64(或某种形式的字符串) 例如:developer.mozilla.org/en-US/docs/Web/API/… 我的建议是将 dataURL 添加到您的文件对象并在之后对其进行字符串化。所以你有完整的文件对象,你可以加载存储了 dataURL 的图像。 jsfiddle.net/bR8Nt/1 @pinoyyid 因为实际上没有办法在 javascript 中实例化File
对象,所以你很不走运。最接近的替代方法是,当从本地存储恢复字符串编码文件时,创建一个Blob
,File
继承自该文件。您可以将Blob
用于大多数您本来可以使用File
的事情。如果您认为这样的示例有用,我会写下来。但它并不能真正解决您的问题,只是让您更接近您真正想要的对象。
@dandavis,谢谢,但与所有答案一样,这需要我保存图像内容的副本。我试图将 File 对象简单地存储为指向手机图库中 .jpg 文件的指针。
【参考方案1】:
您不能序列化文件 API 对象。
并不是说它有助于解决特定问题,而是... 虽然我没用过,但如果你看here,似乎有一些方法(尽管大多数浏览器还不支持)将离线图像数据存储到一些文件中,以便在用户在线时恢复它们(并且不使用本地存储)
【讨论】:
感谢您的链接。一旦文件系统 API 得到更好的支持,它可能会提供比 indexeddb 更好的替代方案。无论哪种方式,我最终都会得到图像的第二个副本(画廊中的原件和我保存在某处的副本),这是我试图避免的。但遗憾的是我认为“你不能序列化文件 API 对象”是正确的答案。 虽然我想你将它保存到 javascript blob,但我觉得使用隐藏的画布对象也有帮助,你可以在其中绘制图像数据,当你在线时从画布中获取图像数据。数据。我想这个画布可以在 iframe 中?只要需要,它就可以持续存在(以免本地存储出现问题)。但同样,只要你有它在 javascript 中,你为什么还要把它放到一个画布对象中呢? 问题是页面/浏览器重新加载。如果用户卸载页面,我会丢失内存中存储的所有内容。 是的,我明白了,这就是为什么你试图将它持久地存储在其他地方。我可以提到的另一件事是,为了拥有更多空间,您可以按顺序消耗浏览器的所有可用空间。我的意思是,例如,您可以按顺序使用本地存储、闪存、google gears,即 userdata 等(就像 Persistjs 一样,但同时使用),但这需要大量编码。无论如何,希望你能找到答案。 这是不可能的,因为存在明显的安全风险。如果允许您将 File 对象作为字符串保存在本地存储中,您还可以修改该字符串以在用户不知道的情况下访问同一目录中的其他文件。【参考方案2】:这是我使用以下代码的一种解决方法。我知道您在编辑时谈到了 localStorage,但我想分享一下我是如何实际实施该解决方法的。我喜欢将函数放在 body 上,这样即使之后通过 AJAX 添加了类,“更改”命令仍然会触发事件。
在此处查看我的示例:http://jsfiddle.net/x11joex11/9g8NN/
如果您运行 JSFiddle 示例两次,您会看到它记住了图像。
我的方法确实使用了 jQuery。这种方法还证明了图像确实存在以证明它有效。
HTML:
<input class="classhere" type="file" name="logo" id="logo" />
<div class="imagearea"></div>
JS:
$(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 检查器,您会注意到图像以 base64 编码存储。
阅读器是异步的,这就是它使用回调函数onload的原因。因此,请确保任何需要图像的重要代码都在 onLoad 中,否则您可能会得到意想不到的结果。
【讨论】:
感谢您发布解决方法,我相信它会对人们有所帮助。我希望我可以编辑您的答案以强调它是一种解决方法,而不是问题的答案。我正在寻找一种方法来保存文件对象而不制作图像数据的第二个副本。 是的,我也在找你要找的东西,我希望它可以完成,我悬赏看看是否有人能弄清楚。 @pinoyyid 这是一种解决方法吗?它有什么问题? 我特别希望持久化文件 object,而不是文件 content。我的应用程序面向移动设备,因此图像已保存在图库中。我想存储对图库图像的引用,而不是使用 localstorage 制作第二个副本,并附带所有的大小限制。 没有。我想要整个 File 对象【参考方案3】:将其转换为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
【讨论】:
谢谢,但请再次阅读问题。我不想保存文件内容,我想保存 File 对象。【参考方案4】:你可以使用这个库:
https://github.com/carlo/jquery-base64
然后做类似的事情:
//Set file
var baseFile = $.base64.encode(fileObject);
window.localStorage.setItem("file",basefile);
//get file
var outFile = window.localStorage.getItem("file");
另一种解决方案是使用 json(我更喜欢这种方法) 使用:http://code.google.com/p/jquery-json/
//Set file
window.localStorage.setItem("file",$.toJSON(fileobject));
//get file
var outFile = $.evalJSON(window.localStorage.getItem("file"));
【讨论】:
谢谢,但您错过了问题的重点。我不是在问如何保存任意的通用对象。我在问如何保存 File 对象,以便在恢复时它可以用作 File 对象。【参考方案5】:我认为没有直接的方法可以将字符串对象字符串化,然后将字符串对象反序列化为您感兴趣的对象。但作为一种解决方法,您可以将图像路径存储在本地存储中,并通过检索图像的 URL 来加载图像。优点是,您永远不会用完存储空间,并且可以在那里存储 1000 倍以上的文件。将图像或任何其他文件作为字符串保存在本地存储中绝不是一个明智的决定。
【讨论】:
"您可以将图像路径存储在本地存储中,并通过检索图像的 URL 来加载图像" 。不,你不能 你可以..你可以存储图像的路径,然后从本地存储中加载它吗?是什么让你认为你不能?保留一个键作为别名,并将图像文件的 url 存储为值。我在我的项目中已经这样做了。 Javascript 安全模型不允许从本地驱动器读取文件。【参考方案6】:在全局范围内创建一个对象
exp: var attmap = new Object();
完成文件选择后,将文件放入 attmap 变量中,如下所示,
attmap[file.name] = attachmentBody;
JSON.stringify(attmap)
然后可以通过input hidden等方式发送到controller,反序列化后使用。
(Map<String, String>)JSON.deserialize(attachments, Map<String,String>.class);
您可以在 for 循环等中使用这些值创建文件。
EncodingUtil.base64Decode(CurrentMapValue);
仅供参考:此解决方案还将涵盖多个文件选择
【讨论】:
【参考方案7】:你可以这样做:
// 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');
【讨论】:
存储文件的内容。我正在寻找一种方法来存储 File 对象。以上是关于如何在本地存储中保存和恢复 File 对象的主要内容,如果未能解决你的问题,请参考以下文章
请问AS3.0 怎样可以将Bitmap对象保存为本地图片文件(如JPG文件)。谢谢!
如何在浏览器本地存储 Flutter Web 应用程序中保存对象列表
如何在 Objective-C iOs 8 上将 ParseObject 存储在本地数据存储和 Parse Cloud 中?