I am trying to stream the response of fetch(very large tar file) to a file using streamsaver library. But the file is not created/written, even though "done writing" is printed in the console.
Here is my code.
const fileStream = streamSaver.createWriteStream('cat.tar')
fetch(requestUrl).then(res => {
const readableStream = res.body
// more optimized
if (window.WritableStream && readableStream.pipeTo) {
return readableStream.pipeTo(fileStream)
.then(() => console.log('done writing'))
}
window.writer = fileStream.getWriter()
const reader = res.body.getReader()
const pump = () => reader.read()
.then(res => res.done
? window.writer.close()
: window.writer.write(res.value).then(pump))
pump()
})
I can not find the file in my system. Is there any piece that I am missing?
You mentioned that you're using the latest version of Chrome. In that environment, it's possible to stream directly to disk from a
fetch
response using the File System Access API by piping the response'sReadableStream
to theFileSystemWritableFileStream
of aFileSystemFileHandle
.Here's the description of how this works from the page
FileSystemWritableFileStream.write
:My interpretation of this is that once the temporary file is completely written, it is moved into the place of the selected file handle, overwriting it. (Perhaps someone can clarify this technicality in a comment.) In any case, it seems to satisfy your criteria of "not buffering the entire download stream contents in memory before writing".
Using this method, you'll be responsible for managing all UI indications (start, error, progress, end, etc.) as it won't use the browser's native file download UI: you can hook into stream events using a custom
TransformStream
for progress monitoring.The MDN docs that I've linked to have all the information you need to understand how to use these APIs. However, I also prepared a basic and contrived, but self-contained example that you can run using a static file server on
localhost
to see it all working:streaming-file-download.html
: