عند قراءة ملف CSV باستخدام DataReader وموفر بيانات OLEDB Jet، كيف يمكنني التحكم في أنواع بيانات الأعمدة؟

StackOverflow https://stackoverflow.com/questions/115658

  •  02-07-2019
  •  | 
  •  

سؤال

في تطبيق C# الخاص بي، أستخدم موفر بيانات Microsoft Jet OLEDB لقراءة ملف CSV.تبدو سلسلة الاتصال كما يلي:

Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\Data;Extended Properties="text;HDR=Yes;FMT=Delimited

أقوم بفتح ADO.NET OleDbConnection باستخدام سلسلة الاتصال تلك وتحديد كافة الصفوف من ملف CSV باستخدام الأمر:

select * from Data.csv

عندما أقوم بفتح OleDbDataReader وفحص أنواع بيانات الأعمدة التي يُرجعها، أجد أن شيئًا ما في المكدس حاول تخمين أنواع البيانات بناءً على الصف الأول من البيانات في الملف.على سبيل المثال، لنفترض أن ملف CSV يحتوي على:

House,Street,Town
123,Fake Street,Springfield
12a,Evergreen Terrace,Springfield

سيؤدي استدعاء الأسلوب OleDbDataReader.GetDataTypeName للعمود المنزلي إلى الكشف عن أن العمود قد تم منحه نوع البيانات "DBTYPE_I4"، لذلك يتم تفسير كافة القيم المقروءة منه على أنها أعداد صحيحة.مشكلتي هي أن House يجب أن يكون سلسلة - عندما أحاول قراءة قيمة House من الصف الثاني، يقوم OleDbDataReader بإرجاع قيمة فارغة.

كيف يمكنني إخبار موفر قاعدة بيانات Jet أو OleDbDataReader بتفسير عمود كسلاسل بدلاً من أرقام؟

هل كانت مفيدة؟

المحلول

يوجد ملف مخطط يمكنك إنشاؤه لإخبار ADO.NET بكيفية تفسير ملف CSV - مما يمنحه في الواقع بنية.

جرب هذا: http://www.aspdotnetcodes.com/Importing_CSV_Database_Schema.ini.aspx

نصائح أخرى

للتوسع في إجابة مارك، أحتاج إلى إنشاء ملف نصي يسمى Schema.ini ووضعه في نفس الدليل مثل ملف CSV.بالإضافة إلى أنواع الأعمدة، يمكن لهذا الملف تحديد تنسيق الملف وتنسيق التاريخ والوقت والإعدادات الإقليمية وأسماء الأعمدة إذا لم تكن مضمنة في الملف.

لكي يعمل المثال الذي قدمته في السؤال، يجب أن يبدو ملف المخطط كما يلي:

[Data.csv]
ColNameHeader=True
Col1=House Text
Col2=Street Text
Col3=Town Text

يمكنني أيضًا تجربة ذلك لجعل موفر البيانات يفحص جميع الصفوف الموجودة في الملف قبل أن يحاول تخمين أنواع البيانات:

[Data.csv]
ColNameHeader=true
MaxScanRows=0

في الحياة الواقعية، يستورد تطبيقي البيانات من ملفات ذات أسماء ديناميكية، لذلك يجب علي إنشاء ملف Schema.ini سريعًا وكتابته في نفس الدليل مثل ملف CSV قبل أن أفتح اتصالي.

مزيد من التفاصيل يمكن العثور عليها هنا - http://msdn.microsoft.com/en-us/library/ms709353(VS.85).aspx - أو من خلال البحث في مكتبة MSDN عن "ملف Schema.ini".

يرجى المراجعة

http://kbcsv.codeplex.com/

using (var reader = new CsvReader("data.csv"))
{
    reader.ReadHeaderRecord();
    foreach (var record in reader.DataRecords)
    {
        var name = record["Name"];
        var age = record["Age"];
    }
}

تحتاج إلى إخبار السائق بمسح كافة الصفوف لتحديد المخطط.بخلاف ذلك، إذا كانت الصفوف القليلة الأولى رقمية والباقي أبجدية رقمية، فستكون الخلايا الأبجدية الرقمية فارغة.

يحب روري, ، وجدت أنني بحاجة إلى إنشاء ملف schema.ini ديناميكيًا لأنه لا توجد طريقة لإخبار برنامج التشغيل برمجيًا بفحص كافة الصفوف.(هذا ليس هو الحال بالنسبة لملفات Excel)

يجب أن تمتلك MaxScanRows=0 في schema.ini الخاص بك

فيما يلي مثال على الكود:

    public static DataTable GetDataFromCsvFile(string filePath, bool isFirstRowHeader = true)
    {
        if (!File.Exists(filePath))
        {
            throw new FileNotFoundException("The path: " + filePath + " doesn't exist!");
        }

        if (!(Path.GetExtension(filePath) ?? string.Empty).ToUpper().Equals(".CSV"))
        {
            throw new ArgumentException("Only CSV files are supported");
        }
        var pathOnly = Path.GetDirectoryName(filePath);
        var filename = Path.GetFileName(filePath);
        var schemaIni =
            $"[{filename}]{Environment.NewLine}" +
            $"Format=CSVDelimited{Environment.NewLine}" +
            $"ColNameHeader={(isFirstRowHeader ? "True" : "False")}{Environment.NewLine}" +
            $"MaxScanRows=0{Environment.NewLine}" +
            $" ; scan all rows for data type{Environment.NewLine}" +
            $" ; This file was automatically generated";
        var schemaFile = pathOnly != null ? Path.Combine(pathOnly, "schema.ini") : "schema.ini";
        File.WriteAllText(schemaFile, schemaIni);

        try
        {
            var sqlCommand = $@"SELECT * FROM [{filename}]";

            var oleDbConnString =
                $"Provider=Microsoft.Jet.OLEDB.4.0;Data Source={pathOnly};Extended Properties=\"Text;HDR={(isFirstRowHeader ? "Yes" : "No")}\"";

            using (var oleDbConnection = new OleDbConnection(oleDbConnString))
            using (var adapter = new OleDbDataAdapter(sqlCommand, oleDbConnection))
            using (var dataTable = new DataTable())
            {
                adapter.FillSchema(dataTable, SchemaType.Source);
                adapter.Fill(dataTable);
                return dataTable;
            }
        }
        finally
        {
            if (File.Exists(schemaFile))
            {
                File.Delete(schemaFile);
            }
        }
    }

ستحتاج إلى إجراء بعض التعديلات إذا كنت تقوم بتشغيل هذا على نفس الدليل في عدة سلاسل رسائل في نفس الوقت.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top