从 indexedDB 中存储的文件句柄加载的文件在文件更改和重新加载页面时不会更新

File loaded from file handle stored in indexedDB does not update when file is changed and page is reloaded

提问人:Mircode 提问时间:10/24/2023 更新时间:10/27/2023 访问量:24

问:

使用此处介绍的方法:

https://stackoverflow.com/a/65938910/3825996

我创建了一个网页,您可以在其中将文件拖放到任何地方,并显示内容。拖放后,文件的句柄存储在 indexedDB 中,刷新页面时,将再次打开并显示上次拖放的文件。

我希望如果我更改文件并重新加载页面,就会显示新内容,但事实并非如此。但是,如果我拖放更改的文件,它将正确显示更改的内容。

在Chrome中,我还做了“清空缓存和硬重新加载”,但它仍然显示旧文件内容。

为什么会这样?文件句柄是否存储完整文件?我该怎么做才能在刷新后重新加载更改的文件?

代码如下: (不能作为 HTML 代码片段使用)

<html>
<head></head>
<body>
    <div id="display"></div>
    <script>
        // stolen from https://www.npmjs.com/package/idb-keyval

        function promisifyRequest(request) {
            return new Promise((resolve, reject) => {
                request.oncomplete = request.onsuccess = () => resolve(request.result);
                request.onabort = request.onerror = () => reject(request.error);
            });
        }

        function createStore(dbName, storeName) {
            const request = indexedDB.open(dbName);
            request.onupgradeneeded = () => request.result.createObjectStore(storeName);
            const dbp = promisifyRequest(request);
            return (txMode, callback) => dbp.then((db) => callback(db.transaction(storeName, txMode).objectStore(storeName)));
        }

        let defaultGetStoreFunc;
        function defaultGetStore() {
            if (!defaultGetStoreFunc) {
                defaultGetStoreFunc = createStore('keyval-store', 'keyval');
            }
            return defaultGetStoreFunc;
        }

        function idbLoad(key, customStore = defaultGetStore()) {
            return customStore('readonly', (store) => promisifyRequest(store.get(key)));
        }

        function idbStore(key, value, customStore = defaultGetStore()) {
            return customStore('readwrite', (store) => {
                store.put(value, key);
                return promisifyRequest(store.transaction);
            });
        }

        function makeKey(domElement) {
            return 'lastOpened-' + domElement.tagName + "-" + domElement.id;
        }

        async function handleFile(domElement, file) {
            await idbStore(makeKey(domElement), file);
            const reader = new FileReader();
            reader.onload = function (e) {
                domElement.dispatchEvent(
                    new CustomEvent("handlefilecontent", { detail: e.target.result })
                );
            };
            reader.readAsText(file);
        }

        function dropHandler(ev) {
            ev.preventDefault();

            if (ev.dataTransfer.items) {
                [...ev.dataTransfer.items].forEach((item, i) => {
                    if (item.kind === "file") {
                        const file = item.getAsFile();
                        handleFile(ev.currentTarget, file);
                    }
                });
            } else {
                [...ev.dataTransfer.files].forEach((file, i) => {
                    handleFile(ev.currentTarget, file);
                });
            }
        }

        function dragOverHandler(ev) {
            ev.preventDefault();
        }

        async function checkLastOpened(domElement) {
            try {
                let file = await idbLoad(makeKey(domElement));
                if (file) {
                    handleFile(domElement, file)
                }
            } catch (error) {
                alert(error.name, error.message);
            }
        }

        function dragDropInitialize(domElement, callback) {
            domElement.addEventListener("drop", dropHandler)
            domElement.addEventListener("dragover", dragOverHandler)
            domElement.addEventListener("handlefilecontent", (ev) => { callback(ev.detail) })
            checkLastOpened(domElement)
        }

        dragDropInitialize(document.body, (content) => {
            document.getElementById("display").innerHTML = content
        })
    </script>
</body>

</html>
JavaScript 文件读取器 索引数据库 页面刷新

评论


答:

1赞 Joshua Bell 10/27/2023 #1

通过 's 或 's list 返回的对象是对象,它们不等同于文件句柄,而是代表文件本身的数据——在 Web 平台 API 中,a 基本上只是一个带有名称的对象。DataTransferItemgetAsFile()DataTransferfilesFileFileBlob

因此,当您调用传递文件时,您实际上是在将文件的内容存储到数据库中。在存储发生时,实现将啜饮文件的内容并将其存储在数据库中。这就是为什么您在重新加载页面时看不到新数据的原因。idbStore()

评论

0赞 Mircode 10/27/2023
谢谢你的解释!你知道有没有办法实现我想要的吗?也许将数据存储在 .js 文件中并以某种方式重新导入?
1赞 Joshua Bell 11/1/2023
基于 Chromium 的浏览器提供了用于本地文件访问的新 API。在这种情况下,您将获得一个 FileSystemHandle 对象,该对象可用于读取文件并存储在 IDB 中。请注意,出于隐私/安全原因,当句柄随后从数据库中拉出时,系统将重新提示用户进行访问。您可以通过测试 DataTransferItem 对象是否具有 getAsFileSystemHandle() 方法来检测这一点,这是您访问句柄的方式。developer.mozilla.org/en-US/docs/Web/API/DataTransferItem/......