दुर्भाग्य से ईपीप्लस के मूल निवासी ऐसी कोई विधि नहीं है। यह क्रैक करने के लिए एक कठिन अखरोट है क्योंकि आपको प्रतिबिंब का उपयोग करना होगा यदि आप वास्तव में इसे सामान्य बनाना चाहते हैं। और एक्सेल की वजह से सभी संख्याओं और तिथियों को डबल के रूप में संग्रहीत करने के कारण आपको बहुत सारे अनबॉक्सिंग से निपटना होगा और चेक टाइप करना होगा।
यह कुछ है जो मैं काम कर रहा हूं। इसकी एक विस्तार विधि है जो इसे Generics
के माध्यम से करेगी। यह काम करता है लेकिन सीमित परीक्षण के तहत ही सुनिश्चित करें कि आप इसे स्वयं जांचें। मैं गारंटी नहीं दे सकता कि यह सबसे अनुकूलित (अभी तक) है लेकिन यह उसके बिंदु पर बहुत सभ्य है। आप इसे इस तरह का प्रयोग करेंगे:
IEnumerable<TestObject> newcollection = worksheet.ConvertSheetToObjects<TestObject>();
विस्तार:
public static IEnumerable<T> ConvertSheetToObjects<T>(this ExcelWorksheet worksheet) where T:new()
{
//DateTime Conversion
var convertDateTime = new Func<double, DateTime>(excelDate =>
{
if (excelDate < 1)
throw new ArgumentException("Excel dates cannot be smaller than 0.");
var dateOfReference = new DateTime(1900, 1, 1);
if (excelDate > 60d)
excelDate = excelDate - 2;
else
excelDate = excelDate - 1;
return dateOfReference.AddDays(excelDate);
});
//Get the properties of T
var tprops = (new T())
.GetType()
.GetProperties()
.ToList();
//Cells only contains references to cells with actual data
var groups = worksheet.Cells
.GroupBy(cell => cell.Start.Row)
.ToList();
//Assume the second row represents column data types (big assumption!)
var types = groups
.Skip(1)
.First()
.Select(rcell => rcell.Value.GetType())
.ToList();
//Assume first row has the column names
var colnames = groups
.First()
.Select((hcell, idx) => new { Name = hcell.Value.ToString(), index = idx })
.Where(o => tprops.Select(p => p.Name).Contains(o.Name))
.ToList();
//Everything after the header is data
var rowvalues = groups
.Skip(1) //Exclude header
.Select(cg => cg.Select(c => c.Value).ToList());
//Create the collection container
var collection = rowvalues
.Select(row =>
{
var tnew = new T();
colnames.ForEach(colname =>
{
//This is the real wrinkle to using reflection - Excel stores all numbers as double including int
var val = row[colname.index];
var type = types[colname.index];
var prop = tprops.First(p => p.Name == colname.Name);
//If it is numeric it is a double since that is how excel stores all numbers
if (type == typeof (double))
{
//Unbox it
var unboxedVal = (double) val;
//FAR FROM A COMPLETE LIST!!!
if (prop.PropertyType == typeof (Int32))
prop.SetValue(tnew, (int) unboxedVal);
else if (prop.PropertyType == typeof (double))
prop.SetValue(tnew, unboxedVal);
else if (prop.PropertyType == typeof (DateTime))
prop.SetValue(tnew, convertDateTime(unboxedVal));
else
throw new NotImplementedException(String.Format("Type '{0}' not implemented yet!", prop.PropertyType.Name));
}
else
{
//Its a string
prop.SetValue(tnew, val);
}
});
return tnew;
});
//Send it back
return collection;
}
इसके पूर्ण उदाहरण:
[TestMethod]
public void Read_To_Collection_Test()
{
//A collection to Test
var objectcollection = new List<TestObject>();
for (var i = 0; i < 10; i++)
objectcollection.Add(new TestObject {Col1 = i, Col2 = i*10, Col3 = Path.GetRandomFileName(), Col4 = DateTime.Now.AddDays(i)});
//Create a test file to convert back
byte[] bytes;
using (var pck = new ExcelPackage())
{
//Load the random data
var workbook = pck.Workbook;
var worksheet = workbook.Worksheets.Add("data");
worksheet.Cells.LoadFromCollection(objectcollection, true);
bytes = pck.GetAsByteArray();
}
//*********************************
//Convert from excel to a collection
using (var pck = new ExcelPackage(new MemoryStream(bytes)))
{
var workbook = pck.Workbook;
var worksheet = workbook.Worksheets["data"];
var newcollection = worksheet.ConvertSheetToObjects<TestObject>();
newcollection.ToList().ForEach(to => Console.WriteLine("{{ Col1:{0}, Col2: {1}, Col3: \"{2}\", Col4: {3} }}", to.Col1, to.Col2, to.Col3, to.Col4.ToShortDateString()));
}
}
//test object class
public class TestObject
{
public int Col1 { get; set; }
public int Col2 { get; set; }
public string Col3 { get; set; }
public DateTime Col4 { get; set; }
}
कंसोल आउटपुट:
{ Col1:0, Col2: 0, Col3: "wrulvxbx.wdv", Col4: 10/30/2015 }
{ Col1:1, Col2: 10, Col3: "wflh34yu.0pu", Col4: 10/31/2015 }
{ Col1:2, Col2: 20, Col3: "ps0f1jg0.121", Col4: 11/1/2015 }
{ Col1:3, Col2: 30, Col3: "skoc2gx1.2xs", Col4: 11/2/2015 }
{ Col1:4, Col2: 40, Col3: "urs3jnbb.ob1", Col4: 11/3/2015 }
{ Col1:5, Col2: 50, Col3: "m4l2fese.4yz", Col4: 11/4/2015 }
{ Col1:6, Col2: 60, Col3: "v3dselpn.rqq", Col4: 11/5/2015 }
{ Col1:7, Col2: 70, Col3: "v2ggbaar.r31", Col4: 11/6/2015 }
{ Col1:8, Col2: 80, Col3: "da4vd35p.msl", Col4: 11/7/2015 }
{ Col1:9, Col2: 90, Col3: "v5dtpuad.2ao", Col4: 11/8/2015 }
महान काम करता है। दूसरों को ध्यान दें: 'const int RESOURCES_WORKSHEET = 1' (वर्कशीट इंडेक्स 1 आधारित हैं) – fiat
यह संशोधित करने के लिए सीधा है इसलिए कॉलम विशेषता कॉलम इंडेक्स के बजाय कॉलम नाम निर्दिष्ट करती है। – subsci
मैं प्रॉपर्टीइन्फो और कॉलम को एक सूची में मैप करने का एक प्रभावी तरीका खोज रहा था, 'फनक' का अच्छा उपयोग और लिंक का अच्छा उपयोग, मैंने उसी ऑपरेशन के लिए 7.5% में उपभोग करने में समय कम किया है जो ऐसा नहीं लगता है बहुत, लेकिन यह 680k एमएस से 50k एमएस पर जाता है यदि आप समानांतर लागू करते हैं तो यह समाधान तेज़ होगा। मैंने इस उत्तर से बहुत कुछ सीख लिया है। धन्यवाद! – Nekeniehl