Cody S
Cody S

Reputation: 4824

IndexedDB Save range as

Ok, so I'm new to IndexedDB and not particularly experienced with Javascript. Right now, I've got code working such that the user can browse to a file on their file system, and, when selected, the file is broken up into chunks (by using slice), those chunks are converted to Hex strings, and the strings (along with a key) are stored in IndexedDB.

The nice thing about this modality is that a user could select a very large file, and, since I'm using the right constructs, the whole file doesn't have to be loaded in memory all at once.

Now I'm attempting to read those Hex strings back out and have the browser pop a "Save as" dialog when the user clicks a button. The issue is that I haven't managed to find a way to "stream" the data out of IndexedDB into a Save As input. Are any of you aware of a way to do this? I'm coming up pretty short on my end.

Thanks

Upvotes: 3

Views: 581

Answers (2)

Brett Sutton
Brett Sutton

Reputation: 4554

So I'm also looking to do this and will update this answer as the implementation proceeds.

The idea is to create two entity types in indexdb.

  1. file
  2. page

There will be an entry in the file entity for each file stored in index db.

The content of the file will be stored in the page entity. The content will be split up into 'pages' where each page is some (arbitrary) fixed size such as 16KB.

My code will be written in dart (which cross compiles to javascript) but the logic should be easy to port directly to js.

I will create a class that will operate some what like a random access file.

Note: this is just pseudo code at this point.

  class RandomAccessFile {
       const int pageSize = 16192;
       int offset = 0;
       int page = 0;
       int inPageOffset = 0;
       List<int> currentPageData;
       String pathToFile;
       late int fileSize;
       RandomAccessFile(this.pathToFile)
       {
          var file = indexDb.read('File', this.pathToFile);
          this.fileSize = file.size;
       }

       void seekTo(int offset)
       {
          this.offset = offset;
          this.page = offset/pageSize;
          this.inPageOffset = offset % pageSize;
        }    
      Stream<int> read() async * {
      { 
         
         _loadPage();
         while (this.offset < fileSize)
         {
             
             while (this.inPageOffset < currentPageData.length) 
             {  
                  yield currentPageData[this.inPageOffset++];
             }
             _loadNextPage()
         }
      }
      void _loadPage()
      {
          currentPageData =  indexDb.read('Page', where file = pathTofile and pageNo = page);
          pageOffset = 0;
       }

  void _loadNextPage()
      {
         page++;
         _loadPage();
           
       }
}

Upvotes: 0

Kyaw Tun
Kyaw Tun

Reputation: 13131

IndexedDB cannot do partial (or projection) read/write on record. FileSystem API seems, likely, since it is for such use case like sequential seek over a large file, but I am not sure.

You might want to check out this recent discussion, IndexedDB, Blobs and partial Blobs - Large Files. They discuss workaround on your problem as well.

Upvotes: 1

Related Questions