Célkitűzés:

Szeretnék importálni egy Excel fájlt, és elolvasni bizonyos oszlopok sorait. Ehhez a ExcelDataReader fájlt használom. Megvalósítottam egy ExcelData nevű alacsony szintű osztályt, amely a ExcelDataReader -t használja, és olyan dolgokat végez, mint például, hogy rájöjjek, hogy ez egy .xls “of” .xslx “fájl (vagy valami teljesen független!) stb. Az osztály tetejére készítettem egy ReadInData osztályt, amely megkapja a kívánt oszlopokat az Excelből lap.

Fő gondok:

  • A fő programom fogási listája
  • Kivételek dobása
  • Az általános felépítés a kód és a kód minősége
  • Be kell-e foglalnom az ExcelData osztályomat a ReadInData -be, vagy tartsam úgy, ahogy van ?
  • A isFirstRowAsColumnNames paraméter átadása

Mivel ez egy vállalat kódja, megváltoztattam pár nevét osztályokból, úgyhogy tudom, hogy nem a legjobb nevek.

A kódom belépési pontja:

class Program { static void Main(string[] args) { try { ReadInData readInData = new ReadInData(@"C:\SC.xlsx", "sc_2014"); IEnumerable<Recipient> recipients = readInData.GetData(); } catch (FileNotFoundException ex) { Console.WriteLine(ex.Message); } catch (ArgumentException ex) { Console.WriteLine(ex.Message); } catch (WorksheetDoesNotExistException ex) { Console.WriteLine(ex.Message); } catch (FileToBeProcessedIsNotInTheCorrectFormatException ex) { Console.WriteLine(ex.Message); } Console.ReadLine(); } } 

Ebben kódot hozok létre egy új ReadInData osztályt, amelyhez átadok s az útvonalat, a fájl nevét és az elolvasni kívánt Excel lap nevét.

Itt aggódik: rendben van-e ezeket a dolgokat átadni a fájlban?

A ReadInData osztály:

public class ReadInData { private string path; private string worksheetName; public ReadInData(string path, string worksheetName) { this.path = path; this.worksheetName = worksheetName; } public IEnumerable<Recipient> GetData(bool isFirstRowAsColumnNames = true) { var excelData = new ExcelData(path); var dataRows = excelData.GetData(worksheetName, isFirstRowAsColumnNames); return dataRows.Select(dataRow => new Recipient() { Municipality = dataRow["Municipality"].ToString(), Sexe = dataRow["Sexe"].ToString(), LivingArea = dataRow["LivingArea"].ToString() }).ToList(); } } 

Alapvetően arra gondoltam, hogy szükségem van egy osztályra a ExcelData osztály, mert valamivel magasabb szintűnek tűnt.

A ExcelData osztály:

public class ExcelData { private string path; public ExcelData(string path) { this.path = path; } private IExcelDataReader GetExcelDataReader(bool isFirstRowAsColumnNames) { using (FileStream fileStream = File.Open(path, FileMode.Open, FileAccess.Read)) { IExcelDataReader dataReader; if (path.EndsWith(".xls")) { dataReader = ExcelReaderFactory.CreateBinaryReader(fileStream); } else if (path.EndsWith(".xlsx")) { dataReader = ExcelReaderFactory.CreateOpenXmlReader(fileStream); } else { //Throw exception for things you cannot correct throw new FileToBeProcessedIsNotInTheCorrectFormatException("The file to be processed is not an Excel file"); } dataReader.IsFirstRowAsColumnNames = isFirstRowAsColumnNames; return dataReader; } } private DataSet GetExcelDataAsDataSet(bool isFirstRowAsColumnNames) { return GetExcelDataReader(isFirstRowAsColumnNames).AsDataSet(); } private DataTable GetExcelWorkSheet(string workSheetName, bool isFirstRowAsColumnNames) { DataSet dataSet = GetExcelDataAsDataSet(isFirstRowAsColumnNames); DataTable workSheet = dataSet.Tables[workSheetName]; if (workSheet == null) { throw new WorksheetDoesNotExistException(string.Format("The worksheet {0} does not exist, has an incorrect name, or does not have any data in the worksheet", workSheetName)); } return workSheet; } public IEnumerable<DataRow> GetData(string workSheetName, bool isFirstRowAsColumnNames = true) { DataTable workSheet = GetExcelWorkSheet(workSheetName, isFirstRowAsColumnNames); IEnumerable<DataRow> rows = from DataRow row in workSheet.Rows select row; return rows; } } 

És végül a Recipient osztály (amely semmi különöset nem csinál):

namespace ConsoleApplicationForTestingPurposes { public class Recipient { public string Municipality { get; set; } public string Sexe { get; set; } public string LivingArea { get; set; } } } 

A kivételosztályok öröklik a Exception fájlt, és csak továbbítanak egy üzenetet a Kivételnek.

Megjegyzések

  • Ez a kód nem működik az összes Excel-fájllal … Ne feledje, hogy van néhány más EXCEL-File végződés is. ".xlsm" és ".xlsb", valamint a sablontípusok …
  • @ Vogel612 Köszönöm, vállalom figyelembe!
  • Ez hasznos volt. Volt olyan kódunk, amely csak az OpenXml kódot használta, amely kivételt vetett be, amikor valaki először megpróbálta .xls-t használni (évekkel az első bevezetés után). Aztán az első kísérlet a javításra ‘ nem működött, mert csak megpróbálta a bináris olvasót, miután az első olvasó érvénytelen volt, de ez tönkretette a folyamot. A bővítmény ellenőrzése először kijavította.

Válasz

Egyszerűsítse a fogási láncot

static void Main(string[] args) { try { ReadInData readInData = new ReadInData(@"C:\SC.xlsx", "sc_2014"); IEnumerable<Recipient> recipients = readInData.GetData(); } catch (Exception ex) { if(!(ex is FileNotFoundException || ex is ArgumentException || ex is FileToBeProcessedIsNotInTheCorrectFormatException)) throw; Console.WriteLine(ex.Message); } Console.Write(Press any key to continue...); Console.ReadKey(true); } 

Nem látok okot arra, hogy ReadInData nem statikus osztály legyen. Nem használja ki azt a tényt, hogy emlékszik az útvonalra és a munkalap nevére, és nem tart valamilyen nyitott kapcsolatot a munkafüzettel. És mindig bátran tegye a kódot bonyolultabbá azáltal, hogy eltávolítja a csak egyszer használatos (opcionális). Nincs ok ToList() erre, mert úgyis egy IEnumerable<T> -t ad vissza.

public static class ReadInData { public static IEnumerable<Recipient> GetData(string path, string worksheetName, bool isFirstRowAsColumnNames = true) { return new ExcelData(path).GetData(worksheetName, isFirstRowAsColumnNames) .Select(dataRow => new Recipient() { Municipality = dataRow["Municipality"].ToString(), Sexe = dataRow["Sexe"].ToString(), LivingArea = dataRow["LivingArea"].ToString() }); } } 

Ugyanezt megteheti ExcelData osztályában is, vagyis ezeket a függvényeket metódusok helyett a osztály. Nem kell, de megint csak nem használod ki nagyon az OO előnyeit, ezért szükséged van rá, hogy OO-vá tedd.


Ha nem akar / kell valakit a ExcelData osztályod használatával, mint azt beburkolja. Úgy érzem azonban, hogy valamikor meg akarja tudni használni ezt az excel olvasót, ebben az esetben ezeket a módszereket áthelyezném egy Static ExcelHelperClass fájlba. És az első osztályod ReadInData Csak elkészítenék egy módszert az eredeti programodban.

private static IExcelDataReader GetExcelDataReader(string path, bool isFirstRowAsColumnNames) { using (FileStream fileStream = File.Open(path, FileMode.Open, FileAccess.Read)) { IExcelDataReader dataReader; if (path.EndsWith(".xls")) dataReader = ExcelReaderFactory.CreateBinaryReader(fileStream); else if (path.EndsWith(".xlsx")) dataReader = ExcelReaderFactory.CreateOpenXmlReader(fileStream); else throw new FileToBeProcessedIsNotInTheCorrectFormatException("The file to be processed is not an Excel file"); dataReader.IsFirstRowAsColumnNames = isFirstRowAsColumnNames; return dataReader; } } private static DataSet GetExcelDataAsDataSet(string path, bool isFirstRowAsColumnNames) { return GetExcelDataReader(path, isFirstRowAsColumnNames).AsDataSet(); } private static DataTable GetExcelWorkSheet(string path, string workSheetName, bool isFirstRowAsColumnNames) { DataTable workSheet = GetExcelDataAsDataSet(path, isFirstRowAsColumnNames).Tables[workSheetName]; if (workSheet == null) throw new WorksheetDoesNotExistException(string.Format("The worksheet {0} does not exist, has an incorrect name, or does not have any data in the worksheet", workSheetName)); return workSheet; } private static IEnumerable<DataRow> GetData(string path, string workSheetName, bool isFirstRowAsColumnNames = true) { return from DataRow row in GetExcelWorkSheet(path, workSheetName, isFirstRowAsColumnNames).Rows select row; } 

Mint a megjegyzésekben említett, nem az összes Excel fájltípust veszi figyelembe.


Ha nem ez volt a bool isFirstRowAsColumnNames, akkor azt javaslom, hogy valóban lépjen tovább az egész OOP-val, és töltse le a munkafüzetet, amikor elkészíti, és kihasználja az OO-tervezés előnyeit azzal, hogy az útvonal mellett ténylegesen belső adatokkal rendelkezik. Úgy gondolom, hogy rendben van, ha lehetőséget ad nekik a isFirstRowAsColumnNames, ez nagyon hasznos lehet.

Megjegyzések

  • Először is, köszönöm szépen, hogy fektett a munkájába. együtt mit lehetne javítani a kódomon. Van azonban néhány kérdésem; az első az, hogy ‘ nem vagyok biztos benne, mit értett a ” És az első osztályú ReadInData-t csak elkészíteném egy módszert az eredeti programodban. A második dolog az, hogy én ‘ sem vagyok igazán biztos abban, hogy mire gondoltál az utolsó bekezdésed első mondatával.Azt akarja mondani, hogy ha nem lenne ‘ nem az isFirstRowAsColumnNames paraméter, akkor többé-kevésbé megtarthatnám a kódomat, ahogy volt? Ha igen, miért függne ez ettől?

Vélemény, hozzászólás?

Az email címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük