C#学习笔记之使用Access读取Excel表格

发布时间 2023-10-30 10:10:46作者: ycx-x

一、读取Excel表的内容(使用DataSet)

1.DataSet定义:表示数据在内存中的缓存。可以理解为,将从Excel表中读取出来的数据存入DataSet类中,之后对DataSet进行数据处理,能提高处理的速度。

2.DataSet属性和方法:

①属性

  • CaseSensitive:获取或设置一个值,该值指示DataTable中的字符串是否区分大小写。true:表示字符串区分大小写,false:表示字符串不区分大小写。默认为 false。
  • DefaultViewManager:获取DataSet中包含的数据的自定义视图,以允许使用自定义的DataViewManager进行筛选、搜索和导航。
  • DataSetName:获取或设置当前DataSet的名称。
  • EnforceConstraints:获取或设置一个值,该值指示是否在尝试任何更新操作时遵循约束规则。true:强制执行规则,否则为false,默认为 false。
  • ExtendedProperties:获取与DataSet相关联的自定义的用户信息的集合。
  • HasErrors:获取一个值,该值指示在DataTable中的任何DataSet对象是否存在错误。
  • IsInitialized:获取一个值,该值指示DataSet是否初始化。
  • Locale:获取或设置用来比较字符串表中的区域设置信息。
  • Namespace:获取或设置DataSet的命名空间。
  • Prefix:获取或设置XML前缀,该前缀是DataSet的命名空间的别名。
  • Relatios:获取关系链接表,并允许导航从父表到子表的集合。
  • RemotingFormat:获取或设置远程处理期间使用的确定的序列化DataSet。
  • SchemaSerializationMode:获取或设置SchemaSerializationMode模式的DataSet。
  • Site:获取或设置ISite的DataSet。
  • Tables:获取包含在DataSet中的表的集合。

②方法

  • BeginInit():开始初始化在窗体上使用或由另一个组件使用DataSet。初始化发生在运行时。
  • Clear():清除DataSet的所有表中删除所有行的任何数据。
  • Clone():将复制DataSet的结构,包括所有DataTable架构、关系和约束。不复制任何数据。
  • Copy():复制该DataSet的结构和数据。
  • DetermineSchemaSerializationMode(SerializationInfo info, StreamingContext context):确定DataSet的SchemaSerializationMode模式。
  • DetermineSchemaSerializationMode(XmlReader reader):确定DataSet的SchemaSerializationMode模式。
  • EndInit():结束在窗体上使用或由另一个组件使用的DataSet的初始化。初始化发生在运行时。
  • GetChanges():获取DataSet的副本,该副本包含自加载后或自上一次调用AcceptChanges()后对数据集做的所有更改。
  • GetChanges(DataRowState rowStates):获取由DataRowStatus筛选的DataSet副本,该副本包含自加载后或自上一次调用AcceptChanges()后对数据集做的所有更改。
  • GetSerializationData(SerializationInfo info, StreamingContext context):反序列化的二进制文件或XML流中的表数据。
  • GetObjectData(SerializationInfo info, StreamingContext context):使用序列化DataSet所需的数据填充序列化对象。
  • GetXml():返回存储在DataSet中的数据的XML表示形式。
  • GetXmlSchema():返回存储在DataSet中的数据的XML表示形式的XML架构。
  • GetSchemaSerializable():返回一个可序列化 System.Xml.Schema.XMLSchema 实例。
  • GetDataSetSchema(XmlSchemaSet schemaSet):获得一份 System.Xml.Schema.XmlSchemaSet 作为数据集。
  • HasChanges():获取一个值,该值指示是否 DataSet 已经更改,包括新的、 已删除,或已修改的行。
  • HasChanges(DataRowState rowStates):获取一个值,该值指示是否 DataSet 已经通过 DataRowState 筛选更改,包括新的、 已删除,或已修改的行。
  • InferXmlSchema(XmlReader reader, string[] nsArray):将指定 XmlReader 中的 XML 架构应用到 DataSet。
  • InferXmlSchema(Stream stream, string[] nsArray):将指定 Stream  中的 XML 架构应用到 DataSet。
  • InferXmlSchema(TextReader reader, string[] nsArray):将指定 TextReader 中的 XML 架构应用到 DataSet。
  • InferXmlSchema(string fileName, string[] nsArray):将指定文件中的 XML 架构应用到 DataSet。
  • InitializeDerivedDataSet():反序列化的所有表数据从二进制文件或XML流的数据集。
  • IsBinarySerialized(SerializationInfo info, StreamingContext context):检查DataSet序列化表示形式的格式。
  • Merge(DataSet dataSet):将指定的DataSet和架构合并到当前DataSet中。
  • Merge(DataSet dataSet, bool preserveChanges):将指定的DataSet和架构合并到当前DataSet中,在此过程中,根据给定的参数保留或放弃 DataSet 中的任何更改。
  • Merge(DataSet dataSet, bool preserveChanges, MissingSchemaAction missingSchemaAction):将指定的DataSet和架构合并到当前DataSet中,在此过程中,根据给定的参数保留或放弃在当前 DataSet中的更改并处理不兼容的架构。
  • Merge(DataTable table):将指定的 DataTable 和架构合并到当前DataSet中。
  • Merge(DataTable table, bool preserveChanges, MissingSchemaAction missingSchemaAction):将指定的 DataTable 和架构合并到当前DataSet中,在此过程中,根据给定的参数保留或放弃在当前 DataSet中的更改并处理不兼容的架构。
  • Merge(DataRow[] rows):将DataRow对象数组合并到当前 DataSet 中。
  • Merge( DataRow[] rows, bool preserveChanges, MissingSchemaAction missingSchemaAction):将DataRow对象数组合并到当前 DataSet 中,在此过程中,根据给定的参数保留或放弃在当前 DataSet中的更改并处理不兼容的架构。
  • OnPropertyChanging(PropertyChangedEventArgs pcevent):引发 DataSet.OnPropertyChanging(PropertyChangedEventArgs) 事件。
  • OnRemoveTable(DataTable table):当从DataTable中移除 DataSet时发生。
  • OnRemoveRelation(DataRelation relation):当从DataRelation中一处DataTable时发生。
  • RaisePropertyChanging(string name):将通知发送指定 DataSet 即将更改的属性。
  • RejectChanges():回滚自创建 DataSet 以来或上次调用 AcceptChanges() 所做的左右更改。
  • Reset():清除所有表并从 DataSet 中删除所有关系、 外部约束和表。子类应重写 Reset, 将 DataSet 还原到其原始状态。
  • ReadXmlSchema(XmlReader reader):从指定 XmlReader 中将 XML 架构读取到 DataSet。
  • ReadXmlSchema(Stream stream):从指定 Stream 中将 XML 架构读取到 DataSet。
  • ReadXmlSchema(TextReader reader):从指定 TextReader 中将 XML 架构读取到 DataSet。
  • ReadXmlSchema(string fileName):从指定文件将 XML 架构读取到 DataSet。
  • ReadXml(XmlReader reader):使用指定的 XmlReader 将 XML 架构和数据读入DataSet。
  • ReadXml(Stream stream):使用指定的 Stream  将 XML 架构和数据读入DataSet。
  • ReadXml(TextReader reader):使用指定的 TextReader 将 XML 架构和数据读入DataSet。
  • ReadXml(string fileName):使用指定的文件将 XML 架构和数据读入DataSet。
  • ReadXml(XmlReader reader, XmlReadMode mode):使用指定的 XmlReader 和 XmlReadMode 模式将 XML 架构和数据读入DataSet。
  • ReadXml(Stream stream, XmlReadMode mode):使用指定的 Stream 和 XmlReadMode 模式将 XML 架构和数据读入DataSet。
  • ReadXml(TextReader stream, XmlReadMode mode):使用指定的 TextReader 和 XmlReadMode 模式将 XML 架构和数据读入DataSet。
  • ReadXml(string fileName, XmlReadMode mode):使用指定的文件和 XmlReadMode 模式将 XML 架构和数据读入DataSet。
  • ReadXmlSerializable(XmlReader reader):将忽略属性,并返回一个空数据集。
  • WriteXmlSchema(Stream stream):将 DataSet 结构作为 XML 架构写入指定的 Stream 对象。
  • WriteXmlSchema(Stream stream, Converter<Type, string> multipleTargetConverter):将 DataSet 结构作为 XML 架构写入指定的 Stream 对象。
  • WriteXmlSchema(string fileName):将 DataSet 结构作为 XML 架构写入文件。
  • WriteXmlSchema(string fileName, Converter<Type, string> multipleTargetConverter):将 DataSet 结构作为 XML 架构写入文件。
  • WriteXmlSchema(TextWriter writer):将 DataSet 结构作为 XML 架构写入指定的 TextWriter 对象。
  • WriteXmlSchema(TextWriter writer, Converter<Type, string> multipleTargetConverter):将 DataSet 结构作为 XML 架构写入指定的 TextWriter 对象。
  • WriteXmlSchema(XmlWriter writer):将 DataSet 结构作为 XML 架构写入指定的 XmlWriter  对象。
  • WriteXmlSchema(XmlWriter writer, Converter<Type, string> multipleTargetConverter):将 DataSet 结构作为 XML 架构写入指定的 XmlWriter 对象。
  • WriteXml(Stream stream):使用指定的 Stream 将当前数据写入 DataSet。
  • WriteXml(TextWriter writer):使用指定的 TextWriter 将当前数据写入 DataSet。
  • WriteXml(XmlWriter writer):使用指定的 XmlWriter 将当前数据写入 DataSet。
  • WriteXml(string fileName):使用指定的文件将当前数据写入 DataSet。
  • WriteXml(Stream stream, XmlWriteMode mode):使用指定的 Stream 和 XmlWriteMode 写入 DataSet 的当前数据和架构(可选)。编写该架构,请设置mode参数为:WriteSchema。
  • WriteXml(TextWriter writer, XmlWriteMode mode):使用指定的 TextWriter 和 XmlWriteMode 写入 DataSet 的当前数据和架构(可选)。编写该架构,请设置mode参数为:WriteSchema。
  • WriteXml(XmlWriter writer, XmlWriteMode mode):使用指定的 XmlWriter 和 XmlWriteMode 写入 DataSet 的当前数据和架构(可选)。编写该架构,请设置mode参数为:WriteSchema。
  • WriteXml(string fileName, XmlWriteMode mode):使用指定的 XmlWriteMode 将 DataSet 当前的数据和架构(可选)写入指定的文件中。编写该架构,请设置mode参数为:WriteSchema。
  • ShouldSerializeRelations():获取一个值,该值指示是否保持Relations属性。
  • ShouldSerializeTables():获取一个值,该值指示是否保持Tables属性。

(方法较多,不一一例举)

3.读取Excel文件的内容,通过OLEDB来连接,关键是连接的路径

  • .xls:Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + path + ";Extended Properties=\"Excel 8.0;HDR=NO;IMEX=1\"
  • .xlsx:Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + path + ";Extended Properties=\"Excel 12.0;HDR=NO;IMEX=1\"

① Provider:使用的是OLEDB连接,但是这个技术会不定时更新,需要查找最新版本;

② Data Source + path:为Excel文件所在完整路径;

③ Extended Properties:指定Excel的版本,需与读取的Excel文件保持一致;

④ 参数Excel 8.0 表示对于Excel97以上到2003版本都用Excel 8.0;2007或2010的都用Excel 12.0;

⑤ HDR = YES:表示第一行是标题,不做为数据使用;HDR = NO:表示第一行不是标题,做为数据来使用。系统默认为YES;

⑥ IMEX(IMport EXport mode)设置:有三种模式

  • IMEX = 0:汇出模式,这个模式开启的 Excel 档案只能用来做“写入”用途;
  • IMEX = 1:汇入模式,这个模式开启的 Excel 档案只能用来做“读取”用途
  • IMEX = 2:连结模式,这个模式开启的 Excel 档案可同时支援“读取”和“写入”用途

4.读取不同的Sheet,方式跟SQL类似:使用字符串 "SELECT * FROM [Sheet1$]" 表示。

string connectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=” + path+ ";Extended Properties=\”Excel 12.0;HDR=NO;IMEX=1\"";
string sqlSelect = "SELECT * FROM [Sheet1$]";//Sheet1表示工作表的名称,可根据实际表格工作表进行设置
OleDbConnection connection = new OleDbConnection(connectionString);
OleDbCommand command = new OleDbCommand(sqlSelect, connection);
OleDbDataAdapter adapter = new OleDbDataAdapter(command);
connection.Open();
adapter.Fill(dataSet);

5.异常处理

①如果出现 External table is not in the expected format.

大多数是因为路径中的OLEDB或者Extented Properties 与当前的Excel文件版本不对应导致。

②如果出现 The "XXXXXXX" provider is not registered on the local machine.

那是因为Platform target配置不当的问题,OLEDB貌似只支持x86, 所以你只需要到项目属性 -> 生成-> 目标平台 -> x86就可以了

 3.如果出现 未在本地计算机上注册 “Microsoft.ACE.OLEDB.12.0"提供程序

可能是没有安装组件,进入Microsoft Access官网下载数据库引擎可再发行程序包

下载链接:Download Microsoft Access Database Engine 2010 Redistributable from Official Microsoft Download Center

双击安装包安装即可:

本人所遇问题,在安装完组件后,以完美解决,且前两个问题也没有出现。

二 、界面设计

 ①触发浏览按钮,选择Excel文档所在文件夹路径(使用的是 using 语句)

 ②触发开始按钮,对数据库进行查找,并将数据缓存至DataSet中

③选择提取出来的DataSet数据库中的表格DataTable

④将DataTable中的内容显示在主界面的控件1中,对DataTable表格内某些内容进行提取并处理,将处理后的数据保存至主界面的控件2内

 三、主界面代码逻辑

private Configuration configuration;
private OtherConfiguration otherConfiguration;
private const string startString = @"开始读值";
private const string stopString = @"停止读值";
int excelCount;
private ProductInfo[] productInfos;

private void FormMain_Load(object sender, EventArgs e)
{
    productInfos = new ProductInfo[255];
    configuration = Configuration.Instance.Read(FilePathStrings.ConfigurantionFilePath);
    otherConfiguration = configuration.OtherConfiguration ?? new OtherConfiguration();
}
private void btnToolSet_Click(object sender, EventArgs e)
{
    using (FormSetting setting = new FormSetting())
    {
        if (setting.ShowDialog() == DialogResult.OK)
        {
            configuration = Configuration.Instance.Read(FilePathStrings.ConfigurantionFilePath);
            otherConfiguration = configuration.OtherConfiguration;
        }
    }
}
private void btnToolTest_Click(object sender, EventArgs e)
{
    if (string.IsNullOrEmpty(otherConfiguration.TestResultPathFile1) || string.IsNullOrEmpty(otherConfiguration.TestResultPathFile2) || string.IsNullOrEmpty(otherConfiguration.DataName))
    {
        MessageBoxEx.Show("参数设置不完整,请转【参数设置】区域", ConstStrings.Tips, MessageBoxButtons.OK, MessageBoxIcon.Warning);
        return;
    }
    Invoke(new Action(() => btnToolSet.Enabled = false));
    excelCount = 0;
    btnToolTest.Text = stopString;
    string[] dataNameList = null;
    int startIndex = -1;
    var currentDataName = ComboBoxEx.GetEnumName<eDataName>(otherConfiguration.DataName);
    switch (currentDataName)
    {
        case eDataName.Convention:
            startIndex = 1;
            dataNameList = ConstStrings.DataNameConvention.Split(',');
            break;
        case eDataName.Special:
            startIndex = 0;
            dataNameList = ConstStrings.DataNameSpecial.Split(',');
            break;
        default: throw new NotImplementedException("无效类型!");
    }
    ForeachAllExcleFromFile(otherConfiguration.TestResultPathFile1, startIndex, dataNameList);
    btnToolTest.Text = startString;
    Invoke(new Action(() => btnToolSet.Enabled = true));
}
private void ForeachAllExcleFromFile(string testResultPathFile1, int startIndex, string[] dataStrings)
{
    dataGridView1.DataSource = null;
dataGridView2.DataSource = null; FileInfo[] fileInfos
= new DirectoryInfo(testResultPathFile1).GetFiles(); //string[] fileStrings = new DirectoryInfo(testResultPathFile1).GetFiles().Select(s => s.Name).ToArray(); productInfos = new ProductInfo[fileInfos.Length]; bool isReadError = false; foreach (var file in fileInfos) { try { isReadError = false; ReadExcelData excelData = new ReadExcelData(file.FullName, file.Extension, dataStrings[0]); DataTable dataTable = excelData.OpenExcel().Tables[0];
dataGridView1.DataSource = dataTable; DisplaysOptimizationTable(startIndex, dataStrings, dataTable,
out bool error); if (!error) excelCount++; } catch (Exception ex) {
MessageBoxEx.Show(ex.Message,ConstStrings.Tips,MessageBoxButtons.OK,MessageBoxIcon.Warning); isReadError
= true; } } if (!isReadError) {
dataGridView2.DataSource
= productInfos; }
}
private void DisplaysOptimizationTable(int startIndex, string[] dataStrings, DataTable dataTable, out bool error) { error = false; int passCount = 0; int failCount = 0; try { int dataIndex = Array.IndexOf(dataTable.Rows[startIndex].ItemArray, dataStrings[2]); int numIndex = Array.IndexOf(dataTable.Rows[startIndex].ItemArray, dataStrings[3]); int resultIndex = Array.IndexOf(dataTable.Rows[startIndex].ItemArray, dataStrings[4]); for (int index = 0; index < dataTable.Rows.Count - 1 - startIndex; index++) { if (dataTable.Rows[index + 1 + startIndex].ItemArray[resultIndex].ToString().ToUpper().Contains("PASS")) passCount++; else failCount++; } var currentDataName = ComboBoxEx.GetEnumName<eDataName>(otherConfiguration.DataName); string dateTimeString = string.Empty; switch (currentDataName) { case eDataName.Convention: dateTimeString = dataTable.Rows[startIndex + 1].ItemArray[dataIndex].ToString(); break; case eDataName.Special: dateTimeString = Convert.ToDateTime(dataTable.Rows[startIndex + 1].ItemArray[dataIndex]).ToString("yyyy-MM-dd"); break; default: throw new InvalidOperationException("指定类型无效"); } productInfos[excelCount] = new ProductInfo() { DateTime = dateTimeString, Name = Convert.ToString(dataTable.Rows[startIndex + 1].ItemArray[numIndex]).ToUpper(), PassCount = passCount, FailCount = failCount, TotalCount = passCount + failCount }; } catch (Exception ex) { error = true; WriteLog(ex.Message); } }