using System; using System.Collections.Generic; using System.Data; using System.IO; using System.Linq; using System.Text.RegularExpressions; namespace bdf { class CXLFile { //public static List ServiceOrders = new List { }; public static List S_ServiceOrders = new List { }; public static void S_getXLS(string task, string dir) { //string folderPath = dir; string filePrefix1 = "ROGERS_"; string filePrefix2 = task + "_SO"; var excelFiles = getLatestVersionFiles(dir, filePrefix1, filePrefix2); if ( (excelFiles.Length == 0) || (excelFiles == null) ) { Console.WriteLine("No Excel files found with prefix: " + filePrefix1 + "*" + filePrefix2); //throw new System.ArgumentNullException("filePaths"); return; } foreach (string path in excelFiles) { if (string.IsNullOrWhiteSpace(path)) continue; if (!System.IO.File.Exists(path)) throw new System.IO.FileNotFoundException( "Excel file not found.", path); Logger.Log(1, "Scanning: {0}", Path.GetFileName(path)); // Create a new workbook and load the file Spire.Xls.Workbook wb = new Spire.Xls.Workbook(); //straight up load from file //wb.LoadFromFile(path); // FreeSpire autodetects .xls vs .xlsx //more network savvy way that handles sharepoint's idiosyncrasies FileStream stream = null; // OneDrive sync engine frequently locks files briefly: const int maxRetries = 12; const int retryDelayMs = 150; for (int i = 0; i < maxRetries; i++) { try { stream = new FileStream( path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete ); break; // opened successfully } catch (IOException) { if (i == maxRetries - 1) throw; System.Threading.Thread.Sleep(retryDelayMs); } } wb.LoadFromStream(stream); Logger.Log(5, " -loaded SO={0}", wb.Worksheets[1][2, 1].Value.ToString() ); S_ServiceOrders.Add(wb); } Logger.Log("All SO Excel files processed successfully."); return; // S_ServiceOrders; } // This routine is wholly dependent on the filename structure being ROGERS*LDF*_SO*VER*number // in future should just open each workbook and read exact version from the first worksheet. public static string[] getLatestVersionFiles(string folder, string prefixA, string prefixB) { var files = Directory.GetFiles(folder); // Build wildcard pattern: // file must contain prefixA ... anything ... prefixB Func matchesPrefix = name => name.IndexOf(prefixA, StringComparison.OrdinalIgnoreCase) >= 0 && name.IndexOf(prefixB, StringComparison.OrdinalIgnoreCase) > name.IndexOf(prefixA, StringComparison.OrdinalIgnoreCase); var filtered = files .Where(f => matchesPrefix(Path.GetFileName(f))) .ToList(); // Serial = 6 digits // After "VER" allow ANY non-digit characters, then the version number var regex = new Regex( @"(?\d{6}).*?VER\D*(?\d+)", RegexOptions.IgnoreCase ); Dictionary best = new Dictionary(); foreach (var file in files) { string name = Path.GetFileName(file); var match = regex.Match(name); if (!match.Success) { Logger.Log(1, " Did not find SO and Version for file {0}", name); continue; } string serial = match.Groups["serial"].Value; if (!int.TryParse(match.Groups["ver"].Value, out int ver)) { Logger.Log(1, " Did not extract Version for file {0}", name); continue; } // Keep highest version per serial if (!best.ContainsKey(serial)) // || ver > best[serial].version) { best[serial] = (ver, file); Logger.Log(5, " Adding: {0} ver {1}", serial, ver); } else if (ver > best[serial].version) { Logger.Log(2, " Replacing: {0} ver {1} with ver {2}", serial, best[serial].version, ver); best[serial] = (ver, file); } else { Logger.Log(4, " Ignoring: {0} v.{1}", serial, ver); } } return best.Values.Select(v => v.file).ToArray(); } /* public static void getXLS(string task, string dir) { //string folderPath = @"C:\Data\ExcelFiles"; // Folder to scan string folderPath = dir; string filePrefix1 = "ROGERS_"; string filePrefix2 = task + "_SO"; //List ServiceOrders = new List { }; try { // Required for ExcelDataReader in .NET 4 System.Text.Encoding.RegisterProvider( System.Text.CodePagesEncodingProvider.Instance); // Get all Excel files that match the prefix //var excelFiles = Directory.GetFiles(folderPath, filePrefix1 + "*" + filePrefix2 + "*.xls*", SearchOption.TopDirectoryOnly); var excelFiles = getLatestVersionFiles(dir, filePrefix1, filePrefix2); if (excelFiles.Length == 0) { Console.WriteLine("No Excel files found with prefix: " + filePrefix1 + "*" + filePrefix2); return; } DataSet _dataSet = null; foreach (var filePath in excelFiles) { Logger.Log(1, "Scanning: {0}", Path.GetFileName(filePath)); // DataSet dataSet = ReadExcelFile(filePath); // STEP 1: Read file into DataSet using ExcelDataReader try { _dataSet = ReadExcelFile(filePath); //_dataSet = LoadOneDriveDataSet(filePath); } catch { try { _dataSet = LoadOneDriveDataSet(filePath); } catch (Exception e) { Logger.Log(0, "Error trying to access file {0}. ({1})", filePath, e.Message); } } // STEP 2: Convert DataSet into a ClosedXML workbook for manipulation var workbook = new XLWorkbook(); //using (var workbook = new XLWorkbook()) { foreach (DataTable table in _dataSet.Tables) { var worksheet = workbook.Worksheets.Add(table.TableName); // Insert headers for (int col = 0; col < table.Columns.Count; col++) { worksheet.Cell(1, col + 1).Value = table.Columns[col].ColumnName; worksheet.Cell(1, col + 1).Style.Font.Bold = true; } // Insert rows for (int row = 0; row < table.Rows.Count; row++) { for (int col = 0; col < table.Columns.Count; col++) { //Logger.Log(5, "type is {0}", table.Rows[row][col].GetType().Name); string valuetype = table.Rows[row][col].GetType().Name; if (valuetype == "Int32") { worksheet.Cell(row + 2, col + 1).Value = (Int32)table.Rows[row][col]; } else if (valuetype == "String") { worksheet.Cell(row + 2, col + 1).Value = (String)table.Rows[row][col]; } else if (valuetype == "Decimal") { worksheet.Cell(row + 2, col + 1).Value = (Decimal)table.Rows[row][col]; } else if (valuetype == "Double") { worksheet.Cell(row + 2, col + 1).Value = (Double)table.Rows[row][col]; } else if (valuetype == "DBNull") { worksheet.Cell(row + 2, col + 1).Value = ""; } else { worksheet.Cell(row + 2, col + 1).Value = "fix me"; } //worksheet.Cell(row + 2, col + 1).Value = table.Rows[row][col]; } } worksheet.Columns().AdjustToContents(); //Logger.Log(0, "Sheet{0} Value={1}", workbook.Worksheets.Count, workbook.Worksheet(workbook.Worksheets.Count).Cell("C2").Value); } // Example: Save modified workbook (optional) string outputFile = Path.Combine(folderPath, "" + Path.GetFileName(filePath) + "x"); //workbook.SaveAs(outputFile); Logger.Log(7, "Processed file: {0}", outputFile); //Logger.Log(0, "Book has {0} sheets", workbook.Worksheets.Count ); CXLFile.ServiceOrders.Add(workbook); //Logger.Log("test: " + workbook.Worksheet(1).Cell("C2").Value); } //Logger.Log("Finished: " + Path.GetFileName(filePath)); //Logger.Log(new string('-', 50)); } Logger.Log("All SO Excel files processed successfully."); } catch (Exception ex) { Logger.Log(0, "SO processing error: {0}" + ex.Message); //Logger.Log("Press any key to exit..."); //Console.ReadKey(); } // //return ServiceOrders; } /// /// Reads an Excel file into a DataSet using ExcelDataReader. /// Each worksheet becomes a DataTable. /// static DataSet ReadExcelFile(string filePath) { // Required for ExcelDataReader to process XLS files System.Text.Encoding.RegisterProvider( System.Text.CodePagesEncodingProvider.Instance); using (var stream = System.IO.File.Open(filePath, FileMode.Open, FileAccess.Read)) { IExcelDataReader reader; // Auto-detect format (XLS or XLSX) if (Path.GetExtension(filePath).Equals(".xls", StringComparison.OrdinalIgnoreCase)) reader = ExcelReaderFactory.CreateBinaryReader(stream); else reader = ExcelReaderFactory.CreateOpenXmlReader(stream); // Convert to DataSet (with first row as header) var result = reader.AsDataSet(new ExcelDataSetConfiguration() { ConfigureDataTable = _ => new ExcelDataTableConfiguration() { UseHeaderRow = true } }); reader.Close(); return result; } } public static DataSet LoadOneDriveDataSet(string path) { if (!System.IO.File.Exists(path)) throw new FileNotFoundException("OneDrive file not found.", path); // Required for ExcelDataReader to process XLS files System.Text.Encoding.RegisterProvider( System.Text.CodePagesEncodingProvider.Instance); FileStream stream = null; // OneDrive sync engine frequently locks files briefly: const int maxRetries = 12; const int retryDelayMs = 150; for (int i = 0; i < maxRetries; i++) { try { stream = new FileStream( path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete ); break; // opened successfully } catch (IOException) { if (i == maxRetries - 1) throw; System.Threading.Thread.Sleep(retryDelayMs); } } // STEP 1: Read the workbook into a DataSet (ExcelDataReader) DataSet dataSet; using (var reader = ExcelReaderFactory.CreateReader(stream)) { dataSet = reader.AsDataSet(new ExcelDataSetConfiguration { ConfigureDataTable = _ => new ExcelDataTableConfiguration { UseHeaderRow = true } }); } return dataSet; } */ } }