Input

Every Pnyx works on an input, typically from Stream, but can be any thing that implements IProcessor. All input done for a Pnyx is done during the process state (see State Machine for details). Some of the details for reading input are documented below.

Encoding

Pnyx uses the file's "Byte Order Mark" (BOM) to determine its encoding. If file does not contain BOM, then encoding defaults to Settings.defaultEncoding. Use the Settings, either globally or for specific Pnyx to control how files are decoded. The following example shows reading UTF-8 files.

Specific Encoding
await using (Pnyx p = new Pnyx())
{
    p.setSettings(defaultEncoding: Encoding.UTF8, detectEncodingFromByteOrderMarks: false);
    p.read("myfile.txt");
    p.writeStdout();
}                        
// Reads a UTF-8 file regardless of BOM (or lack thereof)

Newlines

When reading from a Stream, newlines can be either in Unix, Mac or Windows format, or even mixed together in the same file. Stream parsing uses the first newline character(s) to write to output, in an attempt to maintain the source's original newlines. Finally, parsing keeps track of whether the file is terminated by a newline or not. If so, then the output will also be terminated by a newline.
Newline Parsing
const String input = "1\n2\r\n3\r4";
await using (Pnyx p = new Pnyx())
{
    p.readString(input);
    p.writeStdout();
}     
// outputs: 1\n2\n3\n4

Custom Sources

To build a custom source, implement IProcessor and at least one of ILinePart, IRowPart, IObjectPart or INameValuePairPart. The process method should read or generate all data in one call. Data is pushed to the next IProcessor as it becomes available. On every loop, StreamInformation.active should be checked, to determine if process should terminate prior to exhausting input. Finally, any clean up of resources should be handled by implementing IAsyncDisposable. The following example illustrates these points with a custom source to generate Row data.
rowPart
public class CustomRowSource : IProcessor, IRowPart
{
    private readonly StreamInformation streamInformation;
    private int countDown;
    private IRowProcessor? processor;

    public CustomRowSource(StreamInformation streamInformation, int countDown)
    {
        this.streamInformation = streamInformation;
        this.countDown = countDown;
    }

    public async Task process()
    {
        DateTime date = new DateTime(2013, 4, 2);
        while (countDown >= 0 && streamInformation.active)
        {
            String columnA = countDown.ToString();
            String columnB = date.ToString(DateUtil.FORMAT_MDYYYY);
            List<String?> row = new List<String?> { columnA, columnB };
                
            await processor!.processRow(row);
                
            countDown--;
            date = date.AddDays(-7);
        }
            
        await processor!.endOfFile();  // flushes buffering and output 
    }

    public void setNextRowProcessor(IRowProcessor next)
    {
        processor = next;
    }
}

await using (Pnyx p = new Pnyx())
{
    p.readRow(new CustomRowSource(p.streamInformation, 40), new CsvRowConverter());
    p.head(3);
    p.writeStdout();
}                        
// outputs:
// 40,4/2/2013
// 39,3/26/2013
// 38,3/19/2013

Next

Suggested next steps:
  • Line, learn more about Line operations
  • Row, learn more about Row operations
  • Object, examples of Object operations
  • NameValuePair, examples of Name-Value Pair operations
  • Output, learn more about Output operations
  • Settings, learn more about settings