Last active
August 11, 2023 05:50
-
-
Save julenka/20ece5141e821cb6d0a9cb530d3dc96d to your computer and use it in GitHub Desktop.
Log data to CSV on HoloLens from a Unity project. Writes to Pictures folder instead of applicationDataPath so that files can be accessed from File Explorer (File Explorer -> HoloLens -> Pictures -> YourFolder). Doesn't require using Device portal.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Text; | |
using System.Threading.Tasks; | |
using UnityEngine; | |
#if WINDOWS_UWP | |
using Windows.Storage; | |
#endif | |
namespace holoutils | |
{ | |
/// <summary> | |
/// Component that Logs data to a CSV. | |
/// Assumes header is fixed. | |
/// Copy and paste this logger to create your own CSV logger. | |
/// CSV Logger breaks data up into settions (starts when application starts) which are folders | |
/// and instances which are files | |
/// A session starts when the application starts, it ends when the session ends. | |
/// | |
/// In Editor, writes to MyDocuments/SessionFolderRoot folder | |
/// On Device, saves data in the Pictures/SessionFolderRoot | |
/// | |
/// How to use: | |
/// Find the csvlogger | |
/// if it has not started a CSV, create one. | |
/// every frame, log stuff | |
/// Flush data regularly | |
/// | |
/// **Important: Requires the PicturesLibrary capability!** | |
/// </summary> | |
public class CSVLogger : MonoBehaviour | |
{ | |
#region Constants to modify | |
private const string DataSuffix = "data"; | |
private const string CSVHeader = "Timestamp,SessionID,RecordingID," + | |
"blah,blah,blah"; | |
private const string SessionFolderRoot = "CSVLogger"; | |
#endregion | |
#region private members | |
private string m_sessionPath; | |
private string m_filePath; | |
private string m_recordingId; | |
private string m_sessionId; | |
private StringBuilder m_csvData; | |
#endregion | |
#region public members | |
public string RecordingInstance => m_recordingId; | |
#endregion | |
// Use this for initialization | |
async void Start() | |
{ | |
await MakeNewSession(); | |
} | |
async Task MakeNewSession() | |
{ | |
m_sessionId = DateTime.Now.ToString("yyyyMMdd_HHmmss"); | |
string rootPath = ""; | |
#if WINDOWS_UWP | |
StorageFolder sessionParentFolder = await KnownFolders.PicturesLibrary | |
.CreateFolderAsync(SessionFolderRoot, | |
CreationCollisionOption.OpenIfExists); | |
rootPath = sessionParentFolder.Path; | |
#else | |
rootPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), SessionFolderRoot); | |
if (!Directory.Exists(rootPath)) Directory.CreateDirectory(rootPath); | |
#endif | |
m_sessionPath = Path.Combine(rootPath, m_sessionId); | |
Directory.CreateDirectory(m_sessionPath); | |
Debug.Log("CSVLogger logging data to " + m_sessionPath); | |
} | |
public void StartNewCSV() | |
{ | |
m_recordingId = DateTime.Now.ToString("yyyyMMdd_HHmmssfff"); | |
var filename = m_recordingId + "-" + DataSuffix + ".csv"; | |
m_filePath = Path.Combine(m_sessionPath, filename); | |
if (m_csvData != null) | |
{ | |
EndCSV(); | |
} | |
m_csvData = new StringBuilder(); | |
m_csvData.AppendLine(CSVHeader); | |
} | |
public void EndCSV() | |
{ | |
if (m_csvData == null) | |
{ | |
return; | |
} | |
using (var csvWriter = new StreamWriter(m_filePath, true)) | |
{ | |
csvWriter.Write(m_csvData.ToString()); | |
} | |
m_recordingId = null; | |
m_csvData = null; | |
} | |
public void OnDestroy() | |
{ | |
EndCSV(); | |
} | |
public void AddRow(List<String> rowData) | |
{ | |
AddRow(string.Join(",", rowData.ToArray())); | |
} | |
public void AddRow(string row) | |
{ | |
m_csvData.AppendLine(row); | |
} | |
/// <summary> | |
/// Writes all current data to current file | |
/// </summary> | |
public void FlushData() | |
{ | |
using (var csvWriter = new StreamWriter(m_filePath, true)) | |
{ | |
csvWriter.Write(m_csvData.ToString()); | |
} | |
m_csvData.Clear(); | |
} | |
/// <summary> | |
/// Returns a row populated with common start data like | |
/// recording id, session id, timestamp | |
/// </summary> | |
/// <returns></returns> | |
public List<String> RowWithStartData() | |
{ | |
List<String> rowData = new List<String>(); | |
rowData.Add(Time.timeSinceLevelLoad.ToString("##.000")); | |
rowData.Add(m_recordingId); | |
rowData.Add(m_recordingId); | |
return rowData; | |
} | |
} | |
} |
I think StartNewCSV(
) here is to create a CSV file with the unity editor. If you want to create a CSV file in the Hololens, you need to use the Windows.Storage
for UWP. Referring to https://learn.microsoft.com/en-us/windows/uwp/files/quickstart-reading-and-writing-files
For more file-accessing codes for UWP, I found this helpful:
https://github.com/Microsoft/Windows-universal-samples/tree/main/Samples/FileAccess
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thank you for the code. I have just one question, where should I call the
StartNewCSV()
andFlushData()
functions? The code that you provided has aasync void Start()
function which does not allow me to have my basicvoid start(){}
. I'm guessing I should use theFlushData()
in theUpdate()
function. right?