GithubHelp home page GithubHelp logo

kristofferstrube / blazor.filesystemaccess Goto Github PK

View Code? Open in Web Editor NEW
316.0 10.0 38.0 12.78 MB

A Blazor wrapper for the File System Access browser API.

Home Page: https://kristofferstrube.github.io/Blazor.FileSystemAccess/

License: MIT License

C# 98.54% JavaScript 1.46%
filesystemaccess filesystemaccessapi blazor blazor-webassembly github-actions github-pages editor csharp jsinterop wrapper

blazor.filesystemaccess's Introduction

Kristoffer Strube

I'm currently working on using Blazor Web Apps to work with the browser easily and safely.

Right now, I'm focusing on wrapping the Web Audio API and its surrounding API's in my Blazor.WebAudio and Blazor.MediaCaptureStreams projects.

My Blog: https://kristoffer-strube.dk

I also do consultancy primarily focused on Blazor. If you are interested in my services, just contact me on Twitter or LinkedIn. Jobs related to my open-source projects get a considerable rebate.

Contact

Twitter ๐Ÿค: @KStrubeG

LinkedIn ๐Ÿ‘”: KristofferStrube

Mastodon ๐Ÿ˜: @KristofferStrube

BlueSky ๐Ÿฆ‹: @kstrubeg.bsky.social

blazor.filesystemaccess's People

Contributors

alexandernorup avatar datvm avatar fixnil avatar kristofferstrube avatar nzmangan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

blazor.filesystemaccess's Issues

NuGet and check API availability

Hello Kristoffer, great wrapper!

Are you planning to add this wonderful library to NuGet?

An "isSupported" method will be great as well, I don't know exactly if some browsers will add partial support to this API later...

Thank you, best regards

Regression: Change to API specs to use File System API.

At the start of December 2022, a lot of the definitions that were a part of the File System Access API were moved to the File System API.
The awesome part is that the File System API is supported on all major browsers! ๐Ÿ˜ƒ (Firefox not included)
You can see the PR here from the specs which shows a lot of deletions that are just because the specs were moved to the File System API specs.
WICG/file-system-access#392

This sounds like a breaking change, but happily, this doesn't break any of the features in this wrapper, so we simply have to move the appropriate functionality at some point.

Feature: Stream read Blobs

In Version 1.1.0 we added that FileSystemWritableFileStream extends Stream so that we could easily stream write to that.
I would like the same for Blob so that we easily stream read from that.

We have had some discussion on this in issue #19 already but I wanted to have this issue to track this feature independently.

If we look at the specifications of a Blob we can see that it has a stream method.
So a part of this issue is to explore what a stream in JS is and which similarities it has with Stream from .NET.

A consideration we had in the other discussion was whether or not this work on wrapping JS Blob should actually live in this repo. If we were to split that out and take a dependency on it then others could potentially also utilize it without depending on this repo.

Tree Map Chart

This issue is not high priority as it is not a problem with the core-library but instead with the Tree Map Chart which is used in the sample.

When many files are loaded the rectactangles sometimes gets placed the wrong place. I have not yet found an minimal reproducible example, but the problem seems to be deterministic and consistent across browsers.

image

How to get a StreamReader

Hi, I'm trying to use FileSystemAccess to read a big csv file and I need a StreamReader. I saw that I can get a ReadableStream using GetFileStream but I can't figure out how to convert that into a StreamReader.

Any help will be appreciated.

Thanks!

Bug: The specs have changed to give `FilePickerAcceptType.Description` a default value.

The specs have been updated so that FilePickerAcceptType.Description now has a standard value equal to the empty string i.e. "".

We need to update this in a patch version. This should only be a patch version as it is only a conformance change that won't affect the end users of the library as the previous default value would have been ignored anyway.

This was discovered through the live status page https://kristofferstrube.github.io/Blazor.FileSystemAccess/Status ๐ŸŽˆ

Bug: The option StartIn is invalid

Hi @KristofferStrube,

There is bad news and good news here ๐Ÿ˜ƒ

The bad news is that StartIn is invalid, because the new keyword makes it impossible to get the data covered by the child class in the parent class.

The good news is that I fixed the issue and submitted a PR.

How Specify a custom directory (not well knows) to create a file

I'd like to specify a custom inital directory to save a new file using the library, instead using well know directories...

llike...

var options = new SaveFilePickerOptionsStartInWellKnownDirectory() { SuggestedName = "PROVA.D01", StartIn = "C:\test"};
FileHandle = await FileSystemAccessService.ShowSaveFilePickerAsync(options);

Enhancement: Add tests and API coverage documentation

Why?

The wrapper is prone to human errors as it is an interpretation of the Web IDL specifications.
We have already seen such errors e.g. in PR #14. I originally didn't think that I needed to use unit tests for this project as the primary business logic was present in either the JS files or the actual browser API which would make it unsuitable for testing.

What?

What should we then test?
We have already seen that there can be some errors with the serialization because we create some of the objects used for serialization ourselves when objects have special inheritance relations. This should be tested.
We have also seen cases where we had missed special overloads of some methods from the original API. We should go through the Web IDL specifications systematically and ensure that representative methods/properties are present in the wrapper. This will also serve as an overview of which methods from the wrapper represent which methods in the underlying API which is currently not available without some exploration.

How?

  • We should test the serialization of option types using some unit testing framework.
  • We should ensure coverage of the API with documentation in the form of a table or diagram.

Top Text maxWidth fill not working

This is not a problem with the core library itself but with the demo of the MemeGenerator.

The top text has a max width for the fill that should make the text less wide if the text is too long so that the whole sentence is displayed. This works for the bottom text but not the top text.
image

Solving the problem is not really high priority but it is still interesting and should be fixed at some point.

Doesn't work in Brave browser

Brave browser has some security "features" which may block this. But i didn't investigate..

When I access the demo page, this is shown in console:

Error with Permissions-Policy header: Unrecognized feature: 'interest-cohort'.

after clicking "Open file picker..." button it shows this:

Microsoft.JSInterop.JSException: Could not find 'window.showOpenFilePicker' ('showOpenFilePicker' was undefined).
blazor.webassembly.js:1 Error: Could not find 'window.showOpenFilePicker' ('showOpenFilePicker' was undefined).
blazor.webassembly.js:1     at https://kristofferstrube.github.io/Blazor.FileSystemAccess/_framework/blazor.webassembly.js:1:328
blazor.webassembly.js:1     at Array.forEach (<anonymous>)
blazor.webassembly.js:1     at a.findFunction (https://kristofferstrube.github.io/Blazor.FileSystemAccess/_framework/blazor.webassembly.js:1:296)
blazor.webassembly.js:1     at _ (https://kristofferstrube.github.io/Blazor.FileSystemAccess/_framework/blazor.webassembly.js:1:2437)
blazor.webassembly.js:1     at https://kristofferstrube.github.io/Blazor.FileSystemAccess/_framework/blazor.webassembly.js:1:3325
blazor.webassembly.js:1     at new Promise (<anonymous>)
blazor.webassembly.js:1     at Object.beginInvokeJSFromDotNet (https://kristofferstrube.github.io/Blazor.FileSystemAccess/_framework/blazor.webassembly.js:1:3306)
blazor.webassembly.js:1     at Object.Rt [as invokeJSFromDotNet] (https://kristofferstrube.github.io/Blazor.FileSystemAccess/_framework/blazor.webassembly.js:1:59738)
blazor.webassembly.js:1     at _mono_wasm_invoke_js_blazor (https://kristofferstrube.github.io/Blazor.FileSystemAccess/_framework/dotnet.6.0.2.0c4ewytdwm.js:1:194973)
blazor.webassembly.js:1     at wasm://wasm/00970812:wasm-function[219]:0x1a129
blazor.webassembly.js:1    at Microsoft.JSInterop.JSRuntime.<InvokeAsync>d__16`1[[Microsoft.JSInterop.IJSObjectReference, Microsoft.JSInterop, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]].MoveNext()
blazor.webassembly.js:1    at KristofferStrube.Blazor.FileSystemAccess.FileSystemAccessService.ShowOpenFilePickerAsync(OpenFilePickerOptions openFilePickerOptions)
blazor.webassembly.js:1    at KristofferStrube.Blazor.FileSystemAccess.WasmExample.Pages.Index.OpenFilePicker()

This file: https://kristofferstrube.github.io/Blazor.FileSystemAccess/_content/KristofferStrube.Blazor.FileSystemAccess/KristofferStrube.Blazor.FileSystemAccess.js is loaded.

Feature: Recently used directory

Hello,

Thanks for your great effort!

I'm working on something interesting with your project, but I'm having a problem right now.

I want to get the recently used path or save the Handle, but I can't find the corresponding API. Is there any way?

Thanks again for your dedication!

Question: Is it possible to get a directory handle without using the directory picker?

Hi:

I know the path to the directory that I need to open to look for a file. Is there anyway to get a directory handle without using the directory picker? For example: C:/Users/Public/AccountPictures/[SID].

If I know the path to a file, but the name will have a wildcard, would it be possible to open the file? All the files at the above path will have are names as [GUID]-Image[size], where the GUID would be the same for all the files in the directory. I need to get access to [GUID]-Image96.jpg and [GUID]-Image64.jpg.

The full file path would be: C:/Users/Public/AccountPictures/[SID]/[GUID]-Image[size].jpg,

This is the location where the avatar images used on the Windows Logon Screen, Outlook, Teams, etc are stored.

Thanks

-marc

Quick question

Is there a meaningful performance improvement moving up from version 2.1? Or is 3+ a refactoring or code optimization effort?

Bug fix for RemoveEntry

Need new file FileSystemRemoveEntryOptions.cs under Options:

using System.Text.Json.Serialization;

namespace KristofferStrube.Blazor.FileSystemAccess;

/// <summary>
/// <see href="https://wicg.github.io/file-system-access/#dictdef-filesystemremoveentryoptions">FileSystemRemoveEntryOptions browser specs</see>
/// </summary>
public class FileSystemRemoveEntryOptions
{
    [JsonPropertyName("create")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
    public bool Recursive { get; set; }
}

and FileSystemDirectoryHandle.cs need to update RemoveEntryAsync to the following

public async Task RemoveEntryAsync(string name, FileSystemRemoveEntryOptions? options = null)
{
    await JSReference.InvokeVoidAsync("removeEntry", name, options);
}

How to read file bytes?

Hello,

I've been trying to use your wrapper to read recursively files in a folder structure. I need to get all bytes from every file in an array, but I cannot imagine how to do it.

Is there anyone here that knows how to get all the content of a file in an array of bytes?

Thank you!

question: random access (seeking?)

Thanks for the great library by the way.
I have an issue where I'm trying to get a small amount of data from a very large file on disk (wasm application). Is it possible to seek inside the file without re-reading all the data from start?

Generic JSException on aborting open/save dialogs

When user aborts open/save dialog, showSaveFilePicker/showOpenFilePicker APIs throws AbortError which is unhandled by the Blazor.FileSystemAccess library.
The exception can be catched on the C# side only as generic JSException which has no mean to check what caused the error.
Please propagate AbortError to C# by using specialized exception or null return value.

CopyToAsync() can write too much

I am using the WritableStream like this:

await using var newFileHandle = await rootDirectory.GetFileHandleAsync(publicatie.FileName, new() { Create = true });
await using var newFile = await newFileHandle.CreateWritableAsync();                                                            
await memStream.CopyToAsync(newFile);      

and later I am reading that file back into a ZipArchive.
While for most files this worked Ok, for some of the larger ones it resulted in the Zip error End of Central Directory record could not be found.

Debugging revealed that the stored file's Length was too long. It was the Capacity of the original MemoryStream where it should have been the Length. So the workaround I found is to use TruncateAsync with a known-good value.

...
await memStream.CopyToAsync(newFile);                                        
await newFile.TruncateAsync((ulong) args.File.Size);

Feature: Support for Accessing the Origin Private File System

We do not support Accessing the Origin Private File System.
This should be a very similar implementation to that of ShowDirectoryPickerAsync, but the name should probably be something close to the original JS call which is navigator.storage.getDirectory.

Potential names for the Method could be:

  • GetOriginDirectory
  • GetPrivateOriginDirectory
  • GetStorageDirectory
  • GetNavigatorStorageDirectory

I'm open to other suggestions as well.

We of cause also need a new demo page that utilizes this feature.

Feature: Support asynchronous accessors for Blazor Server

Some might use this package in Blazor Server. In Blazor Server we can't use IJSInProcessObjectRefereces which we currently use to get properties like Name from a FileSystemHandle synchronously. It would be nice to have a sample project that uses Blazor Server and to set up the service structure so that you don't need to initialize an IJSInProcessObjectReferece if you don't use it.
A proposed name for the asynchronous counterpart i.e. the Name property would be GetNameAsync().

Example crashed with file size > 50kb

I cloned your repository and ran it locally. On the /ViewZipFile page, if I select a zip file with a size above 50 KB, it crashes at:

     var buffer = await file.ArrayBufferAsync(); // <<----------crash happen at this line.
     using var stream = new MemoryStream(buffer);
     using var archive = new ZipArchive(stream, ZipArchiveMode.Read, true);

with the exception:

blazor.server.js:1 [2023-11-20T04:37:04.932Z] Error: Connection disconnected with error 'Error: Server returned an error on close: Connection closed with an error.'.

However your app at https://kristofferstrube.github.io/Blazor.FileSystemAccess/ViewZipFile works fine with any file size.

Is there any size limitation we need to set?

Large files rejected by SignalR when using Blazor Server

Default setting for message size used by SignalR is 32768 and as such it is largest chunk of data possible to be transferred from JavaScript to Blazor Server app.
It seems that this library is transferring whole file content in one chunk and attempt to load larger files ends with exception InvalidDataException: The maximum message size of 32768B was exceeded.
This issue can be fixed by setting MaximumReceiveMessageSize option for SignalR, but it would be great if this library streams file content in chunks instead to enable opening files of unlimited size.

Feature: Serialize / Deserialize object to be able to store in indexedDB

Love this package, made my life a lot easier.

I am just missing one thing and thats the posibility to serialize / deserialize a filehandler to be stored in indexeddb.

I am able to serialize using the JSReference but am unable to deserialize it to a FileSystemHandler, would be a great feature.

Feature: Support non-text file reading

Hi @KristofferStrube,
I've recently had some issues reading non-text files into the browser.

Expect an API like this:

var handle = await directory.GetFileHandleAsync("sample.db");

var file = await handle.GetFileAsync();

var buffer = new byte[file.Size];

file.Read(buffer, 0, buffer.Length);

or like this:

var handle = await directory.GetFileHandleAsync("sample.db");

var file = await handle.GetFileAsync();

var reader = new FileReader(file);

var buffer = new byte[reader.Size];

reader.Read(buffer, 0, buffer.Length);

Thank you for your work!

Feature: `FileSystemWritableFileStream` should extend `WritableStream` from `Blazor.Streams`

The WebIDL specifications for FileSystemWritableFileStream define that it inherits from the WritableStream interface that has been wrapped in the Blazor.Streams project. We should reflect this by having it extend that.

We currently have FileSystemWritableFileStream extend the .NET Stream class with some overrides. We should still override these methods, but much of the boilerplate for the initial inheritance can be removed, which is good.

Support URL.createObjectURL

https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL

Implementing this API permits the creation of browser addressable urls for File and Blob.

These examples provide some tangible use cases.

https://developer.mozilla.org/en-US/docs/Web/API/File_API/Using_files_from_web_applications#example_using_object_urls_to_display_pdf

A drag is the need to also implement URL.revokeObjectURL which deallocates a url resource to refer to the object.
https://developer.mozilla.org/en-US/docs/Web/API/URL/revokeObjectURL

Feature: Drag and Drop

I have looked at adding support for the Drag and Drop part of the API which is defined like this in the Web IDL specs:

partial interface DataTransferItem {
    Promise<FileSystemHandle?> getAsFileSystemHandle();
};

This means that it is an extension on the existing WebIDL definition of the DataTransferItem.

Blazor has a matching class for the DataTransferItem which can be seen here in the docs

The problem with that class is that it is indeed handled as a POCO when parsed to JS through JSInterop. This means that we will only get the two properties that exist on the object not a posibility to call JS function on the object itself from i.e. the previously described extension.

This has been tested on a feature branch of this project https://github.com/KristofferStrube/Blazor.FileSystemAccess/tree/feature/DragAndDrop

Which currently gives an error when we try to invoke getAsFileSystemHandle() or any other existing DataTransferItem methods.

This is the expected behaviour. What could be nice would be if the DataTransferItem from C# would (or could) be interpreted as the JS reference so that people can call the native browser methods on the object.

It is planned to open an issue on the aspnetcore repository once I have collected more information about how the DataTransferItem is currently handled in the project and when I have found some approach that would make this possible without bloating the existing object.

Feature: Local file access fully available only from code behind

@KristofferStrube Is it possible to select on one page let's say a whole main-directory path, and from a other page set additional folders in that main-directory and read/write/overwrite files into that directory automatically? So with automatically I mean by code, let's say by a event from example a http logic, but important not from a button click event or similar.

So is it possible to use it somehow similar like when you make a local app for example a console app in c# and using some file access like below, but in Blazor WASM?

// write code from backend code when a eventlistener has become a event (conceptual something like this)
string localPath = @"C:\BlazorFolder\Log"; //in Blazor this master-path could also be selected when blazor starts, on a separate page

if( !Directory.Exists( localPath ))
Directory.CreateDirectory( localPath );
if( !File.Exists( localPath + "log.txt")
File.WriteAllText(localPath + "log.txt", string.empty);
string readText = File.ReadAllText(localPath + "log.txt");
string newText = readText + "LOG-Message : stream service error detected " + DateTime.Now.ToString("MM/dd/yyyy hh:mm tt");
File.WriteAllText(localPath + "log.txt", newText );

If this is possible, could you integrate such a example in your project to demonstrate how this would work in Blazor WASM ?

Thank you!

Retrieving file path

Hi,

Is it possible to get the full filepath of the selected file using this code?
I can't seem to see how to do that from the documentation.

Processing a file "uploaded" via <InputFile>

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
  

}

Browser APIs code generation

First of all, well done on your talk on dotNET, very clear explanations!

Apologies for the way I am reaching out to you, I couldn't find your email. Have you thought about auto generating apis wrappers from specs from wicg?

I would like to offer my help if that's something you would contemplate doing.

Module import with _content path does not work for Blazor with Chrome Extension

I am building a Chrome extension and due to their file system, any folder starting with _ is prohibited. I am using Blazor.BrowserExtension to build Blazor project and there is similar issue mingyaulee/Blazor.BrowserExtension#43, and the _content folder is renamed to content instead.

My suggestion is to add support for custom module path so we can put our own path. The file in question is:

internal static async Task<IJSObjectReference> GetHelperAsync(this IJSRuntime jSRuntime)

Feature: Support Blazor Server

Hello,

I'm getting a Error while trying to open a Directory Dialog.

protected async Task SetExcludeFoler()
    {
        try
        {
            var options = new DirectoryPickerOptionsStartInWellKnownDirectory() { StartIn = WellKnownDirectory.Pictures };
            directoryHandle = await FileSystemAccessService.ShowDirectoryPickerAsync(options);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex);
        }
        finally
        {
            if (directoryHandle != null)
            {
                string folderName = directoryHandle.Name;
            }
        }
    }

Exception : Microsoft.JSInterop.JSException: 'An exception occurred executing JS interop: Deserialization of interface types is not supported. Type 'Microsoft.JSInterop.IJSInProcessObjectReference'. Path: $ | LineNumber: 0 | BytePositionInLine: 1.. See InnerException for more details.'

Code readability suggestion

Since I expect this library will be very important, I hope you don't mind if I'm a bit pedantic. I see an inconsistent pattern so I wanted to highlight, for example, with FileSystemCreateWritableOptions(bool) and it's imposed constructor, when using this function in code, you end up with

new FileSystemCreateWritableOptions(false)

but the false is non-descriptive, whereas an example of a non-constructor variation looks like

new FileSystemGetFileOptions() { Create = true }

very self-explanatory.

If constructors is your preference, maybe use enums instead of base types?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.