Cíl:

Chci importovat soubor aplikace Excel a přečíst řádky určitých sloupců. K tomu používám ExcelDataReader. Implementoval jsem třídu na nízké úrovni s názvem ExcelData, která používá ExcelDataReader a dělá věci, jako je zjišťování, zda se jedná o soubor .xls Soubor „of“ .xslx „(nebo možná něco zcela nesouvisejícího!) atd. Kromě této třídy jsem vytvořil třídu ReadInData, která z aplikace Excel získá konkrétní sloupce, které chci. list.

Hlavní obavy:

  • Seznam úlovků v mém hlavním programu
  • Házení výjimek
  • Celková konstrukce kódu a kvality kódu
  • Mám zapouzdřit svoji ExcelData třídu do ReadInData, nebo ji ponechat, jaká je ?
  • Předání parametru isFirstRowAsColumnNames

Protože se jedná o kód pro společnost, změnil jsem názvy párů tříd, takže vím, že to nejsou ta nejlepší jména.

Vstupní bod mého kódu:

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(); } } 

V tomto kód Vytvořím novou ReadInData třídu, do které přejdu s cesta, název souboru a název listu aplikace Excel, který chci číst.

Obavy zde: je v pořádku předávat tyto věci do tohoto souboru?

Třída ReadInData:

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(); } } 

V zásadě jsem zjistil, že potřebuji třídu nad ExcelData třída, protože se zdála o něco vyšší úroveň.

ExcelData třída:

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; } } 

A nakonec třída Recipient (která nedělá nic zvláštního):

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

Třídy výjimek dědí z Exception a stačí předat zprávu výjimce.

Komentáře

  • Tento kód nefunguje u všech souborů Excel … Pamatujte, že existují i některé další konce souborů EXCEL. ".xlsm" a ".xlsb" a také typy šablon …
  • @ Vogel612 Díky, vezmu to v úvahu!
  • To bylo užitečné. Měli jsme kód, který právě používal ten OpenXml, který způsobil výjimku, když se někdo poprvé pokusil použít .xls (roky po první implementaci). Pak první pokus o opravu nepracoval ‚ t, protože to zkusilo binární čtečku poté, co byla první čtečka neplatná, ale to zničilo stream. Kontrola rozšíření to nejprve opravila.

Odpovědět

Zjednodušte svůj řetězec zachycení

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); } 

Nevidím důvod, aby ReadInData byl nestatická třída. Nevyužíváte výhody toho, že si pamatujete cestu a název listu a nezachováváte nějaký druh otevřeného připojení k sešitu. A vždy klidně udělejte svůj kód komplexnějším odstraněním proměnných, které jsou pouze jednou použito (volitelné). Není důvod ToList() to dělat, protože IEnumerable<T> stejně vracíte.

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() }); } } 

To samé můžete udělat pro svoji třídu ExcelData, tj. dělat tyto funkce místo metod na třída. Nemusíte, ale opět nevyužíváte mnoho výhod OO, takže je nutné, abyste z toho udělali OO.


Pokud nemáte chtít / potřebovat někoho, kdo používá vaši ExcelData třídu, než ji zapouzdřit. Cítím však, že v určitém okamžiku budete chtít být schopni znovu použít tuto aplikaci Excel Reader, v takovém případě bych tyto metody přesunul do Static ExcelHelperClass. A vaše první třída ReadInData Jen bych vytvořil metodu ve vašem původním programu.

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; } 

Jak zmíněné v komentářích, nepočítáte se všemi typy souborů aplikace Excel.


Pokud to nebylo pro bool isFirstRowAsColumnNames navrhoval bych, abyste skutečně šli vpřed s celou věcí OOP a při jejím sestavení načtěte sešit a využijte výhod OO designu tím, že budete mít kromě cesty pouze interní data. Myslím, že je v pořádku, že jim dáte možnost zadat isFirstRowAsColumnNames, to by mohlo být velmi užitečné.

Komentáře

  • Nejprve vám moc děkuji za váš čas při uvádění společně, co by se dalo na mém kódu vylepšit. Mám však několik otázek; první je, že si ‚ nejsem si jistý, co jste myslel “ A s vaší první třídou ReadInData bych vytvořil metodu ve vašem původním programu. Druhá věc je, že si také ‚ nejsem úplně jistý, co jste myslel první větou vašeho posledního odstavce.Říkáte, že kdybych ‚ neměl parametr isFirstRowAsColumnNames, mohl bych si kód ponechat víceméně tak, jak byl? Pokud ano, proč by na tom záleželo?

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *