c# - ईपीप्लस का उपयोग कर डेटाटेबल को एक्सेल-संपादन के लिए एक्सेल लॉक किया गया




excel epplus (4)

मैं ईपीप्लस का उपयोग कर एक्सेल को डेटाटेबल में बदलने के लिए निम्न कोड का उपयोग कर रहा हूं:

public DataTable ExcelToDataTable(string path)
{
    var pck = new OfficeOpenXml.ExcelPackage();
    pck.Load(File.OpenRead(path));
    var ws = pck.Workbook.Worksheets.First();
    DataTable tbl = new DataTable();
    bool hasHeader = true;
    foreach (var firstRowCell in ws.Cells[1, 1, 1, ws.Dimension.End.Column])
    {
        tbl.Columns.Add(hasHeader ? firstRowCell.Text : string.Format("Column {0}", firstRowCell.Start.Column));
    }
    var startRow = hasHeader ? 2 : 1;
    for (var rowNum = startRow; rowNum <= ws.Dimension.End.Row; rowNum++)
    {
        var wsRow = ws.Cells[rowNum, 1, rowNum, ws.Dimension.End.Column];
        var row = tbl.NewRow();
        foreach (var cell in wsRow)
        {
            row[cell.Start.Column - 1] = cell.Text;
        }
        tbl.Rows.Add(row);
    }
    pck.Dispose();
    return tbl;
}

यह एक्सेल बनाता है, हालांकि, जब मैं इसे खोलने का प्रयास करता हूं, तो यह मुझे संदेश देता है कि इसे किसी अन्य उपयोगकर्ता द्वारा संपादित करने के लिए बंद कर दिया गया है और मैं इसे केवल-पढ़ने के लिए मोड में खोल सकता हूं।

मैंने सोचा था:

pck.Dispose();

इस मुद्दे को हल करेंगे, हालांकि मुझे अभी भी एक ही त्रुटि मिल रही है।

साथ ही, जब मैं फ़ाइल को हटाने का प्रयास करता हूं, तो मुझे संदेश मिलता है: कार्रवाई पूर्ण नहीं की जा सकती क्योंकि फ़ाइल WebDev.WebServer40.EXE में खुली है।

कोई विचार यह कैसे हल करें? अग्रिम में धन्यवाद। :)


टिम श्मेलर के उत्तर का एक विस्तार संस्करण।

public static DataTable ToDataTable(this ExcelWorksheet ws, bool hasHeaderRow = true)
{
    var tbl = new DataTable();
    foreach (var firstRowCell in ws.Cells[1, 1, 1, ws.Dimension.End.Column])
        tbl.Columns.Add(hasHeaderRow ?
            firstRowCell.Text : string.Format("Column {0}", firstRowCell.Start.Column));
    var startRow = hasHeaderRow ? 2 : 1;
    for (var rowNum = startRow; rowNum <= ws.Dimension.End.Row; rowNum++)
    {
        var wsRow = ws.Cells[rowNum, 1, rowNum, ws.Dimension.End.Column];
        var row = tbl.NewRow();
        foreach (var cell in wsRow) row[cell.Start.Column - 1] = cell.Text;
        tbl.Rows.Add(row);
    }
    return tbl;
}

मैं देखता हूं, मैंने हाल ही में यहां पोस्ट किया है (अब सही)। ExcelPackage और FileStream ( File.OpenRead ) का उपयोग करने के बाद इसका निपटारा नहीं किया जा सकता है।

public static DataTable GetDataTableFromExcel(string path, bool hasHeader = true)
{
    using (var pck = new OfficeOpenXml.ExcelPackage())
    {
        using (var stream = File.OpenRead(path))
        {
            pck.Load(stream);
        }
        var ws = pck.Workbook.Worksheets.First();  
        DataTable tbl = new DataTable();
        foreach (var firstRowCell in ws.Cells[1, 1, 1, ws.Dimension.End.Column])
        {
            tbl.Columns.Add(hasHeader ? firstRowCell.Text : string.Format("Column {0}", firstRowCell.Start.Column));
        }
        var startRow = hasHeader ? 2 : 1;
        for (int rowNum = startRow; rowNum <= ws.Dimension.End.Row; rowNum++)
        {
            var wsRow = ws.Cells[rowNum, 1, rowNum, ws.Dimension.End.Column];
            DataRow row = tbl.Rows.Add();
            foreach (var cell in wsRow)
            {
                row[cell.Start.Column - 1] = cell.Text;
            }
        }
        return tbl;
    }
}

यह उपरोक्त जेनेरिक में सुधार है। उपयोग करें यदि आपके पास निम्न गुणों के साथ एक वर्ग है, "नाम", "उपनाम", "टेलीफोन", "फ़ैक्स" और आपके पास समान नाम वाली पहली पंक्ति के साथ एक्सेल शीट है, तो यह एक्सेल पंक्तियों को लोड करेगा कक्षा वस्तु और इसे एक सूची में पॉप

public static List<T> GetClassFromExcel<T>(string path, int fromRow, int fromColumn, int toRow = 0, int toColumn = 0)
{
if (toColumn != 0 && toColumn < fromColumn) throw new          Exception("toColumn can not be less than fromColumn");
if (toRow != 0 && toRow < fromRow) throw new Exception("toRow can not be less than fromRow");
List<T> retList = new List<T>();
using (var pck = new ExcelPackage())
{
            using (var stream = File.OpenRead(path))
            {
                pck.Load(stream);
            }
            //Retrieve first Worksheet
            var ws = pck.Workbook.Worksheets.First();
            //If the to column is empty or 0, then make the tocolumn to the count of the properties
            //Of the class object inserted
            toColumn = toColumn == 0 ? typeof(T).GetProperties().Count() : toColumn;

            //Read the first Row for the column names and place into a list so that
            //it can be used as reference to properties
            Dictionary<string, int> columnNames = new Dictionary<string, int>();
            // wsRow = ws.Row(0);
            var colPosition = 0;
            foreach (var cell in ws.Cells[1, 1, 1, toColumn == 0 ? ws.Dimension.Columns : toColumn])
            {
                columnNames.Add(cell.Value.ToString(), colPosition);
                colPosition++;
            }
            //create a instance of T
            T objT = Activator.CreateInstance<T>();
            //Retrieve the type of T
            Type myType = typeof(T);
            //Get all the properties associated with T
            PropertyInfo[] myProp = myType.GetProperties();


            //Loop through the rows of the excel sheet
            for (var rowNum = fromRow; rowNum <= (toRow == 0? ws.Dimension.End.Row : toRow); rowNum++)
            {
                var wsRow = ws.Cells[rowNum, fromColumn, rowNum, ws.Cells.Count()];

                foreach (var propertyInfo in myProp)
                {
                    if (columnNames.ContainsKey(propertyInfo.Name))
                    {
                        int position = 0;
                        columnNames.TryGetValue(propertyInfo.Name, out position);
                        //int position = columnNames.IndexOf(propertyInfo.Name);
                        //To prevent an exception cast the value to the type of the property.
                        propertyInfo.SetValue(objT, Convert.ChangeType(wsRow[rowNum, position + 1].Value, propertyInfo.PropertyType));
                    }
                }

                retList.Add(objT);
            }

        }
        return retList;
    }

यदि आप की जरूरत है तो अब आप एक डाटाबेसिंग स्रोत के रूप में सूची का उपयोग कर सकते हैं ... मुझे आप से एक ... :) डैनियल सी। वेरी

इसे कॉल करने के लिए कॉलम के लिए अपडेट किया गया और पंक्ति में जोड़ा गया और एंड्रियास सुझावों का पालन किया। एंड्रियास के लिए अंगूठे ऊपर


public static List<T> GetClassFromExcel<T>(string path, int fromRow, int fromColumn, int toRow = 0, int toColumn = 0) where T: class, new()
{
        if (toColumn != 0 && toColumn < fromColumn) throw new Exception("toColumn can not be less than fromColumn");
        if (toRow != 0 && toRow < fromRow) throw new Exception("toRow can not be less than fromRow");
        List<T> retList = new List<T>();
        using (var pck = new ExcelPackage())
        {
            using (var stream = File.OpenRead(path))
            {
                pck.Load(stream);
            }
            //Retrieve first Worksheet
            var ws = pck.Workbook.Worksheets.First();

            toColumn = toColumn == 0 ? typeof(T).GetProperties().Count() : toColumn; //If the to column is empty or 0, then make the tocolumn to the count of the properties Of the class object inserted

            //Read the first Row for the column names and place into a list so that
            //it can be used as reference to properties
            Dictionary<string, int> columnNames = new Dictionary<string, int>();
            // wsRow = ws.Row(0);
            var colPosition = 0;
            foreach (var cell in ws.Cells[1, 1, 1, toColumn == 0 ? ws.Dimension.Columns : toColumn])
            {
                columnNames.Add(cell.Value.ToString(), colPosition);
                colPosition++;
            }

            //Retrieve the type of T
            Type myType = typeof(T);

            //Get all the properties associated with T
            PropertyInfo[] myProp = myType.GetProperties();

            //Loop through the rows of the excel sheet
            for (var rowNum = fromRow + 1; rowNum <= (toRow == 0 ? ws.Dimension.End.Row : toRow); rowNum++) // fromRow + 1 to read from next row after columnheader
            {

                //create a instance of T
                //T objT = Activator.CreateInstance<T>();
                T objT = new T();

                // var wsRow = ws.Cells[rowNum, fromColumn, rowNum, ws.Cells.Count()]; //ws.Cells.Count() causing out of range error hence using ws.Dimension.Columns to get last column index 
                var wsRow = ws.Cells[rowNum, fromColumn, rowNum, ws.Dimension.Columns];
                foreach (var propertyInfo in myProp)
                {
                    var attribute = propertyInfo.GetCustomAttributes(typeof(DisplayNameAttribute), true).Cast<DisplayNameAttribute>().SingleOrDefault();
                    string displayName = attribute != null && !string.IsNullOrEmpty(attribute.DisplayName) ? attribute.DisplayName : propertyInfo.Name; // If DisplayName annotation not used then get property name itself                       
                    if (columnNames.ContainsKey(displayName))
                    {
                        int position = 0;                           
                        columnNames.TryGetValue(displayName, out position);
                        ////int position = columnNames.IndexOf(propertyInfo.Name);
                        ////To prevent an exception cast the value to the type of the property.
                        propertyInfo.SetValue(objT, Convert.ChangeType(wsRow[rowNum, position + 1].Value, propertyInfo.PropertyType));
                    }
                }                   
                retList.Add(objT);
            }

        }
        return retList;
    }
//IMPLEMENTATION DONE BY PLACING Code IT IN SEPARATE Helpers.CS file  and 
//Consuming it in this manner
List<CustomerExcelModel> records = 
Helpers.GetClassFromExcel<CustomerExcelModel>(filelocation, 1, 1);

धन्यवाद उपयोगकर्ता के लिए बहुत कुछ जो कोड और एंड्रियास को सुझाव के लिए सबमिट किया गया है, निम्नलिखित परिवर्तन किए गए हैं, मैं जेनेरिकों के लिए नया हूं इसलिए मुझे किसी भी गलतियों के लिए क्षमा करें और सही करें कृपया नीचे संशोधित कोड ढूंढने से कोई मदद कर सकता है

  • एक्सेल कॉलम नाम के साथ मैप करने के लिए डिस्प्ले एनोटेशन इकाई मॉडल जोड़ा गया ताकि रिक्त स्थान के साथ कॉलम नाम भी संभाला जा सके।
  • "टी objT" मुद्दा था क्योंकि यह लूप के बाहर था और इसलिए उसी मूल्य को बार-बार सूची में डाला गया
    अंदरूनी लूप का अर्थ है यानी "नया टी ()"
  • कॉलम गिनती पाने के लिए "ws.Dimension.Columns" का उपयोग कर रेंज त्रुटि से फिक्स्ड कॉलम, ws.Cells.Count () की बजाय श्रेणी कॉलम त्रुटि के कारण
  • पंक्ति डेटा के माध्यम से लूपिंग के लिए +1 जोड़ा गया, क्योंकि RowNum = 1 हेडर नाम पढ़ रहा था, इसलिए "rowNum = fromRow + 1" का मामूली परिवर्तन किया गया




epplus