Esempio n. 1
0
        /// <summary>
        /// This method tries to process given line according to given set of parameters.
        /// </summary>
        /// <remarks>
        /// This method processes given line by splitting it into its pieces and then by
        /// trying to convert each element into its type-safe object expression.
        /// </remarks>
        /// <param name="line">
        /// The line to be processed.
        /// </param>
        /// <param name="separator">
        /// The separator to be used to split given line at.
        /// </param>
        /// <param name="exactly">
        /// An exception of type 'FormatException' is throw if this parameter is 'true' and
        /// converting one of the values has failed. Otherwise, each variable is set to a
        /// default value. Which default value will be used in such a failure case depends
        /// on current data type. For example, strings using &lt;null&gt; as default value,
        /// 'false' is used as default for Boolean types, and the corresponding max-value is
        /// used for all other types.
        /// </param>
        /// <param name="culture">
        /// The culture information to be used for data conversion.
        /// </param>
        /// <param name="mapping">
        /// The value mappings to be used for an extended data interpretation.
        /// </param>
        /// <param name="descriptors">
        /// A list of data type descriptor items that help interpreting data.
        /// </param>
        /// <returns>
        /// An instance of class of type <typeparamref name="TInstance"/>.
        /// </returns>
        /// <exception cref="InvalidOperationException">
        /// This exception is thrown for example if <typeparamref name="TInstance"/> does not
        /// provide a default constructor.
        /// </exception>
        /// <exception cref="FormatException">
        /// This exception is thrown for example if 'exactly' is set to 'true' and one of the
        /// data items could not be converted.
        /// </exception>
        /// <exception cref="NotSupportedException">
        /// This exception is thrown as soon as a class of type <typeparamref name="TInstance"/>
        /// wants to use an unsupported data type.
        /// </exception>
        private static TInstance ProcessLine(String line, Char separator, Boolean exactly, CultureInfo culture, CsvMappings mapping, List <ItemDescriptor> descriptors)
        {
            TInstance result = CsvImporter <TInstance> .Construct(); // throws

            List <String> values = ProcessHelper.SplitIntoCells(line, separator);

            for (Int32 index = 0; index < values.Count; index++)
            {
                // A simple break is possible because of column validation has been done already.
                if (index >= descriptors.Count)
                {
                    break;
                }

                String       value    = values[index];
                PropertyInfo property = descriptors[index].Origin;
                Type         type     = property.PropertyType;

                property.SetValue(result, TypeConverter.IntoObject(value, type, exactly, culture, mapping)); // throws
            }

            return(result);
        }
Esempio n. 2
0
        /// <summary>
        /// This method tries to write a particular line into given stream according
        /// to given parameter set.
        /// </summary>
        /// <remarks>
        /// This method may throw exceptions which must be handled by the caller.
        /// </remarks>
        /// <param name="writer">
        /// The stream writer to be used to push data.
        /// </param>
        /// <param name="separator">
        /// The delimiter to be used to separate each column.
        /// </param>
        /// <param name="textual">
        /// The flag indicating how strings have to be handled. If true then all string
        /// are enclosed in double-quotes. If false then only the necessary strings are
        /// enclosed in double-quotes.
        /// </param>
        /// <param name="culture">
        /// The culture to be used for data conversion.
        /// </param>
        /// <param name="mapping">
        /// The mapping to be used for value transformation.
        /// </param>
        /// <param name="values">
        /// A list of values representing a single line of the CSV file.
        /// </param>
        private static void WriteLine(StreamWriter writer, Char separator, Boolean textual, CultureInfo culture, CsvMappings mapping, IEnumerable <Object> values)
        {
            StringBuilder builder = new StringBuilder(1024);

            if (values != null && values.Any())
            {
                foreach (Object value in values)
                {
                    String current = ProcessHelper.ConvertToString(value, culture, mapping);
                    builder.Append(ProcessHelper.ConvertToOutput(current, separator, textual));
                }
            }

            writer.WriteLine(ProcessHelper.FixupOutput(builder, separator).ToString());
        }
Esempio n. 3
0
        /// <summary>
        /// This method tries to load all values from given stream using given
        /// settings.
        /// </summary>
        /// <remarks>
        /// The settings parameter describes how the data within given file should be
        /// processed. For example, users may define the expected culture, the expected
        /// file encoding, which separator is used and so on.
        /// </remarks>
        /// <param name="stream">
        /// The stream to read data from.
        /// </param>
        /// <param name="settings">
        /// The settings to be used to process stream data.
        /// </param>
        /// <returns>
        /// A list of classes of  <typeparamref name="TInstance"/>.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// This exception is thrown either if given stream or if given settings is
        /// invalid.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// This exception is thrown in case of given stream does not have read access.
        /// </exception>
        public static IEnumerable <TInstance> Load(Stream stream, CsvSettings settings)
        {
            List <TInstance> values = new List <TInstance>();

            if (stream == null)
            {
                throw new ArgumentNullException(nameof(stream), $"The stream to read the data from is invalid.");
            }

            if (!stream.CanRead)
            {
                throw new ArgumentException("No read access to given stream.", nameof(stream));
            }

            if (settings == null)
            {
                throw new ArgumentNullException(nameof(settings), "The CSV settings are invalid.");
            }

            TypeDescriptor descriptor = TypeProcessor.LoadDescriptor <TInstance>();

            // NOTE: Keep in mind! All item descriptors are confirmed and ordered already.
            //       This means they are in the right (which means expected) order! Therefore,
            //       something like "search for right column" is absolutely redundant.

            List <ItemDescriptor> items = descriptor.Settings.ToList();
            List <String>         lines = new List <String>();

            using (StreamReader reader = new StreamReader(stream, settings.Encoding))
            {
                while (!reader.EndOfStream)
                {
                    String line = reader.ReadLine();
                    if (!String.IsNullOrWhiteSpace(line))
                    {
                        lines.Add(line);
                    }
                }
            }

            if (lines.Count > 0)
            {
                Char        separator = settings.Separator;
                Boolean     exactly   = settings.Exactly;
                CultureInfo culture   = settings.Culture;
                Boolean     heading   = settings.Heading;
                CsvMappings mapping   = settings.Mappings;

                CsvImporter <TInstance> .ValidateColumns(lines, separator, exactly, items); // throws

                Int32 index = 0;

                List <String> cells = ProcessHelper.SplitIntoCells(lines[index], separator);

                if (CsvImporter <TInstance> .IsHeaderLine(cells, items))
                {
                    // An exact header validation is performed, but only if the first
                    // line represents a header and Heading and Exactly are both enabled.
                    // In such a case a Format Exception is thrown as soon as the header
                    // does not exactly fit! In this conjunction, the validation must pass
                    // the case-sensitive check as well as the position check.

                    if (heading && exactly)
                    {
                        CsvImporter <TInstance> .ValidateHeader(cells, items); // throws
                    }

                    index++;
                }

                for (; index < lines.Count; index++)
                {
                    values.Add(CsvImporter <TInstance> .ProcessLine(lines[index], separator, exactly, culture, mapping, items));
                }
            }

            return(values);
        }