目的:

Excelファイルをインポートして、特定の列の行を読み取ります。このために、私はExcelDataReaderを使用します。 ExcelDataReaderを使用し、それが「.xls」であるかどうかを判断するなどの処理を行うExcelDataという低レベルのクラスを実装しました。 “.xslx”ファイルの “(または完全に無関係なもの!)など。そのクラスの上にReadInDataクラスを作成しました。これにより、Excelから必要な特定の列が取得されます。シート。

主な懸念事項:

  • メインプログラムのキャッチのリスト
  • 例外のスロー
  • 全体的な構造コードとコード品質の概要
  • ExcelDataクラスをReadInData内にカプセル化するか、そのままにしておく必要があります?
  • isFirstRowAsColumnNamesパラメーターの受け渡し

これは会社のコードであるため、カップルの名前を変更しました

コードのエントリポイント:

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

この中コード新しいReadInDataクラスを作成します。 ■パス、ファイルの名前、および読みたいExcelシートの名前。

ここでの懸念事項:そのファイル内でそれらを渡しても大丈夫ですか?

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

基本的に、

クラス、レベルがやや高いように見えたため。

ExcelDataクラス:

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

そして最後に、Recipientクラス(特別なことは何もしません):

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

例外クラスはExceptionを継承し、メッセージをExceptionに渡すだけです。

コメント

  • このコードはすべてのExcelファイルで機能するわけではありません…他にもいくつかのEXCELファイルの末尾があることに注意してください。 ".xlsm"".xlsb"、およびテンプレートタイプ…
  • @ Vogel612ありがとうございます。考慮に入れてください!
  • これは役に立ちました。 OpenXmlを使用したコードがあり、誰かが初めて.xlsを使用しようとしたときに例外がスローされました(最初の実装から数年後)。次に、最初のリーダーが無効になった後でバイナリリーダーを試しただけで、ストリームが台無しになったため、最初の修正の試みは機能しませんでした。拡張機能を確認すると、最初に修正されました。

回答

キャッチチェーンを簡素化する

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

ReadInDataを非静的クラスにする理由はありません。パスとワークシート名を覚えているという事実を利用しておらず、ワークブックへの何らかのオープンな接続を維持していません。また、唯一の変数を削除することで、コードをより複雑に見せることができます。一度使用されます(オプション)。とにかくIEnumerable<T>を返すため、これをToList()する理由はありません。

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

ExcelDataクラスでも同じことができます。つまり、メソッドの代わりにこれらの関数を作成します。クラス。そうする必要はありませんが、OOをあまり活用していないので、OOにする必要があります。


そうでない場合カプセル化するよりも、ExcelDataクラスを使用している人が欲しい/必要です。ただし、いつかこのExcelリーダーを再利用できるようにしたいと思うでしょう。その場合は、これらのメソッドを静的ExcelHelperClassに移動します。そして、最初のクラスReadInData元のプログラムでメソッドを作成します。

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

Asコメントに記載されているように、すべてのExcelファイルタイプを考慮しているわけではありません。


bool isFirstRowAsColumnNamesが考慮されていない場合は実際に先に進むことをお勧めしますOOP全体を使用して、ワークブックを作成するときにロードし、パスだけでなく内部データを実際に持つことでオブジェクト指向設計を活用します。isFirstRowAsColumnNames、これは非常に便利です。

コメント

  • まず、お時間を割いていただきありがとうございます。私のコードについて何を改善できるかを一緒に説明します。ただし、いくつか質問があります。最初の質問は、’が”そして最初のクラスのReadInData私はあなたの元のプログラムでメソッドを作るだけです。 2つ目は、’も、最後の段落の最初の文で何を意味するのかよくわからないということです。’ isFirstRowAsColumnNamesパラメータがない場合、コードを多かれ少なかれそのままにしておくことができると言っていますか? もしそうなら、なぜそれはそれに依存するのでしょうか?

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です