Exception handling in reading excel files, C# - c#

I am fairly new to C# coding, and recently I read that it is better to use Try Catch than if/else for file I/O related matters. I also read in other threads that try catch block should be avoided in loops because they significantly lower performances.
In my case, I am reading multiple (often over 1,000) excel files using for loop. Currently, I am using if/else if to handle really basic exceptions (i.e. file exist or not), but I was thinking of implementing try catch for the reason I explained above.
Here's some of my code
public void ReadFile(string path)
{
Excel.Application xlApp;
Excel.Workbooks xlBooks;
Excel.Workbook xlBook;
Excel.Worksheet xlSheet;
xlApp = new Excel.Application();
xlBooks = xlApp.Workbooks;
xlBook = xlBooks.Open(path);
xlSheet = xlBook.Sheets[1];
int rowCount = FindLastRow(xlSheet);
int colCount = FindLastColumn(xlSheet);
string header = "";
string glNum = Path.GetFileNameWithoutExtension(path).Trim();
for (int row = 1; row <= rowCount; row++)
{
bool processDone = false;
string curationInfo = "";
List<string> data = new List<string>();
// If empty line, skip
if (IsEmpty(xlSheet, row, colCount)) continue;
// If header line, capture
if (IsHeader(xlSheet, row, colCount) != "")
{
header = IsHeader(xlSheet, row, colCount);
continue;
}
// If coloured line, capture
if (IsColoured(xlSheet, row, colCount))
{
curationInfo = ConstructCurationInfo(xlSheet, row, colCount);
data.Add(curationInfo);
// If last row, end
if (row == rowCount) processDone = true;
while (!processDone)
{
// If last row
if (row == rowCount)
{
// If last row is empty, one section is done
if (IsEmpty(xlSheet, row, colCount)) processDone = true;
// If last row is header, one section is done
else if (IsHeader(xlSheet, row, colCount) != "") processDone = true;
// Every other case
else
{
// if coloured, capture
if (IsColoured(xlSheet, row, colCount))
{
string newCurationInfo = ConstructCurationInfo(xlSheet, row, colCount);
data.Add(newCurationInfo);
}
processDone = true;
}
}
// If not last row
else
{
int nextRow = row + 1;
// If next row is last row, end
if (nextRow == rowCount) processDone = true;
// If next row is empty, one section is done
if (IsEmpty(xlSheet, nextRow, colCount)) processDone = true;
// If next row is header, one section is done
else if (IsHeader(xlSheet, nextRow, colCount) != "") processDone = true;
// Every other case
else
{
// if coloured, capture
if (IsColoured(xlSheet, nextRow, colCount))
{
string newCurationInfo = ConstructCurationInfo(xlSheet, nextRow, colCount);
data.Add(newCurationInfo);
}
row++;
}
}
}
}
if (processDone && data.Count != 0)
{
Curation cur = new Curation(header, data, glNum);
curationList.Add(cur);
}
}
// Terminate background Excel Workers
xlBook.Close(false, Missing.Value, Missing.Value);
xlBooks.Close();
xlApp.Quit();
xlApp.DisplayAlerts = false;
Marshal.ReleaseComObject(xlSheet);
Marshal.ReleaseComObject(xlBook);
Marshal.ReleaseComObject(xlBooks);
Marshal.ReleaseComObject(xlApp);
GC.WaitForPendingFinalizers();
GC.Collect();
}
And the Form method that uses ReadFile() method
// Background workers
private void mergeNew_bgw_DoWork(object sender, DoWorkEventArgs e)
{
string input_path = db_input_tb.Text;
string output_dir_path = output_tb.Text;
// Status message to be reported to the UI
string status = "";
status = "Collecting files to be read.....";
mergeNew_bgw.ReportProgress(0, status);
List<string> excelPaths = GetPathToExcel(input_path);
if (IsEmpty(excelPaths))
{
status = "No File to be Processed!";
mergeNew_bgw.ReportProgress(0, status);
fileToProcess = false;
}
// If not empty list, process
else
{
ExcelInfo info = new ExcelInfo();
bool doesExist = false;
string path = "";
int row = 1;
for (int i = 0; i < excelPaths.Count; i++)
{
status = "Processing....." + (i + 1).ToString() + "/" + excelPaths.Count.ToString();
mergeNew_bgw.ReportProgress(0, status);
info.ReadFile(excelPaths[i]);
// If last file, write excel file
if (i + 1 == excelPaths.Count)
{
status = "Writing Complete Merged File";
mergeNew_bgw.ReportProgress(0, status);
info.WriteNew(ref doesExist, ref row, ref path, output_dir_path);
info.Clear();
}
else if ((i + 1) % cutoff == 0)
{
status = "Writing Partial Merged File";
mergeNew_bgw.ReportProgress(0, status);
info.WriteNew(ref doesExist, ref row, ref path, output_dir_path);
info.Clear();
}
}
}
}
Should I implement try catch block inside the for loop in mergeNew_bgw_DoWork method like this?
for (int i = 0; i < excelPaths.Count; i++)
{
status = "Processing....." + (i + 1).ToString() + "/" + excelPaths.Count.ToString();
mergeNew_bgw.ReportProgress(0, status);
try
{
info.ReadFile(excelPaths[i]);
}
catch(Exception e)
{
throw new Exception(e.ToString());
}
finally
{
// If last file, write excel file
if (i + 1 == excelPaths.Count)
{
status = "Writing Complete Merged File";
mergeNew_bgw.ReportProgress(0, status);
info.WriteNew(ref doesExist, ref row, ref path, output_dir_path);
info.Clear();
}
else if ((i + 1) % cutoff == 0)
{
status = "Writing Partial Merged File";
mergeNew_bgw.ReportProgress(0, status);
info.WriteNew(ref doesExist, ref row, ref path, output_dir_path);
info.Clear();
}
}
}
Thank you for your help!
EDIT
Apparently, performance will not change that much as pointed by one of the comments. However, where should I insert try catch block in order to get meaningful error messages? ReadFile() method is big, so I think putting the entire method in try block may not give users meaning error messages. Would it be better to insert try catch somewhere inside ReadFile() method?

Related

Appending one spreadsheet to another with NPOI with CellStyling included

I'm trying to read one file and append it onto another with the cell styling included. All problems seem to be stemming from the inner foreach loop and I have asterisked the line giving the error.
The problem with this code is that:
An unhandled exception of type 'System.ArgumentException' occurred in NPOI.OOXML.dll
Additional information: This Style does not belong to the supplied Workbook Stlyes Source. Are you trying to assign a style from one workbook to the cell of a differnt workbook?
private void AddCellFooter(ref ISheet quoteSheet,string brandName, int lastRowIndex, ref IWorkbook quoteWorkbook )
{
FileStream sw = null;
if (File.Exists("Quote Templates\\" + brandName + "MasterFooter.xlsx"))
{
IRow currentRow;
ICell currentCell;
ICellStyle currentStyle;
int cellIndex;
sw = File.OpenRead("Quote Templates\\" + brandName + "MasterFooter.xlsx");
IWorkbook footerWorkBook = WorkbookFactory.Create(sw);
ISheet footerSheet = footerWorkBook.GetSheet("Sheet1");
foreach (IRow footerRow in footerSheet)
{
cellIndex = 0;
currentRow = quoteSheet.CreateRow(lastRowIndex);
foreach (ICell footerCell in footerRow)
{
currentCell = currentRow.CreateCell(cellIndex,footerCell.CellType);
currentCell.SetCellValue(footerCell.StringCellValue);
currentStyle = quoteWorkbook.CreateCellStyle();
currentStyle = footerCell.CellStyle;
******currentCell.CellStyle = currentStyle;******
cellIndex++;
}
lastRowIndex++;
}
sw.Close();
}
}
What this is supposed to do is read through all the cells in the footer spreadsheet and write them onto the quotesheet. The first two lines of the foreach loop work fine so I can write the text in the footer but I can't find a way to preserve stylings when copying it across.
I have tried setting the foreach loop to just be
foreach (ICell footerCell in footerRow)
{
currentCell = currentRow.CreateCell(cellIndex,footerCell.CellType);
currentCell = footerCell;
cellIndex++;
}
But that just produced empty cells.
Any help would be greatly appreciated,
Thanks
If anyone needs this in the future
this works correctly: (footerHeight and footerWidth are the dimensions of the spreadsheet to be appended)
for (int i = 0; i < footerHeight; i++)
{
currentRow = quoteSheet.CreateRow(i + lastRowIndex);
for (int j = 0; j < footerWidth; j++)
{
CellType ct = footerSheet.GetRow(i).GetCell(j)?.CellType ?? CellType.Blank;
if (ct != CellType.Unknown)
{
ICell footerCell = footerSheet.GetRow(i).GetCell(j);
switch (ct)
{
case CellType.Unknown:
break;
case CellType.Numeric:
currentCell = currentRow.CreateCell(j, CellType.Numeric);
currentCell.SetCellValue(footerCell.NumericCellValue);
break;
case CellType.String:
currentCell = currentRow.CreateCell(j, CellType.String);
currentCell.SetCellValue(footerCell.StringCellValue);
break;
case CellType.Formula:
break;
case CellType.Blank:
currentCell = currentRow.CreateCell(j, CellType.String);
currentCell.SetCellValue("");
break;
case CellType.Boolean:
break;
case CellType.Error:
break;
default:
break;
}
currentStyle = quoteWorkbook.CreateCellStyle();
if (footerCell != null)
{
currentStyle.CloneStyleFrom(footerCell.CellStyle);
}
currentCell.CellStyle = currentStyle;
}
}
}
With the main new feature being
currentStyle.CloneStyleFrom(footerCell.CellStyle);
As apparently CellStyles are quite complex so a special command is required to copy across workbooks.

Unmerge and clear cells in epplus 4.1

I had no luck deleting rows in excel so now I try to clear their content and still get the error:
"Can't delete/overwrite merged cells. A range is partly merged with the another merged range. A57788:J57788".
Columns 1-10 are really merged, but how do I unmerge them?
Here's my code:
cntr = 0;
while (ws.Cells[RowNum + cntr, 1].Value == null || !ws.Cells[RowNum + cntr, 1].Value.ToString().StartsWith("Report generation date"))
{
ws.Cells[RowNum + cntr, 1, RowNum + cntr, 18].Value = "";
ws.Cells[RowNum + cntr, 1, RowNum + cntr, 10].Merge = false;
for (int i = 1; i < 17; i++)
{
ws.Cells[RowNum + cntr, i].Style.Border.BorderAround(OfficeOpenXml.Style.ExcelBorderStyle.None);
ws.Cells[RowNum + cntr, i].Clear();
}
cntr++;
}
//ws.DeleteRow(RowNum, cntr);
The thing is you can not unmerge a single cell in a range, you have to unmerge the whole range.
To do that you can get the merged range that a cell belongs to using my solution here:
public string GetMergedRange(ExcelWorksheet worksheet, string cellAddress)
{
ExcelWorksheet.MergeCellsCollection mergedCells = worksheet.MergedCells;
foreach (var merged in mergedCells)
{
ExcelRange range = worksheet.Cells[merged];
ExcelCellAddress cell = new ExcelCellAddress(cellAddress);
if (range.Start.Row<=cell.Row && range.Start.Column <= cell.Column)
{
if (range.End.Row >= cell.Row && range.End.Column >= cell.Column)
{
return merged.ToString();
}
}
}
return "";
}
The second step is unmerging the whole range using:
public void DeleteCell(ExcelWorksheet worksheet, string cellAddress)
{
if (worksheet.Cells[cellAddress].Merge == true)
{
string range = GetMergedRange(worksheet, cellAddress); //get range of merged cells
worksheet.Cells[range].Merge = false; //unmerge range
worksheet.Cells[cellAddress].Clear(); //clear value
}
}
This way will cost you to lose merging of the other cells, and their value, to overcome this you can save value before clearing and unmerging then you can write it back, something like:
public void DeleteCell(ExcelWorksheet worksheet, string cellAddress)
{
if (worksheet.Cells[cellAddress].Merge == true)
{
var value = worksheet.Cells[cellAddress].Value;
string range = GetMergedRange(worksheet, cellAddress); //get range of merged cells
worksheet.Cells[range].Merge = false; //unmerge range
worksheet.Cells[cellAddress].Clear(); //clear value
//merge the cells you want again.
//fill the value in cells again
}
}

Try...catch returning nothing but code is still breaking

UPDATE: So this code is collection a SQL Query into a DataSet prior to this method. This data set is then dropped into excel in the corresponding tab at a specific cell address(which is loaded from the form) but the code below is the exporting to excel method. I am getting the following error:
An unhandled exception of type 'System.AccessViolationException' occurred in SQUiRE (Sql QUery REtriever) v1.exe
Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
I have been tracking this for a while and thought I fixed it, but my solution was a false positive. So I am using a try...catch block that is breaking but not returning anything. Let me know if you all see anything that I am missing. I usually break on this line (templateSheet = templateBook.Sheets[tabName];) and on the same tabName. The tab is not locked or restricted so It can be written to and works more than half of the time.
public void ExportToExcel(DataSet dataSet, Excel.Workbook templateBook, int i, int h, Excel.Application excelApp) //string filePath,
{
try
{
lock (this.GetType())
{
Excel.Worksheet templateSheet;
//check to see if the template is already open, if its not then open it,
//if it is then bind it to work with it
//if (!fileOpenTest)
//{ templateBook = excelApp.Workbooks.Open(filePath); }
//else
//{ templateBook = (Excel.Workbook)System.Runtime.InteropServices.Marshal.BindToMoniker(filePath); }
//Grabs the name of the tab to dump the data into from the "Query Dumps" Tab
string tabName = lstQueryDumpSheet.Items[i].ToString();
templateSheet = templateBook.Sheets[tabName];
// Copy DataTable
foreach (System.Data.DataTable dt in dataSet.Tables)
{
// Copy the DataTable to an object array
object[,] rawData = new object[dt.Rows.Count + 1, dt.Columns.Count];
// Copy the values to the object array
for (int col = 0; col < dt.Columns.Count; col++)
{
for (int row = 0; row < dt.Rows.Count; row++)
{ rawData[row, col] = dt.Rows[row].ItemArray[col]; }
}
// Calculate the final column letter
string finalColLetter = string.Empty;
string colCharset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int colCharsetLen = 26;
if (dt.Columns.Count > colCharsetLen)
{ finalColLetter = colCharset.Substring((dt.Columns.Count - 1) / colCharsetLen - 1, 1); }
finalColLetter += colCharset.Substring((dt.Columns.Count - 1) % colCharsetLen, 1);
/*Grabs the full cell address from the "Query Dump" sheet, splits on the '=' and
*pulls out only the cell address (i.e., "address=a3" becomes "a3")*/
string dumpCellString = lstQueryDumpText.Items[i].ToString();
string dumpCell = dumpCellString.Split('=').Last();
/*Refers to the range in which we are dumping the DataSet. The upper right hand cell is
*defined by 'dumpCell'and the bottom right cell is defined by the final column letter
*and the count of rows.*/
string firstRef = "";
string baseRow = "";
//Determines if the column is one letter or two and handles them accordingly
if (char.IsLetter(dumpCell, 1))
{
char[] createCellRef = dumpCell.ToCharArray();
firstRef = createCellRef[0].ToString() + createCellRef[1].ToString();
for (int z = 2; z < createCellRef.Count(); z++)
{ baseRow = baseRow + createCellRef[z].ToString(); }
}
else
{
char[] createCellRef = dumpCell.ToCharArray();
firstRef = createCellRef[0].ToString();
for (int z = 1; z < createCellRef.Count(); z++)
{ baseRow = baseRow + createCellRef[z].ToString(); }
}
int baseRowInt = Convert.ToInt32(baseRow);
int startingCol = ColumnLetterToColumnIndex(firstRef);
int endingCol = ColumnLetterToColumnIndex(finalColLetter);
int finalCol = startingCol + endingCol;
string endCol = ColumnIndexToColumnLetter(finalCol - 1);
int endRow = (baseRowInt + (dt.Rows.Count - 1));
string cellCheck = endCol + endRow;
string excelRange;
if (dumpCell.ToUpper() == cellCheck.ToUpper())
{ excelRange = string.Format(dumpCell + ":" + dumpCell); }
else
{ excelRange = string.Format(dumpCell + ":{0}{1}", endCol, endRow); }
//Dumps the cells into the range on Excel as defined above
templateSheet.get_Range(excelRange, Type.Missing).Value2 = rawData;
/*Check to see if all the SQL queries have been run from
if (i == lstSqlAddress.Items.Count - 1)
{
//Turn Auto Calc back on
excelApp.Calculation = Excel.XlCalculation.xlCalculationAutomatic;
/*Run through the value save sheet array then grab the address from the corresponding list
*place in the address array. If the address reads "whole sheet" then save the whole page,
*else set the addresses range and value save that.
for (int y = 0; y < lstSaveSheet.Items.Count; y++)
{
MessageBox.Show("Save Sheet: " + lstSaveSheet.Items[y] + "\n" + "Save Address: " + lstSaveRange.Items[y]);
}*/
//run the macro to hide the unused columns
excelApp.Run("ReportMakerExecute");
//save excel file as hospital name and move onto the next
SaveTemplateAs(templateBook, h);
}
}
}
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
}

How to get Active process file name using windows forms application?

public static string GetActiveProcessFileName()
{
try
{
IntPtr hwnd = GetForegroundWindow();
uint pid;
GetWindowThreadProcessId(hwnd, out pid);
Process p = Process.GetProcessById((int)pid);
// return p.MainModule.FileName;
CommandLine = GetMainModuleFilepath((int)pid);
if (CommandLine != null)
{
var array = CommandLine.Split('"');
if (array.Length == 3)
{
if (array[array.Length - 1].Equals(" "))
{
return "Application";
}
if (!array[array.Length - 1].Equals(" "))
{
return array[array.Length - 1];
}
return null;
}
if (array.Length == 5)
{
return array[array.Length - 2];
}
return "Explorer";
}
return "Explorer";
}
catch (Exception ex)
{
ErrorLog.ErrorLog.Log(ex);
return "Explorer";
}
}
Here "[CommandLine]" get current open file names correnctly..
if i run my application.executed successfully..Now
i open 3 notepad files like abc.txt,aaa.txt,dde.txt one by one then,Which will opened file will be display as normal...
If i opened word documents 3 files one by one or excel files..I get only first opened file names saved only...
How can i get correct result of open document Why i got this problem when open word or excel or pdf file open situvation...
use the below code to get the word file instances
private void timer1_Tick(object sender, EventArgs e)
{
y = GetActiveWindowTitle();
try
{
Microsoft.Office.Interop.Word.Application WordObj;
WordObj = (Microsoft.Office.Interop.Word.Application)System.Runtime.InteropServices.Marshal.GetActiveObject("Word.Application");
var vvv = WordObj.StartupPath;
x = "";
for (int i = 0; i < WordObj.Windows.Count; i++)
{
object idx = i + 1;
Microsoft.Office.Interop.Word.Window WinObj = WordObj.Windows.get_Item(ref idx);
// doc_list.Add(WinObj.Document.FullName);
x = x + "," + WinObj.Document.FullName;
//x = WinObj.Document.FullName;
}
}
catch (Exception ex)
{
// No documents opened
}
string[] ax=x.Split(',');
// string[] ax1 = x1.Split(',');
ForAllWordFiles.Text = x;
ForWordTitle.Text = y;
if (y != null)
{
ActiveWord.Text = " ";
if (y.Contains("- Microsoft Word"))
{
ForWordTitle.Text = y.Substring(0, y.Length - 17);
foreach (var item in ax)
{
if (item.Contains(ForWordTitle.Text))
{
ActiveWord.Text = item;
break;
}
ActiveWord.Text = " ";
}
}
}
}
this code is valid for 2010 office

Merge 2 Files and throw an error if an Invalid File selected

Hi all i am having a list box on my Form which will display all the .txt files from the directory C:. This list box selection mode is set to MultiExtended.
My condition to check whether the file is valid or not will be checked using the condition as each and every line content of the selected file should be *94*. If this one satisifes then only it is said to be a valid file. I have written a code for this too but as i am checking in the loop and at a time i can only read one file content this was working fine. But i have to check initially all the selected files matches the condition or not if ok then i have to do the remaining code if not i would like to display error
My code on Button Click
private void btnMerge_Click(object sender, EventArgs e)
{
if (lstACH.SelectedIndices.Count == 1)
{
MessageBox.Show("Select 2 Files To Merge");
}
else
{
for (i = 0; i < lstACH.SelectedItems.Count; i++)
{
strFile = lstACH.SelectedItems[i].ToString();
lines = File.ReadAllLines(strFile);
if (LinesHaveCorrectLength(lines, 94)) // Here i am checking but at a tym i am checking one file only i have to check for all and if ok then the remaining code has to be executed
{
if (i == 0)
{
Stream myStream;
SaveFileDialog saveFileDialog1 = new SaveFileDialog();
saveFileDialog1.InitialDirectory = #"C:\";
saveFileDialog1.DefaultExt = "txt";
saveFileDialog1.Filter = "(*.txt)|*.txt";
saveFileDialog1.FilterIndex = 2;
saveFileDialog1.RestoreDirectory = true;
saveFileDialog1.ValidateNames = true;
if (saveFileDialog1.ShowDialog() == DialogResult.OK)
{
Append.FileName = saveFileDialog1.FileName;
if (Append.FileName.Contains(" \\/:*?<>|"))
{
MessageBox.Show("File name should not contain \\/:*?<>|", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else
{
if ((myStream = saveFileDialog1.OpenFile()) != null)
{
Append.FileName = saveFileDialog1.FileName;
myStream.Close();
}
}
}
}
using (StreamWriter sw = new StreamWriter(Append.FileName, true))
{
using (StreamReader srBatch = new StreamReader(strFile))
{
while (srBatch.Peek() >= 0)
{
strReadLine = srBatch.ReadLine();
if (strReadLine.StartsWith("1"))
{
if (i == 0)
{
strFileHeader = strReadLine;
sw.WriteLine(strFileHeader);
}
}
if (strReadLine.StartsWith("5"))
{
strBtchHeader = strReadLine;
if (i == 0)
{
Btchno = Convert.ToInt32(strReadLine.Substring(87, 7));
BatchCnt = Convert.ToInt16(Btchno);
}
if (i > 0)
{
BatchCnt++;
strBtchHeader = strBtchHeader.Substring(0, 87) + Convert.ToString(BatchCnt.ToString().PadLeft(7, (char)48));
}
sw.WriteLine(strBtchHeader);
}
if (strReadLine.StartsWith("6"))
{
strEntryDetail = strReadLine;
if (i == 0)
{
strTraceNo = strEntryDetail.Substring(87, 7);
EntryCount = Convert.ToInt16(strTraceNo);
}
if (i > 0)
{
EntryCount++;
strEntryDetail = strEntryDetail.Substring(0, 87) + EntryCount.ToString().PadLeft(7, (char)48);
}
sw.WriteLine(strEntryDetail);
}
if (strReadLine.StartsWith("8"))
{
strBtchCntrl = strReadLine;
if (i > 0)
{
//btchEntry++;
strBtchCntrl = strBtchCntrl.Substring(0, 87) + BatchCnt.ToString().PadLeft(7, (char)48);
}
sw.WriteLine(strBtchCntrl);
}
if (strReadLine.StartsWith("9"))
{
strFileCntrl = strReadLine;
strBtchCnt = strReadLine.Substring(1, 6);
strEntrycnt = strReadLine.Substring(13, 8);
strEntryHash = strReadLine.Substring(21, 10);
strDebitAmnt = strReadLine.Substring(31, 12);
strCreditAmnt = strReadLine.Substring(43, 12);
BtchCnt += Convert.ToDouble(strBtchCnt);
Entrycnt += Convert.ToDouble(strEntrycnt);
EntryHash += Convert.ToDouble(strEntryHash);
DebitAmnt += Convert.ToDouble(strDebitAmnt);
CreditAmnt += Convert.ToDouble(strCreditAmnt);
if (i == lstACH.SelectedItems.Count - 1)
{
strFileCntrl = strFileCntrl.Substring(0, 1) + BtchCnt.ToString().PadLeft(6, (char)48) + strFileCntrl.Substring(7, (strFileCntrl.Length - 7));
strFileCntrl = strFileCntrl.Substring(0, 13) + Entrycnt.ToString().PadLeft(8, (char)48) + strFileCntrl.Substring(21, (strFileCntrl.Length - 21));
strFileCntrl = strFileCntrl.Substring(0, 21) + EntryHash.ToString().PadLeft(10, (char)48) + strFileCntrl.Substring(31, (strFileCntrl.Length - 31));
strFileCntrl = strFileCntrl.Substring(0, 31) + DebitAmnt.ToString().PadLeft(12, (char)48) + strFileCntrl.Substring(43, (strFileCntrl.Length - 43));
strFileCntrl = strFileCntrl.Substring(0, 43) + CreditAmnt.ToString().PadLeft(12, (char)48) + strFileCntrl.Substring(55, (strFileCntrl.Length - 55));
sw.WriteLine(strFileCntrl);
}
}
}
}
}
if (i == lstACH.SelectedItems.Count - 1)
{
MessageBox.Show("File Has Been Merged Successfully");
this.Close();
}
}
else
{
MessageBox.Show("One of the Selected File is not a Valid ACH File");
break;
}
}
}
}
Checking for Each and every line Length
private static bool LinesHaveCorrectLength(string[] lines, int expectedLineLength)
{
foreach (string item in lines)
{
if (item.Length != expectedLineLength)
{
return false;
}
}
return true;
}
Just check them all first - and if all good, THEN begin merge.
if (lstACH.SelectedIndices.Count != 2)
{
MessageBox.Show("Select 2 Files To Merge");
return;
}
foreach (String fileName in lstACH.SelectedItems)
{
if( LinesHaveCorrectLength( File.ReadAllLines(fileName), 94 ) == false )
{
MessageBox.Show("File: " + fileName + " has an incorrect line length");
return;
}
}
// Now process them all again to merge:
foreach(String fileName in lstACH.SelectedItems)
{
// ... do merge logic
}
Ok according to your comment it looks like First you want both files to be validated. if that is the case then:
(There could be many ways , this is one of them)
First define a Function to do the checking for all files:
public bool AreFilesValid(ListBox.SelectedObjectCollection filenames)
{
int count = filenames.Count;
bool valid = false;
for(int i=0;i<count;i++)
{
string strFile = filenames[i].ToString();
string[] lines = File.ReadAllLines(strFile);
if(LinesHaveCorrectLength(lines, 94)) { valid=true; }
else { valid = false; }
}
return valid;
}
Then call it in your if condition, i.e just change following lines:
...
strFile = lstACH.SelectedItems[i].ToString();
lines = File.ReadAllLines(strFile);
if (LinesHaveCorrectLength(lines, 94))
{
...
To only this:
...
if (AreFilesValid(lstACH.SelectedItems))
{
...
You have already got your else statement down the code to catch when this if condition fails.

Categories