C#에서 Excel을 읽는 세 가지 방법 및 비교 분석
(1) OleDB 방식
장점: 엑셀을 직접 데이터소스로 취급하고, 내용을 SQL을 통해 직접 읽어 읽기 속도가 더 빠르다.
단점: 데이터를 읽는 방법이 유연하지 않고 특정 셀을 직접 읽을 수 없습니다. 전체 Sheet 페이지를 읽은 후에만(결과는 Datatable임) 이를 기반으로 Datatable에서 지정된 값을 얻을 수 있습니다. 행과 열의 수.
엑셀 데이터의 양이 많을 때. 많은 메모리를 차지하며, 메모리가 충분하지 않으면 메모리 오버플로 예외가 발생합니다.
읽는 코드는 다음과 같습니다.
public DataTable GetExcelTableByOleDB(string strExcelPath, string tableName) { try { DataTable dtExcel = new DataTable(); //数据表 DataSet ds = new DataSet(); //获取文件扩展名 string strExtension = System.IO.Path.GetExtension(strExcelPath); string strFileName = System.IO.Path.GetFileName(strExcelPath); //Excel的连接 OleDbConnection objConn = null; switch (strExtension) { case ".xls": objConn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + strExcelPath + ";" + "Extended Properties=\"Excel 8.0;HDR=NO;IMEX=1;\""); break; case ".xlsx": objConn = new OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + strExcelPath + ";" + "Extended Properties=\"Excel 12.0;HDR=NO;IMEX=1;\""); break; default: objConn = null; break; } if (objConn == null) { return null; } objConn.Open(); //获取Excel中所有Sheet表的信息 //System.Data.DataTable schemaTable = objConn.GetOleDbSchemaTable(System.Data.OleDb.OleDbSchemaGuid.Tables, null); //获取Excel的第一个Sheet表名 //string tableName = schemaTable.Rows[0][2].ToString().Trim(); string strSql = "select * from [" + tableName + "]"; //获取Excel指定Sheet表中的信息 OleDbCommand objCmd = new OleDbCommand(strSql, objConn); OleDbDataAdapter myData = new OleDbDataAdapter(strSql, objConn); myData.Fill(ds, tableName);//填充数据 objConn.Close(); //dtExcel即为excel文件中指定表中存储的信息 dtExcel = ds.Tables[tableName]; return dtExcel; } catch { return null; } }
다음은 연결 문자열을 설명합니다.
HDR=Yes, 즉 첫 번째 행은 제목이고 데이터로 사용되지 않습니다. (그러나 실제 사용시 첫 번째 행에 복잡한 값이 있으면 읽은 Datatable 열 제목이 자동으로 F1, F2 등으로 설정되어 일관성이 없습니다. 실제 애플리케이션에서는 HDR=No를 통해 모든 콘텐츠를 Datatable로 읽은 다음 첫 번째 행을 수동으로 제목으로 설정했습니다. IMEX(IMport EXport 모드) 설정
IMEX에는 세 가지 모드가 있습니다.
0은 내보내기 모드
1은 가져오기 모드
2는 연결 모드(전체 업데이트 기능)
여기서 특히 설명하고 싶은 것은 IMEX 매개변수입니다. 모드에 따라 읽기 및 쓰기 동작이 다르기 때문입니다. :
IMEX =0이 "내보내기 모드"인 경우 이 모드에서 열린 Excel 파일은 "쓰기" 목적으로만 사용할 수 있습니다.
IMEX=1이면 "가져오기 모드"입니다. 이 모드에서 열린 Excel 파일은 "읽기" 목적으로만 사용할 수 있습니다.
IMEX=2이면 "링크 모드"입니다. 이 모드에서 열린 Excel 파일은 "읽기" 및 "쓰기" 목적을 모두 지원할 수 있습니다.
----------------------
또 Excel2007도 읽어보세요 파일 버전을 8.0에서 12.0으로 변경해야 합니다. 동시에 드라이버는 더 이상 Jet를 사용할 수 없지만 ACE를 사용해야 합니다. "설치 가능한 ISAM을 찾을 수 없음" 오류의 원인입니다.
----------------------
온라인에서도 찾을 수 있습니다. 방법을 사용하면 검색된 시트 테이블 수가 실제 Excel 테이블의 시트 테이블 수보다 클 수 있습니다. 여기에는 두 가지 이유가 있습니다.
1 추출된 이름에는 XL Naming Manager 이름( XL2007의 공식을 참조하세요. 바로 가기 키 Crtl+F3). 추출된 이름에는 XL에서 필터 범위를 기록하는 데 사용되는 FilterDatabase 접미사가 포함되어 있습니다.
첫 번째 사항은 비교적 간단합니다. 기존 이름 지정 관리자에서 콘텐츠를 삭제하면 됩니다. 두 번째 사항은 필터를 삭제한 후에도 계속 유지됩니다. 새 시트를 추가한 다음 원본 시트를 복사하세요. 그러나 실제 상황에서는 모든 Excel에 대해 위의 검사를 수행할 수 없습니다. 필터링 방식은 아래와 같습니다. (이 문제는 저희가 확인했으니 직접 확인해 주세요)
//objConn为读取Excel的链接,下面通过过滤来获取有效的Sheet页名称集合 System.Data.DataTable schemaTable = objConn.GetOleDbSchemaTable(System.Data.OleDb.OleDbSchemaGuid.Tables, null); List<string> lstSheetNames = new List<string>(); for (int i = 0; i < schemaTable.Rows.Count; i++) { string strSheetName = (string)dtSheetName.Rows[i]["TABLE_NAME"]; if (strSheetName.Contains("$") && !strSheetName.Replace("'", "").EndsWith("$")) { //过滤无效SheetName完毕.... continue; } if (lstSheetNames != null && !lstSheetNames.Contains(strSheetName)) lstSheetNames.Add(strSheetName); }
잘못된 SheetName의 마지막 문자는 일반적으로 $가 아니기 때문입니다. SheetName에 특수 기호가 있으면 읽은 SheetName에 작은따옴표가 자동으로 추가됩니다. 예를 들어 Excel에서 SheetName을 MySheet(1)로 편집하는 경우 읽기 SheetName은 'MySheet(1)$'가 되므로 마지막 문자가 $인지 판단하기 전에 작은따옴표를 필터링하는 것이 가장 좋습니다.
----------------------
(2) Com 컴포넌트 (Microsoft.Office.Interop.Excel 참조를 추가하여 구현)
장점: Excel의 데이터를 매우 유연하게 읽을 수 있으며, 처리를 위한 다양한 기능을 사용자가 유연하게 호출할 수 있습니다.
단점: 셀 기반 처리는 읽기 속도가 느립니다. 이런 식으로 많은 양의 파일을 읽지 않는 것이 가장 좋습니다.
해당 DLL 참조를 추가해야 합니다. 이 참조를 사용하려면 먼저 존재해야 합니다. 웹 사이트가 IIS에 배포된 경우 Excel을 서버 컴퓨터에 설치해야 하며 경우에 따라 IIS 권한이 필요합니다. 구성됩니다.
읽는 코드는 다음과 같습니다.
private Stopwatch wath = new Stopwatch(); /// <summary> /// 使用COM读取Excel /// </summary> /// <param name="excelFilePath">路径</param> /// <returns>DataTabel</returns> public System.Data.DataTable GetExcelData(string excelFilePath) { Excel.Application app = new Excel.Application(); Excel.Sheets sheets; Excel.Workbook workbook = null; object oMissiong = System.Reflection.Missing.Value; System.Data.DataTable dt = new System.Data.DataTable(); wath.Start(); try { if (app == null) { return null; } workbook = app.Workbooks.Open(excelFilePath, oMissiong, oMissiong, oMissiong, oMissiong, oMissiong, oMissiong, oMissiong, oMissiong, oMissiong, oMissiong, oMissiong, oMissiong, oMissiong, oMissiong); //将数据读入到DataTable中——Start sheets = workbook.Worksheets; Excel.Worksheet worksheet = (Excel.Worksheet)sheets.get_Item(1);//读取第一张表 if (worksheet == null) return null; string cellContent; int iRowCount = worksheet.UsedRange.Rows.Count; int iColCount = worksheet.UsedRange.Columns.Count; Excel.Range range; //负责列头Start DataColumn dc; int ColumnID = 1; range = (Excel.Range)worksheet.Cells[1, 1]; while (range.Text.ToString().Trim() != "") { dc = new DataColumn(); dc.DataType = System.Type.GetType("System.String"); dc.ColumnName = range.Text.ToString().Trim(); dt.Columns.Add(dc); range = (Excel.Range)worksheet.Cells[1, ++ColumnID]; } //End for (int iRow = 2; iRow <= iRowCount; iRow++) { DataRow dr = dt.NewRow(); for (int iCol = 1; iCol <= iColCount; iCol++) { range = (Excel.Range)worksheet.Cells[iRow, iCol]; cellContent = (range.Value2 == null) ? "" : range.Text.ToString(); dr[iCol - 1] = cellContent; } dt.Rows.Add(dr); } wath.Stop(); TimeSpan ts = wath.Elapsed; //将数据读入到DataTable中——End return dt; } catch { return null; } finally { workbook.Close(false, oMissiong, oMissiong); System.Runtime.InteropServices.Marshal.ReleaseComObject(workbook); workbook = null; app.Workbooks.Close(); app.Quit(); System.Runtime.InteropServices.Marshal.ReleaseComObject(app); app = null; GC.Collect(); GC.WaitForPendingFinalizers(); } } /// <summary> /// 使用COM,多线程读取Excel(1 主线程、4 副线程) /// </summary> /// <param name="excelFilePath">路径</param> /// <returns>DataTabel</returns> public System.Data.DataTable ThreadReadExcel(string excelFilePath) { Excel.Application app = new Excel.Application(); Excel.Sheets sheets = null; Excel.Workbook workbook = null; object oMissiong = System.Reflection.Missing.Value; System.Data.DataTable dt = new System.Data.DataTable(); wath.Start(); try { if (app == null) { return null; } workbook = app.Workbooks.Open(excelFilePath, oMissiong, oMissiong, oMissiong, oMissiong, oMissiong, oMissiong, oMissiong, oMissiong, oMissiong, oMissiong, oMissiong, oMissiong, oMissiong, oMissiong); //将数据读入到DataTable中——Start sheets = workbook.Worksheets; Excel.Worksheet worksheet = (Excel.Worksheet)sheets.get_Item(1);//读取第一张表 if (worksheet == null) return null; string cellContent; int iRowCount = worksheet.UsedRange.Rows.Count; int iColCount = worksheet.UsedRange.Columns.Count; Excel.Range range; //负责列头Start DataColumn dc; int ColumnID = 1; range = (Excel.Range)worksheet.Cells[1, 1]; while (iColCount >= ColumnID) { dc = new DataColumn(); dc.DataType = System.Type.GetType("System.String"); string strNewColumnName = range.Text.ToString().Trim(); if (strNewColumnName.Length == 0) strNewColumnName = "_1"; //判断列名是否重复 for (int i = 1; i < ColumnID; i++) { if (dt.Columns[i - 1].ColumnName == strNewColumnName) strNewColumnName = strNewColumnName + "_1"; } dc.ColumnName = strNewColumnName; dt.Columns.Add(dc); range = (Excel.Range)worksheet.Cells[1, ++ColumnID]; } //End //数据大于500条,使用多进程进行读取数据 if (iRowCount - 1 > 500) { //开始多线程读取数据 //新建线程 int b2 = (iRowCount - 1) / 10; DataTable dt1 = new DataTable("dt1"); dt1 = dt.Clone(); SheetOptions sheet1thread = new SheetOptions(worksheet, iColCount, 2, b2 + 1, dt1); Thread othread1 = new Thread(new ThreadStart(sheet1thread.SheetToDataTable)); othread1.Start(); //阻塞 1 毫秒,保证第一个读取 dt1 Thread.Sleep(1); DataTable dt2 = new DataTable("dt2"); dt2 = dt.Clone(); SheetOptions sheet2thread = new SheetOptions(worksheet, iColCount, b2 + 2, b2 * 2 + 1, dt2); Thread othread2 = new Thread(new ThreadStart(sheet2thread.SheetToDataTable)); othread2.Start(); DataTable dt3 = new DataTable("dt3"); dt3 = dt.Clone(); SheetOptions sheet3thread = new SheetOptions(worksheet, iColCount, b2 * 2 + 2, b2 * 3 + 1, dt3); Thread othread3 = new Thread(new ThreadStart(sheet3thread.SheetToDataTable)); othread3.Start(); DataTable dt4 = new DataTable("dt4"); dt4 = dt.Clone(); SheetOptions sheet4thread = new SheetOptions(worksheet, iColCount, b2 * 3 + 2, b2 * 4 + 1, dt4); Thread othread4 = new Thread(new ThreadStart(sheet4thread.SheetToDataTable)); othread4.Start(); //主线程读取剩余数据 for (int iRow = b2 * 4 + 2; iRow <= iRowCount; iRow++) { DataRow dr = dt.NewRow(); for (int iCol = 1; iCol <= iColCount; iCol++) { range = (Excel.Range)worksheet.Cells[iRow, iCol]; cellContent = (range.Value2 == null) ? "" : range.Text.ToString(); dr[iCol - 1] = cellContent; } dt.Rows.Add(dr); } othread1.Join(); othread2.Join(); othread3.Join(); othread4.Join(); //将多个线程读取出来的数据追加至 dt1 后面 foreach (DataRow dr in dt.Rows) dt1.Rows.Add(dr.ItemArray); dt.Clear(); dt.Dispose(); foreach (DataRow dr in dt2.Rows) dt1.Rows.Add(dr.ItemArray); dt2.Clear(); dt2.Dispose(); foreach (DataRow dr in dt3.Rows) dt1.Rows.Add(dr.ItemArray); dt3.Clear(); dt3.Dispose(); foreach (DataRow dr in dt4.Rows) dt1.Rows.Add(dr.ItemArray); dt4.Clear(); dt4.Dispose(); return dt1; } else { for (int iRow = 2; iRow <= iRowCount; iRow++) { DataRow dr = dt.NewRow(); for (int iCol = 1; iCol <= iColCount; iCol++) { range = (Excel.Range)worksheet.Cells[iRow, iCol]; cellContent = (range.Value2 == null) ? "" : range.Text.ToString(); dr[iCol - 1] = cellContent; } dt.Rows.Add(dr); } } wath.Stop(); TimeSpan ts = wath.Elapsed; //将数据读入到DataTable中——End return dt; } catch { return null; } finally { workbook.Close(false, oMissiong, oMissiong); System.Runtime.InteropServices.Marshal.ReleaseComObject(workbook); System.Runtime.InteropServices.Marshal.ReleaseComObject(sheets); workbook = null; app.Workbooks.Close(); app.Quit(); System.Runtime.InteropServices.Marshal.ReleaseComObject(app); app = null; GC.Collect(); GC.WaitForPendingFinalizers(); } }
(3) NPOI 모드에서 Excel 읽기(이 방법은 테스트되지 않았습니다.)
NPOI는 POI 프로젝트의 .NET 버전입니다. POI는 Excel, WORD 및 기타 Microsoft OLE2 구성 요소 문서를 읽고 쓰기 위한 오픈 소스 Java 프로젝트입니다. NPOI를 이용하면 Office가 설치되지 않은 기기나 해당 환경에서 WORD/EXCEL 문서를 읽고 쓸 수 있습니다.
장점: 엑셀 읽기 속도 향상, 유연한 읽기 방식
단점: 해당 플러그인을 다운받아 시스템 레퍼런스에 추가해야 한다.
/// <summary> /// 将excel中的数据导入到DataTable中 /// </summary> /// <param name="sheetName">excel工作薄sheet的名称</param> /// <param name="isFirstRowColumn">第一行是否是DataTable的列名</param> /// <returns>返回的DataTable</returns> public DataTable ExcelToDataTable(string sheetName, bool isFirstRowColumn) { ISheet sheet = null; DataTable data = new DataTable(); int startRow = 0; try { fs = new FileStream(fileName, FileMode.Open, FileAccess.Read); if (fileName.IndexOf(".xlsx") > 0) // 2007版本 workbook = new XSSFWorkbook(fs); else if (fileName.IndexOf(".xls") > 0) // 2003版本 workbook = new HSSFWorkbook(fs); if (sheetName != null) { sheet = workbook.GetSheet(sheetName); } else { sheet = workbook.GetSheetAt(0); } if (sheet != null) { IRow firstRow = sheet.GetRow(0); int cellCount = firstRow.LastCellNum; //一行最后一个cell的编号 即总的列数 if (isFirstRowColumn) { for (int i = firstRow.FirstCellNum; i < cellCount; ++i) { DataColumn column = new DataColumn(firstRow.GetCell(i).StringCellValue); data.Columns.Add(column); } startRow = sheet.FirstRowNum + 1; } else { startRow = sheet.FirstRowNum; } //最后一列的标号 int rowCount = sheet.LastRowNum; for (int i = startRow; i <= rowCount; ++i) { IRow row = sheet.GetRow(i); if (row == null) continue; //没有数据的行默认是null DataRow dataRow = data.NewRow(); for (int j = row.FirstCellNum; j < cellCount; ++j) { if (row.GetCell(j) != null) //同理,没有数据的单元格都默认是null dataRow[j] = row.GetCell(j).ToString(); } data.Rows.Add(dataRow); } } return data; } catch (Exception ex) { Console.WriteLine("Exception: " + ex.Message); return null; } }
C#에서 Excel을 읽는 세 가지 방법과 비교 분석에 대한 더 많은 기사를 보려면 PHP 중국어 웹사이트를 주목하세요!

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

Video Face Swap
완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











C 언어 커버 산술, 할당, 조건, 논리, 비트 연산자 등의 기호의 사용 방법은 기본 수학 연산에 사용되며, 할당 연산자는 할당 및 추가, 곱하기, 분할 할당에 사용되며, 곱하기 및 분할 할당에 사용되며, 조건에 따라 조건 운영자가 사용되며, 비트 오퍼레이터에 사용되며, 스페셜 오퍼레이터는 비트 수준의 운영에 사용됩니다. 포인터, 파일 종료 마커 및 비수통 값.

C에서 숯 유형은 문자열에 사용됩니다. 1. 단일 문자를 저장하십시오. 2. 배열을 사용하여 문자열을 나타내고 널 터미네이터로 끝납니다. 3. 문자열 작동 함수를 통해 작동합니다. 4. 키보드에서 문자열을 읽거나 출력하십시오.

C 언어에서 특수 문자는 다음과 같은 탈출 시퀀스를 통해 처리됩니다. \ n 라인 브레이크를 나타냅니다. \ t는 탭 문자를 의미합니다. char c = '\ n'과 같은 특수 문자를 나타 내기 위해 탈출 시퀀스 또는 문자 상수를 사용하십시오. 백 슬래시는 두 번 탈출해야합니다. 다른 플랫폼과 컴파일러마다 다른 탈출 시퀀스가있을 수 있습니다. 문서를 참조하십시오.

멀티 스레딩과 비동기식의 차이점은 멀티 스레딩이 동시에 여러 스레드를 실행하는 반면, 현재 스레드를 차단하지 않고 비동기식으로 작업을 수행한다는 것입니다. 멀티 스레딩은 컴퓨팅 집약적 인 작업에 사용되며 비동기식은 사용자 상호 작용에 사용됩니다. 멀티 스레딩의 장점은 컴퓨팅 성능을 향상시키는 것이지만 비동기의 장점은 UI 스레드를 차단하지 않는 것입니다. 멀티 스레딩 또는 비동기식을 선택하는 것은 작업의 특성에 따라 다릅니다. 계산 집약적 작업은 멀티 스레딩을 사용하고 외부 리소스와 상호 작용하고 UI 응답 성을 비동기식으로 유지 해야하는 작업을 사용합니다.

C 언어에서 char와 wchar_t의 주요 차이점은 문자 인코딩입니다. char ascii를 사용하거나 ascii를 확장하고, wchar_t는 유니 코드를 사용합니다. Char는 1-2 바이트를 차지하고 WCHAR_T는 2-4 바이트를 차지합니다. Char는 영어 텍스트에 적합하며 WCHAR_T는 다국어 텍스트에 적합합니다. Char_t는 널리 지원되며, 컴파일러 및 운영 체제가 유니 코드를 지원하는지 여부에 따라 다릅니다. Char는 문자 범위가 제한되며 WCHAR_T는 더 큰 문자 범위를 가지며 특수 함수는 산술 작업에 사용됩니다.

C 언어에서 숯 유형 변환은 다른 유형으로 직접 변환 할 수 있습니다. 캐스팅 : 캐스팅 캐릭터 사용. 자동 유형 변환 : 한 유형의 데이터가 다른 유형의 값을 수용 할 수 있으면 컴파일러가 자동으로 변환됩니다.

Char 및 Unsigned Char는 문자 데이터를 저장하는 두 가지 데이터 유형입니다. 주요 차이점은 음수 및 양수를 다루는 방법입니다. 음수 처리 : char는 부정확 한 char가 할 수없고 음수를 저장할 수 있습니다. 비트 모드 : char 가장 높은 비트는 기호, 부호없는 문자 부호 비트를 나타냅니다. 산술 연산 : char and signed char는 서명하고 서명되지 않은 유형이며, 산술 작업은 다릅니다. 호환성 : 문자와 서명되지 않은 숯

C 언어에서 char를 사용하기위한 오류 및 회피 방법 : 초기화되지 않은 char 변수 : 상수 또는 문자열 리터럴을 사용하여 초기화. 문자 범위를 벗어나 : 변수 값이 유효 범위 (-128 ~ 127) 내에 있는지 비교하십시오. 문자 비교는 대소 문자를 사용하지 않습니다. toupper () 또는 tolower ()를 사용하여 문자 케이스를 변환합니다. char*: strlen ()을 사용하여 문자 배열을 참조 할 때 '\ 0'은 추가되지 않습니다. char 배열을 사용할 때 배열 크기를 무시하십시오. 배열 크기를 명시 적으로 지정하거나 ()를 사용하여 길이를 결정하십시오. Char Pointer를 사용할 때는 Null 포인터가 확인되지 않습니다. 사용하기 전에 포인터가 Null인지 확인하십시오. Char Pointer를 사용하여 비 특가자 데이터를 가리 키십시오
