Skip to main content

File Inputs - Advanced

When using file inputs and outputs on ArupCompute it is generally recommended to use the ComputeFile class. However, there are occasions where it may be useful to write your own class that can be treated as a file input. ArupCompute supports using any class that implements the IBaseComputeFile interface as a file input or output. This interface contains all of the methods required for ArupCompute to handle the file input or output.

The IBaseComputeFile interface

The base interface that all ArupCompute file inputs/outputs must follow.

tip

Any class that is being used as an ArupCompute file input must also have an empty constructor.

Methods

NameDescription
AddData(byte[])Adds the data to the instance. Will be called by Compute when putting the data into the object before calling the calculation
SetName(string)Sets the name of the file that this object represents. When being called by Compute this method will be used to pass in the name that the user gave to the file that was inputted
GetStream()Returns the file in a Stream format
GetFileName()Returns a string representing the name of the file

Example

We can rewrite the "Single file input" calculation from the previous page and create our own class for specifically handling text file inputs to show how to use the IBaseComputeFile interface.

First we must create a new class, ExampleTextFile. This class will implement IBaseComputeFile interface and also add some new methods:

MethodDescription
AddLine(string)Add a line to the text file with "New Line: " prepended to the line
AddLines(string)Splits the input string by "," and then adds each of the items as a new line
GetLines()Get the lines in the text file
CountText()Gets the count of how many words are in the text file
using Arup.Compute.DotNetSdk.Attributes;
using Arup.Compute.DotNetSdk;
using Arup.Compute.DotNetSdk.FileIO.Interfaces;

public class ExampleTextFile : IBaseComputeFile
{
// this will store our file name
private string Name = string.Empty;

// this will store the lines in our text file
private readonly List<string> Lines = [];

// An IBaseComputeFile class must include an empty constructor
public ExampleTextFile() { }

/// <summary>
/// Splits the input string by "," and then adds each of the items as a new line
/// </summary>
/// <param name="lines">The comma separated string of lines to add</param>
public void AddLines(string lines)
{
foreach (string line in lines.Split(","))
{
AddLine(line);
}
}

/// <summary>
/// Add a line to the text file with "New Line: " prepended to the line
/// </summary>
/// <param name="line">The new line to add</param>
public void AddLine(string line)
{
Lines.Add($"New Line: {line}");
}

/// <summary>
/// Get the lines in the text file
/// </summary>
/// <returns></returns>
public List<string> GetLines()
{
return Lines;
}

/// <summary>
/// Gets the count of how many words are in the text file
/// </summary>
/// <returns></returns>
public int CountText()
{
return Lines.Aggregate(0, (acc, curr) => acc + curr.Split(" ").Length);
}

/// <summary>
/// Add the text file data to the text file
/// </summary>
/// <param name="bytes">The byte array of the text file</param>
public void AddData(byte[] bytes)
{
// normally we would use `using` here. As we are returning the stream we will not do that here. ArupCompute will be responsible for closing the stream
MemoryStream memoryStream = new(bytes);
StreamReader streamReader = new(memoryStream);

string? line = streamReader.ReadLine();

while (line != null)
{
Lines.Add(line);
line = streamReader.ReadLine();
}

streamReader.Close();
}

/// <summary>
/// Get the name of the text file
/// </summary>
/// <returns></returns>
public string GetFileName()
{
return Name;
}

/// <summary>
/// Get the file in a Stream format
/// </summary>
/// <returns></returns>
public Stream GetStream()
{
using MemoryStream memoryStream = new();
using TextWriter textWriter = new StreamWriter(memoryStream);

foreach (string line in Lines)
{
textWriter.WriteLine(line);
}

textWriter.Flush();
memoryStream.Position = 0;
return memoryStream;
}

/// <summary>
/// Set the name of the text file
/// </summary>
/// <param name="name"></param>
public void SetName(string name)
{
Name = name;
}
}

We can then use these methods in our calculation. We've also added a couple of other abilities to our calculation. It now also takes in a comma-separated list of lines to add to the file, reports the total number of words in the file (after adding the new lines to the file), and returns the new file.

using Arup.Compute.DotNetSdk.Attributes;
using Arup.Compute.DotNetSdk;
using Arup.Compute.DotNetSdk.FileIO.Interfaces;

[Calculation(
"Complex Single file input",
"The same as the Single File Input calculation, but using a custom class that implements the IBaseComputeFile interface",
"[email protected]",
Arup.Compute.DotNetSdk.Enums.LevelOfReview.Complete
)]
[Output("Lines", "The lines in the file", "", "")]
[Output("Name", "The file name", "", "")]
[Output("Count", "The total number of words in the file", "", "")]
[FileOutput("File", "The inputted file with the new lines", "", ".txt")]
public static ArupComputeResult ComplexSingleFileInput(
[FileInput("file input", "The file to input", "", new string[] { ".txt" }, null)]
ExampleTextFile file, // we accept the our text file class as the input
[Input("Add lines", "The lines to add to the file", "", "")] string lines
)
{
file.AddLines(lines); // add the new lines to the file
ArupComputeResult result = new()
{
ArupComputeResultItems = new()
{
new ArupComputeResultItem()
{
Description = "The lines in the file",
Symbol = "Lines",
Value = file.GetLines(), // read the new file
},
new ArupComputeResultItem()
{
Description = "The file name",
Symbol = "Name",
Value = file.GetFileName(), // get the file's name
},
new ArupComputeResultItem()
{
Description = "The total number of words in the file",
Symbol = "Count",
Value = file.CountText(), // count the words in the file
}
},
ArupComputeResultFileItems = new()
{
new ArupComputeResultFileItem()
{
FileName = file.GetFileName(), // returns the new file
FileData = file,
FileType = ".txt",
Description = "The lines to add to the file"
}
}
};

return result;
}