0

Anybody know how to get the following code to work? It's from: https://web.dev/file-system-access/#accessing-the-origin-private-file-system

const root = await navigator.storage.getDirectory();
const fileHandle = await root.getFileHandle('Untitled.txt', { create: true });

Ultimately I'm trying to gain access to the origin directory to store files created by my Blazor site. I prefer the origin directory because it doesn't require user interaction and is somewhat protected from the user.

Absolutely not to be confused with the key/pair 'localstorage' feature. I'm talking about genuine file access.

Sean
  • 2,531
  • 2
  • 17
  • 17
  • (Not posting as an answer because it may not be) - have you tried this library https://www.nuget.org/packages/KristofferStrube.Blazor.FileSystemAccess/ that provides a wrapper around the filesystem apis? – Mister Magoo Jun 26 '22 at 09:17
  • I did actually. It only supports FilePicker at this time. It doesn't seem to support origin directories – Sean Jun 26 '22 at 15:30

2 Answers2

1

Here is a basic sample of creating/writing/reading a simple text file.

<button @onclick=CreateFile>Create File</button>
<button @onclick=ReadFile>Read File</button>

@code
{
    [Inject] public IJSRuntime JS { get; set; } 

    async Task CreateFile()
    {
        var textToSave = await JS.InvokeAsync<string>("prompt","What is your name?");
        var jsDirHandle = await JS.InvokeAsync<IJSObjectReference>("navigator.storage.getDirectory");
        var jsFileHandle = await jsDirHandle.InvokeAsync<IJSObjectReference>("getFileHandle", "testfile", new { create = true });
        var jsFileStream = await jsFileHandle.InvokeAsync<IJSObjectReference>("createWritable");
        await jsFileStream.InvokeVoidAsync("write",$"You said your name is {textToSave} on {DateTime.Now}");
        await jsFileStream.InvokeVoidAsync("close");
        await JS.InvokeVoidAsync("alert", "File created");
    }
    async Task ReadFile()
    {
        var jsDirHandle = await JS.InvokeAsync<IJSObjectReference>("navigator.storage.getDirectory");
        var jsFileHandle = await jsDirHandle.InvokeAsync<IJSObjectReference>("getFileHandle", "testfile", new { create = true });
        var jsFile = await jsFileHandle.InvokeAsync<IJSObjectReference>("getFile");
        var fileText = await jsFile.InvokeAsync<string>("text");
        await JS.InvokeVoidAsync("alert", fileText);
    }
}

And a live sample: https://blazorrepl.telerik.com/mmkAQgPL05sNJ72w42

Mister Magoo
  • 7,452
  • 1
  • 20
  • 35
  • Thank you so much, this helped me to augment Kristoffer Strube's code base. My answer shows those updates – Sean Jun 26 '22 at 19:55
0

Thanks to Mister Magoo's answer, I was able to augment Kristoffer Strube's File System Access library. To his FileSystemAccessService.cs file, I added:

/// <summary>
/// Get handle to the exclusive origin directory for executing website
/// </summary>
/// <returns>handle to origin directory</returns>
public async Task<FileSystemDirectoryHandle> GetOriginDirectoryAsync()
{
    IJSInProcessObjectReference helper = await helperTask.Value;
    IJSObjectReference? jSFileHandle = await jSRuntime.InvokeAsync<IJSObjectReference>("navigator.storage.getDirectory");
    return new FileSystemDirectoryHandle(jSFileHandle, helper);
}

and then to demonstrate usage, I have the following:

//write/create
directoryHandle = await FileSystemAccessService.GetOriginDirectoryAsync();
var jsFileHandle = await directoryHandle.GetFileHandleAsync("testfile", new FileSystemGetFileOptions() { Create = true });
var jsFileStream = await jsFileHandle.CreateWritableAsync(new FileSystemCreateWritableOptions(false));
await jsFileStream.WriteAsync("hello");
await jsFileStream.CloseAsync();
// read
jsFileHandle = await directoryHandle.GetFileHandleAsync("testfile");
var jsFile = await jsFileHandle.GetFileAsync();
var fileText = await jsFile.TextAsync();
Sean
  • 2,531
  • 2
  • 17
  • 17