This class reads CSV formatted data from an input stream. It can read individual fields in a row, a full row or the whole file. Data can only be read once - so if the first field in a row is read, it won't be part of the row if that is read next. The term Row is used rather than line because quoted fields can include line breaks (real, not escaped) so that one row may be spread across multiple lines.
        public override void Load( string filename )
        {
            Debug.WriteLine( "Loading " + filename );
            CsvDocument csvDoc = new CsvDocument(filename);

            FileStream fileStream = null;
            try
            {
                //Console.WriteLine("Loading " + filename);
                fileStream = File.OpenRead( filename );
                CsvReader reader = new CsvReader( fileStream );

                string[][] records = reader.ReadAll();
                csvDoc.Rows = records;
            }
            finally
            {
                if( fileStream != null )
                {
                    fileStream.Close();
                }
            }

            document = csvDoc;
            base.Load( filename );
        }
        public void TestCsvDifferentNumberFieldsFile()
        {
            FileStream fileStream = null;
            const string filename = DifferentNumberFieldsTestFile;

            try
            {
                Console.WriteLine("Loading " + filename);
                fileStream = File.OpenRead(filename);
                CsvReader reader = new CsvReader(fileStream);

                string[][] records = reader.ReadAll();
                int line = 0;

                foreach (string[] record in records)
                {
                    Console.WriteLine(++line + ":" + ToString(record));
                }

                Assert.IsTrue(records.Length == 4, "Wrong number of records in " + filename);

                int index = 0;
                Assert.IsTrue(records[index].Length == 3, "Wrong number of items on record " + (index + 1));
                Assert.IsTrue(CompareStringArray(new string[] { "A", "B", "C" }, records[index]), "contents of record " + (index + 1));

                index++;
                Assert.IsTrue(records[index].Length == 4, "Wrong number of items on record " + (index + 1));
                Assert.IsTrue(CompareStringArray(new string[] { "a", "b", "c", "d" }, records[index]), "contents of record " + (index + 1));

                index++;
                Assert.IsTrue(records[index].Length == 2, "Wrong number of items on record " + (index + 1));
                Assert.IsTrue(CompareStringArray(new string[] { "9", "8" }, records[index]), "contents of record " + (index + 1));

                index++;
                Assert.IsTrue(records[index].Length == 5, "Wrong number of items on record " + (index + 1));
                Assert.IsTrue(CompareStringArray(new string[] { "1", "2", "3", "4", "5" }, records[index]), "contents of record " + (index + 1));
            }
            catch (Exception ex)
            {
                Assert.Fail(ex.Message);
            }
            finally
            {
                if (fileStream != null)
                {
                    fileStream.Close();
                }
            }
        }
        public void TestCsvWriter()
        {
            const string filename = CsvTestDataDirectory + "mixed.csv";
            FileStream inStream = null;
            FileStream outStream = null;
            try
            {
                Console.WriteLine( "Loading " + filename );
                inStream = File.OpenRead( filename );
                CsvReader reader = new CsvReader( inStream );
                string [][] records = reader.ReadAll();

                const string outName = CsvOutputDirectory + "test-writer.csv";
                outStream = File.OpenWrite( outName );
                outStream.SetLength( 0L );

                CsvWriter writer = new CsvWriter( outStream );
                //writer.QuoteLimit = -1;

                writer.WriteAll( records );
                outStream.Flush();
            }
            catch (Exception ex)
            {
                Assert.Fail( ex.Message );
            }
            finally
            {
                if( inStream != null )
                {
                    inStream.Close();
                }

                if( outStream != null )
                {
                    outStream.Close();
                }
            }
        }
        public void TestWriteAlternateSeparator()
        {
            string filename = Path.Combine(CsvOutputDirectory, "test-write-alternate-separator.csv");
            string[] record = new string[] { "AA,AA original separator", "BB|BB new separator", "CCCC" };

            Stream stream = null;
            try
            {
                Console.WriteLine("Creating empty " + filename);
                //	Create the temp file (or overwrite if already there).
                stream = File.Open(filename, FileMode.OpenOrCreate, FileAccess.ReadWrite);
                stream.SetLength(0);
                stream.Close();

                //	Check it's empty.
                FileInfo info = new FileInfo(filename);
                Assert.AreEqual(0, info.Length, "File length not zero.");

                //  Open for append
                Console.WriteLine("Writing " + filename);
                stream = File.OpenWrite(filename);

                //	Append a record.
                CsvWriter writer = new CsvWriter(stream);
                writer.Separator = '|';
                writer.WriteRecord(record);
                stream.Flush();
                stream.Close();

                Console.WriteLine("Loading " + filename);
                stream = File.OpenRead(filename);
                CsvReader reader = new CsvReader(stream);
                reader.Separator = '|';
                string[][] records = reader.ReadAll();

                Assert.AreEqual(1, records.Length, "Should only be one record.");

                Console.WriteLine("Read :" + ToString(records[0]));

                Assert.AreEqual(record.Length, records[0].Length, "Should be " + record.Length + " fields in record.");

                for (int fieldNo = 0; fieldNo < record.Length; fieldNo++)
                {
                    Assert.AreEqual(record[fieldNo], records[0][fieldNo], "Field " + record.Length + " Should be " + record[fieldNo]);
                }
            }
            catch (Exception ex)
            {
                Assert.Fail(ex.Message);
            }
            finally
            {
                if (stream != null)
                {
                    stream.Close();
                }
            }
        }
        public void TestWriteAlternateQuote()
        {
            string filename = Path.Combine(CsvOutputDirectory, "test-write-alternate-quote.csv");
            string[][] recordsOut =
            {
                new string[] { "aaa", "bb*b", "ccc" },
                new string[] { "", "new" + Environment.NewLine + "line", "quoted" },
                new string[] { "with", "\"other\"", "quo\"\"te" }
            };

            Stream stream = null;
            try
            {
                Console.WriteLine("Creating " + filename);
                //	Create the temp file (or overwrite if already there).
                stream = File.Open(filename, FileMode.OpenOrCreate, FileAccess.ReadWrite);
                stream.SetLength(0);

                //	Append the data.
                CsvWriter writer = new CsvWriter(stream);
                writer.Quote = '*';
                writer.QuoteLimit = -1;
                writer.WriteAll(recordsOut);
                stream.Flush();
                stream.Close();

                Console.WriteLine("Loading " + filename);
                stream = File.OpenRead(filename);
                CsvReader reader = new CsvReader(stream);
                reader.Quote = '*';
                string[][] recordsIn = reader.ReadAll();

                int line = 0;
                foreach (string[] record in recordsIn)
                {
                    Console.WriteLine(++line + ":" + ToString(record));
                }

                Assert.IsTrue(recordsIn.Length == 3, "Wrong number of records in " + filename);

                int index = 0;
                Assert.IsTrue(recordsIn[index].Length == 3, "Wrong number of items on record " + (index + 1));
                Assert.IsTrue(CompareStringArray(recordsOut[index], recordsIn[index]), "contents of record " + (index + 1));

                index++;
                Assert.IsTrue(recordsIn[index].Length == 3, "Wrong number of items on record " + (index + 1));
                Assert.IsTrue(CompareStringArray(recordsOut[index], recordsIn[index]), "contents of record " + (index + 1));

                index++;
                Assert.IsTrue(recordsIn[index].Length == 3, "Wrong number of items on record " + (index + 1));
                Assert.IsTrue(CompareStringArray(recordsOut[index], recordsIn[index]), "contents of record " + (index + 1));
            }
            catch (Exception ex)
            {
                Assert.Fail(ex.Message);
            }
            finally
            {
                if (stream != null)
                {
                    stream.Close();
                }
            }
        }
        public void TestCsvThreeBlankLinesFile()
        {
            FileStream fileStream = null;
            string filename = ThreeBlankLinesTestFile;

            try
            {
                Console.WriteLine("Loading " + filename);
                fileStream = File.OpenRead(filename);
                CsvReader reader = new CsvReader(fileStream);

                string[][] records = reader.ReadAll();
                int line = 0;

                foreach (string[] record in records)
                {
                    Console.WriteLine(++line + ":" + ToString(record));
                }

                Assert.IsTrue(records.Length == 3, "Wrong number of records in " + filename);
                Assert.IsTrue(records[0].Length == 1, "Wrong number of items on the first record");
                Assert.IsTrue(records[0][0].Length == 0, "Should be an empty string");
                Assert.IsTrue(records[1].Length == 1, "Wrong number of items on the second record");
                Assert.IsTrue(records[1][0].Length == 0, "Should be an empty string");
                Assert.IsTrue(records[2].Length == 1, "Wrong number of items on the third record");
                Assert.IsTrue(records[2][0].Length == 0, "Should be an empty string");
            }
            catch (Exception ex)
            {
                Assert.Fail(ex.Message);
            }
            finally
            {
                if (fileStream != null)
                {
                    fileStream.Close();
                }
            }
        }
        public void TestCsvSpacesFile()
        {
            FileStream fileStream = null;
            string filename = SpacesTestFile;

            try
            {
                Console.WriteLine("Loading " + filename);
                fileStream = File.OpenRead(filename);
                CsvReader reader = new CsvReader(fileStream);

                string[][] records = reader.ReadAll();
                int line = 0;

                foreach (string[] record in records)
                {
                    Console.WriteLine(++line + ":" + ToString(record));
                }

                Assert.IsTrue(records.Length == 1, "Wrong number of records in " + filename);
                Assert.IsTrue(CompareStringArray(new string[] { "trailing ", " leading", " both " }, records[0]), "the first record");
            }
            catch (Exception ex)
            {
                Assert.Fail(ex.Message);
            }
            finally
            {
                if (fileStream != null)
                {
                    fileStream.Close();
                }
            }
        }
        public void TestCsvReadFieldAndRecord()
        {
            Console.WriteLine("Loading " + MixedTestFile);
            FileStream fileStream = null;
            try
            {
                fileStream = File.OpenRead(MixedTestFile);
                CsvReader reader = new CsvReader(fileStream);

                Console.WriteLine("Line 1, Field 1: \"" + reader.ReadField() + "\"");

                Console.WriteLine("Rest of Line 1: \"" + ToString(reader.ReadRecord()) + "\"");

                Console.WriteLine("Rest of File: ");

                string[][] records = reader.ReadAll();
                int line = 0;
                foreach (string[] record in records)
                {
                    Console.WriteLine(++line + ":" + ToString(record));
                }
            }
            catch (Exception ex)
            {
                Assert.Fail(ex.Message);
            }
            finally
            {
                if (fileStream != null)
                {
                    fileStream.Close();
                }
            }
        }
        public void TestCsvQuotedLineBreaksFile()
        {
            FileStream fileStream = null;
            string filename = QuotedLineBreaksTestFile;

            try
            {
                Console.WriteLine("Loading " + filename);
                fileStream = File.OpenRead(filename);
                CsvReader reader = new CsvReader(fileStream);

                string[][] records = reader.ReadAll();
                int line = 0;

                foreach (string[] record in records)
                {
                    Console.WriteLine(++line + ":" + ToString(record));
                }

                Assert.IsTrue(records.Length == 1, "Wrong number of records in " + filename);

                int index = 0;

                Assert.IsTrue(records[index].Length == 3, "Wrong number of items on record " + (index + 1));
                Assert.IsTrue(CompareStringArray(new string[]
                {
                    "A longer entry with some new" + Environment.NewLine +
                    "lines" + Environment.NewLine +
                    "even" + Environment.NewLine +
                    "" + Environment.NewLine +
                    "a blank one.",
                    "",
                    "Quotes" + Environment.NewLine +
                    "\" and " + Environment.NewLine +
                    "\"\t\"TABS " + Environment.NewLine +
                    "AND,commas" }, records[index]), "contents of record " + (index + 1));
            }
            catch (Exception ex)
            {
                Assert.Fail(ex.Message);
            }
            finally
            {
                if (fileStream != null)
                {
                    fileStream.Close();
                }
            }
        }
        public void TestCsvQuotedFile()
        {
            FileStream fileStream = null;
            string filename = QuotedTestFile;

            try
            {
                Console.WriteLine("Loading " + filename);
                fileStream = File.OpenRead(filename);
                CsvReader reader = new CsvReader(fileStream);

                string[][] records = reader.ReadAll();
                int line = 0;

                foreach (string[] record in records)
                {
                    Console.WriteLine(++line + ":" + ToString(record));
                }

                Assert.IsTrue(records.Length == 2, "Wrong number of records in " + filename);

                int index = 0;
                Assert.IsTrue(records[index].Length == 2, "Wrong number of items on record " + (index + 1));
                Assert.IsTrue(CompareStringArray(new string[] { "2lines, 2 fields, With, commas", "With \"Quotes\"" }, records[index]), "contents of record " + (index + 1));

                index++;
                Assert.IsTrue(records[index].Length == 2, "Wrong number of items on record " + (index + 1));
                Assert.IsTrue(CompareStringArray(new string[] { "With	Tabs", "Quotes\" and \"	\"TABS AND,commas" }, records[index]), "contents of record " + (index + 1));
            }
            catch (Exception ex)
            {
                Assert.Fail(ex.Message);
            }
            finally
            {
                if (fileStream != null)
                {
                    fileStream.Close();
                }
            }
        }
        public void TestCsvFieldNamesFile()
        {
            FileStream fileStream = null;
            string filename = FieldNamesTestFile;

            try
            {
                Console.WriteLine("Loading " + filename);
                fileStream = File.OpenRead(filename);
                CsvReader reader = new CsvReader(fileStream);

                string[][] records = reader.ReadAll();
                int line = 0;

                foreach (string[] record in records)
                {
                    Console.WriteLine(++line + ":" + ToString(record));
                }

                Assert.IsTrue(records.Length == 3, "Wrong number of records in " + filename);
                Assert.IsTrue(CompareStringArray(new string[] { "Title", "Forename", "Last Name", "Age" }, records[0]), "the first record");
                Assert.IsTrue(CompareStringArray(new string[] { "Mr.", "John", "Smith", "21" }, records[1]), "the second record");
                Assert.IsTrue(CompareStringArray(new string[] { "Mrs.", "Jane", "Doe-Jones", "42" }, records[2]), "the third record");
            }
            catch (Exception ex)
            {
                Assert.Fail(ex.Message);
            }
            finally
            {
                if (fileStream != null)
                {
                    fileStream.Close();
                }
            }
        }
        public void TestCsvEmptyFile()
        {
            FileStream fileStream = null;
            string filename = EmptyTestFile;

            try
            {
                Console.WriteLine("Loading " + filename);
                fileStream = File.OpenRead(filename);
                CsvReader reader = new CsvReader(fileStream);

                string[][] records = reader.ReadAll();
                int line = 0;

                foreach (string[] record in records)
                {
                    Console.WriteLine(++line + ":" + ToString(record));
                }

                //TODO: Not sure here - should there be zero records or one empty record with an empty field?
                //Assert.IsTrue(records.Length == 0, "Should be no records in " + filename);
                Assert.IsTrue(records.Length == 1, "Wrong number of record in " + filename);
                Assert.IsTrue(records[0].Length == 1, "Wrong number of items on the first record");
                Assert.IsTrue(records[0][0].Length == 0, "Should be an empty string");
            }
            catch (Exception ex)
            {
                Assert.Fail(ex.Message);
            }
            finally
            {
                if (fileStream != null)
                {
                    fileStream.Close();
                }
            }
        }
        public void TestCsvEmptyFieldFile()
        {
            FileStream fileStream = null;
            string filename = EmptyFieldTestFile;

            try
            {
                Console.WriteLine("Loading " + filename);
                fileStream = File.OpenRead(filename);
                CsvReader reader = new CsvReader(fileStream);

                string[][] records = reader.ReadAll();
                int line = 0;

                foreach (string[] record in records)
                {
                    Console.WriteLine(++line + ":" + ToString(record));
                }

                Assert.IsTrue(records.Length == 4, "Wrong number of records in " + filename);

                int index = 0;
                Assert.IsTrue(records[index].Length == 3, "Wrong number of items on record " + (index + 1));
                Assert.IsTrue(CompareStringArray(new string[] { "aaa", "bbb", "ccc" }, records[index]), "contents of record " + (index + 1));

                index++;
                Assert.IsTrue(records[index].Length == 3, "Wrong number of items on record " + (index + 1));
                Assert.IsTrue(CompareStringArray(new string[] { "", "eee", "fff" }, records[index]), "contents of record " + (index + 1));

                index++;
                Assert.IsTrue(records[index].Length == 3, "Wrong number of items on record " + (index + 1));
                Assert.IsTrue(CompareStringArray(new string[] { "ggg", "", "jjj" }, records[index]), "contents of record " + (index + 1));

                index++;
                Assert.IsTrue(records[index].Length == 3, "Wrong number of items on record " + (index + 1));
                Assert.IsTrue(CompareStringArray(new string[] { "xxx", "yyy", "" }, records[index]), "contents of record " + (index + 1));
            }
            catch (Exception ex)
            {
                Assert.Fail(ex.Message);
            }
            finally
            {
                if (fileStream != null)
                {
                    fileStream.Close();
                }
            }
        }
        public void TestCsvDifferentQuotesFile()
        {
            FileStream fileStream = null;
            string filename = DifferentQuotesFile;

            try
            {
                Console.WriteLine("Loading " + filename);
                fileStream = File.OpenRead(filename);
                CsvReader reader = new CsvReader(fileStream);

                reader.Quote = '*';
                string[][] records = reader.ReadAll();
                int line = 0;

                foreach (string[] record in records)
                {
                    Console.WriteLine(++line + ":" + ToString(record));
                }

                Assert.IsTrue(records.Length == 3, "Wrong number of records in " + filename);

                int index = 0;
                Assert.IsTrue(records[index].Length == 3, "Wrong number of items on record " + (index + 1));
                Assert.IsTrue(CompareStringArray(new string[] { "aaa", "bbb", "ccc" }, records[index]), "contents of record " + (index + 1));

                index++;
                Assert.IsTrue(records[index].Length == 3, "Wrong number of items on record " + (index + 1));
                Assert.IsTrue(CompareStringArray(new string[] { "", "new" + Environment.NewLine + "line", "quoted" }, records[index]), "contents of record " + (index + 1));

                index++;
                Assert.IsTrue(records[index].Length == 3, "Wrong number of items on record " + (index + 1));
                Assert.IsTrue(CompareStringArray(new string[] { "with", "\"other\"", "quo\"\"te" }, records[index]), "contents of record " + (index + 1));
            }
            catch (Exception ex)
            {
                Assert.Fail(ex.Message);
            }
            finally
            {
                if (fileStream != null)
                {
                    fileStream.Close();
                }
            }
        }