Blazor.FileSystemAccess icon indicating copy to clipboard operation
Blazor.FileSystemAccess copied to clipboard

Processing a file "uploaded" via <InputFile>

Open JasonKoopmans opened this issue 3 years ago • 3 comments

Is it possible to save a file that's "uploaded" through the <InputFile /> component and wind up saving it through the FileAPI implemented in your library? I see references to Blob and File -- but it isn't clear if those are translatable to the IBrowserFile interface thats available when the onchange event fires on the InputFile.

Consider:

<InputFile   OnChange="@OnChange" />

Which is handled by:

public void OnChange(InputFileChangeEventArgs args) {
  // file implements IBrowserFile, which contains OpenReadStream()
  var file = args.File
  

}

JasonKoopmans avatar May 11 '22 02:05 JasonKoopmans

Thanks for the issue. I will try to explore this issue more closely.

My first bet would be that it is not directly possible, but we could probably read the content of the file as a string or byte array and then create a new Blob using some custom JSInterop and parse that to the library through the CreateAsync method on the Blob class.

KristofferStrube avatar May 11 '22 08:05 KristofferStrube

I have now constructed an example that shows how to use them together.

@page "/InputFileExample"
@inject FileSystemAccessService FileSystemAccessService

<PageTitle>InputFile Example</PageTitle>

<InputFile OnChange="OnChange" />
<br />
@if (buffer is not null)
{
    <button @onclick="Save">Save</button>
}

@code {
    public byte[] buffer;

    public async Task OnChange(InputFileChangeEventArgs args)
    {
        var file = args.File;
        using var stream = file.OpenReadStream();
        buffer = new byte[stream.Length];
        await stream.ReadAsync(buffer);
    }

    public async Task Save()
    {
        var fileHandle = await FileSystemAccessService.ShowSaveFilePickerAsync();
        var writable = await fileHandle.CreateWritableAsync();
        await writable.WriteAsync(BytesToString(buffer));
        await writable.CloseAsync();
    }

    private static string BytesToString(byte[] bytes)
    {
        using MemoryStream stream = new MemoryStream(bytes);
        using StreamReader streamReader = new StreamReader(stream);
        return streamReader.ReadToEnd();
    }
}

The example can also be seen here: https://kristofferstrube.github.io/Blazor.FileSystemAccess/InputFileExample

It is not the most beautiful thing and I think a way that could makes this nicer would be if the FileSystemWritableFileStream where to extend the Stream class and override some of its methods like others have suggested earlier. I will keep this issue open to track progress on that.

  • [x] Make FileSystemWritableFileStream extend Stream

KristofferStrube avatar May 24 '22 09:05 KristofferStrube

Thanks for sharing this. FileSystemWritableFileStream extending Stream would would be convenient. This example works for small files, but this needs to load the files completely into memory which would be a problem for larger files

JasonKoopmans avatar Jun 10 '22 22:06 JasonKoopmans