HoloLens File Transfer

Tranferring file to and from HoloLens seems non-trivial. It is written in HoloLens official document about saving and sending your files:

Unlike Windows on a PC or phone, HoloLens does not have a File Explorer application.

Getting access to non-media file is not an easy task. Tools like file picker and OneDrive are definitly over-kill for this task.

Goal

The goals here are two-folded:

File Explorer on Device Portal

File explorer on the device portal is used as a bridge. But the directories listed on the device portal is not complete. Therefore, we need to find out the accessible directory for both HoloLens application and user on PC.

Luckily I found such a location. The folder LocalAppData\SOMEAPP\RoamingState on the device portal is mapped to ApplicationData.Current.RoamingFolder.Path in the application at runtime.

Device Portal Screenshot

So, when the file is written to this path in UWP application, it will appear here, and you can download it by simply clicking on the download button. On the other hand, if you upload a file to this path, it can be read out by UWP application.

Scripts

The scripts are adapted from HoloToolkit.

Reading

The sample script for reading file is:

public void ReadString() {
  string s;
#if !UNITY_EDITOR && UNITY_METRO
  try {
    using (Stream stream = OpenFileForRead(ApplicationData.Current.RoamingFolder.Path, "filename.txt")) {
      byte[] data = new byte[stream.Length];
      stream.Read(data, 0, data.Length);
      s = Encoding.ASCII.GetString(data);
    }
  }
  catch (Exception e) {
    Debug.Log(e);
  }
#endif
  return s;
}

private static Stream OpenFileForRead(string folderName, string fileName) {
  Stream stream = null;
#if !UNITY_EDITOR && UNITY_METRO
  Task task = new Task(
    async () => {
      StorageFolder folder = await StorageFolder.GetFolderFromPathAsync(folderName);
      StorageFile file = await folder.GetFileAsync(fileName);
      stream = await file.OpenStreamForReadAsync();
    });
  task.Start();
  task.Wait();
#endif
  return stream;
}

Writing

The sample script for writing file is:

public void WriteString(string s) {
#if !UNITY_EDITOR && UNITY_METRO
  using (Stream stream = OpenFileForWrite(ApplicationData.Current.RoamingFolder.Path, "filename.txt")) {
    byte[] data = Encoding.ASCII.GetBytes(s);
    stream.Write(data, 0, data.Length);
    stream.Flush();
  }
#endif
}


private static Stream OpenFileForWrite(string folderName, string fileName) {
  Stream stream = null;
#if !UNITY_EDITOR && UNITY_METRO
  Task task = new Task(
    async () => {
      StorageFolder folder = await StorageFolder.GetFolderFromPathAsync(folderName);
      StorageFile file = await folder.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting);
      stream = await file.OpenStreamForWriteAsync();
    });
  task.Start();
  task.Wait();
#endif
  return stream;
}

In the above sample code, the file that is queried must exist. In the case when you want to list existing files in a given folder, it is as simple as:

StorageFolder folder = await StorageFolder.GetFolderFromPathAsync(folderName);
foreach (StorageFile f in allFiles) {
  Debug.Log(TAG + ": found file " + f.Name + ", " + f.DateCreated);
}

The above code snippets are tested with the following configurations:

Further Reading

Apart from the RoamingState folder on HoloLens Device Portal, some other folders are accessible as well, for example, TempState and LocalState etc. More information can be found on UWP API page of Windows.Storage.ApplicationData.

Thanks for reading!