using System;
using System.IO;
using System.Text;
using Excel;
using System.Reflection;
namespace CompareXls
{
/// <summary>
/// Diff の概要の説明です。
///
/// Change Java to C# by xzl@DCE at 2004/05
/// zl_xue@hotmail.com
/// @Version C# version 0.1 2004
/// </summary>
/// <summary>
/// This is the info kept per-file.
/// </summary>
class fileInfo
{
internal static int MAXLINECOUNT = 200;
public int maxLine; // After input done, # lines in file.
internal int[] other; // Map of line# to line# in other file.
internal node[] symbol; // The symtab handle of each file.
// (-1 means do not know.)
// Allocated after the lines are read.
// internal System.IO.StreamReader file; ----->delete
// Excel Application to Open Excel Files. --->add
private Excel.Application xlsApp;
private Excel.Workbook xlsBook;
private Excel.Sheets xlsSheets;
internal Excel._Worksheet xlsSheet;
/// <summary>
/// Normal constructor with one filename: fileis opened and saved.
/// </summary>
/// <param name="fileName">File name</param>
internal fileInfo(string fileName)
{
symbol = new node[MAXLINECOUNT+2];
other = null; //allocated later.
try
{
// ***********File Path Test***********
fileName=@"G:\test\CompareXls\bin\Debug\"+fileName;
xlsApp= new Excel.Application();
xlsApp.Visible =false;
try{
xlsBook= xlsApp.Workbooks.Open(fileName,
Missing.Value,false,Missing.Value,null,null,
Missing.Value,Missing.Value,Missing.Value,
Missing.Value,Missing.Value,Missing.Value,
Missing.Value,Missing.Value,Missing.Value);
xlsSheets=xlsApp.Sheets;
xlsSheet=(Worksheet)xlsSheets.get_Item(1);
}
catch{
xlsClose();
return;
}
// file = new System.IO.StreamReader(fileName); ----->delete
}
catch(System.NullReferenceException e){
Console.WriteLine ("File Error! "+e.ToString());
//--->add
xlsClose();
return;
}
}
//This is done late, to be same size as # lines in input file.
internal void alloc()
{
other = new int[symbol.Length +2];
}
//Close excel file --->add
internal void xlsClose(){
xlsApp.Quit();
xlsSheets = null ;
xlsBook = null ;
xlsApp = null ;
GC.Collect() ;
}
}
/// <summary>
/// Diff Text file difference utility.
/// </summary>
class Diff
{
/// <summary>
/// アプリケーションのメイン エントリ ポイントです。
/// </summary>
///
// block len > and Psssible real block len.
int unReal=int.MaxValue ;
// Keeps track of information abouot file1 and file2.
fileInfo oldInfo, newInfo;
/* blocklen is the info about blocks. It will be set to 0, except at the line#s where
* blocks start in the old file. At these plcaes it will be set to the # lines in the
* block. During printout, this # will be reset to -1 if the block is printed as a MOVE
* block (because the printout phase will encouter the block twice, but must only print
* it once .) .
* The array declarations are to MAXLINECOUNT+2 so that we can have two extra lines at
* line# 0 and line# MAXLINECOUNT+1 (or less).
*/
int[] blocklen;
[STAThread]
static void Main(string[] args)
{
//
// TODO: アプリケーションを開始するコードをここに追加してください。
//
Console.WriteLine("Input Compare File --| oldFile(*.xls) newFile(*.xls) |--> ");
// Read File Name
string strRead=Console.ReadLine ();
if(strRead!=string.Empty)
{
string[] strFileName=strRead.Split( );
Diff d= new Diff ();
d.doDiff(strFileName[0],strFileName[1]);
//--->add
Console.WriteLine("Enter Exit.");
Console.Read();
}
else
{
Console.WriteLine("Useage: oldFile(*.xls) newFile(*.xls)");
}
return;
}
//Construct a Diff object.
Diff(){
}
/// <summary>
/// Do one file comparison. Called with both filenames.
/// </summary>
/// <param name="oldFile">Old File Name</param>
/// <param name="newFile">New File Name</param>
public void doDiff(string oldFile,string newFile)
{
oldInfo= new fileInfo(oldFile);
newInfo = new fileInfo(newFile);
//We don't process until we know both files really do exist.
try
{
inputScan(oldInfo);
inputScan(newInfo);
}
catch{
Console.WriteLine("Read error.");
return;
}
//Now that we've read all the lines, allocate some arrrays. ----->update
blocklen= new int[(oldInfo.xlsSheet.UsedRange.Cells.Rows.Count*oldInfo.xlsSheet.UsedRange.Cells.Columns.Count >
newInfo.xlsSheet.UsedRange.Cells.Rows.Count*newInfo.xlsSheet.UsedRange.Cells.Columns.Count ?
oldInfo.xlsSheet.UsedRange.Cells.Rows.Count*oldInfo.xlsSheet.UsedRange.Cells.Columns.Count :
newInfo.xlsSheet.UsedRange.Cells.Rows.Count*newInfo.xlsSheet.UsedRange.Cells.Columns.Count)+2];
oldInfo.alloc();
newInfo.alloc();
//Do the work and print the results.
transform();
printOut();
//Close Excel Application. --->add
oldInfo.xlsClose();
newInfo.xlsClose();
}
/// <summary>
/// inputScan Read the file specified by pinfo.file.
/// Places the lines of that file in the symbol table.
/// Sets pinfo.maxLine to the number of lines found.
/// </summary>
/// <param name="pinfo"></param>
void inputScan(fileInfo pinfo){
string lineBuffer;
pinfo.maxLine =0;
//--->update
int j,i; // Excel file Cells (Row ,Column)
for(j=1;j<pinfo.xlsSheet.UsedRange.Cells.Rows.Count;j++)
{
for(i=1;i<pinfo.xlsSheet.UsedRange.Columns.Rows.Count;i++)
{
lineBuffer=pinfo.xlsSheet.get_Range(pinfo.xlsSheet.Cells[j,i],pinfo.xlsSheet.Cells[j,i]).Text.ToString();
if(lineBuffer!=string.Empty )
storeline(lineBuffer,pinfo);
else continue;
}
}
}
/// <summary>
/// storeline Places line into symbol table.
/// Expects pinfo.maxLine initted: increments.
/// Places symbol table handle in pinfo.symbol.
/// Expects pinfo is either oldinfo or newinfo.
/// </summary>
/// <param name="lineBuffer"></param>
/// <param name="pinfo"></param>
void storeline(string lineBuffer,fileInfo pinfo)
{
int lineNum =++pinfo.maxLine ; //note, no line zero.
if(lineNum>fileInfo.MAXLINECOUNT)
{
Console.WriteLine ("Exceeded,Stop.");
return;
}
pinfo.symbol[lineNum]=node.addSymbol(lineBuffer,pinfo.Equals(oldInfo),lineNum);
}
/// <summary>
/// transform Analyzes the file differences and leaves its finding in
/// the global arrays oldInfo.other, newInfo.other and blocklen.
/// </summary>
void transform()
{
int oldLine,newLine;
int oldMax=oldInfo.maxLine+2;
int newMax= newInfo.maxLine +2;
for (oldLine=0;oldLine<oldMax;oldLine++)
oldInfo.other[oldLine]=-1;
for (newLine=0;newLine<newMax;newLine++)
newInfo.other[newLine]=-1;
scanUnique(); // Scan for lines used once in both files.
scanAfter(); // Scan past sure-matches for non-unique blocks.
scanBefore(); // Scan backwards form sure-matches
scanBlocks(); // Fine the fronts and lengths of blocks.
}
/// <summary>
/// scanUnique Scans for lines which are used exactly once in each file.
/// </summary>
void scanUnique()
{
int oldLine,newLine;
node psymbol;
for(newLine=1;newLine<=newInfo.maxLine ;newLine++)
{
psymbol=newInfo.symbol[newLine];
if(psymbol.symbollsUnique()) // 1 use in each file
{
oldLine=psymbol.lineNum;
newInfo.other[newLine]=oldLine;
oldInfo.other[oldLine]=newLine;
}
}
newInfo.other[0]=0;
oldInfo.other[0]=0;
newInfo.other[newInfo.maxLine +1]=oldInfo.maxLine +1;
oldInfo.other[oldInfo.maxLine +1]=newInfo.maxLine +1;
}
/// <summary>
/// scanAfter Expects both files in symtab, and oldInfo and newInfo valild.
/// </summary>
void scanAfter()
{
int oldLine,newLine;
for(newLine=0;newLine<=newInfo.maxLine ;newLine++)
{
oldLine=newInfo.other[newLine];
if(oldLine>=0) // is unique in old & new.
{
for(;;) // Scan after there in both files.
{
if(++oldLine>oldInfo.maxLine ) break;
if(oldInfo.other[oldLine]>=0) break;
if(++newLine>newInfo.maxLine ) break;
if(newInfo.other[newLine]>=0) break;
if(newInfo.symbol[newLine]!=oldInfo.symbol[oldLine])
break; // not same
newInfo.other[newLine]=oldLine; // record a match
oldInfo.other[oldLine]=newLine;
}
}
}
}
/// <summary>
/// scanBefore As scanAfter, except scans towards file fronts.
/// Assumes the off-end lines have benn marked as a match.
/// </summary>
void scanBefore()
{
int oldLine,newLine;
for(newLine=newInfo.maxLine +1;newLine>0;newLine--)
{
oldLine=newInfo.other[newLine];
if(oldLine>=0) //unique in each
{
for(;;)
{
if(--oldLine<=0)
break;
if(oldInfo.other[oldLine]>=0)
break;
if(--newLine<=0)
break;
if(newInfo.other[newLine]>=0)
break;
if(newInfo.symbol[newLine]!=oldInfo.symbol[oldLine])
break;
newInfo.other[newLine]=oldLine;
oldInfo.other[oldLine]=newLine;
}
}
}
}
/// <summary>
/// scanBlocks Finds the beginnings and lenghts of blocks of matches.
/// Sets the blocklen array
/// Expects oldInfo valid.
/// </summary>
void scanBlocks()
{
int oldLine,newLine;
int oldFront=0; // line# of front of a block in old or 0
int newLast=-1; // newline's value during prev. iteration.
for(oldLine=1;oldLine<=oldInfo.maxLine ;oldLine++)
blocklen[oldLine]=0;
blocklen[oldInfo.maxLine +1]=unReal; // starts a mthical blk
for(oldLine=1;oldLine<=oldInfo.maxLine ;oldLine++)
{
newLine=oldInfo.other[oldLine];
if(newLine<0) // no match: not in block
oldFront=0;
else // match.
{
if(oldFront==0)oldFront=oldLine;
if(newLine!=(newLast+1))oldFront=oldLine;
++blocklen[oldFront];
}
newLast=newLine;
}
}
public static int idle=0,delete=1,insert=2,movenew=3,moveold=4,same=5,change=6;
int printStatus;
bool anyPrinted;
int printOldLine,printNewLine; // line numbers in old & new file.
/// <summary>
/// printOut Prints summary to stdout.
/// Expects all data structures have been filled out.
/// </summary>
void printOut()
{
printStatus=idle;
anyPrinted=false;
for(printOldLine=printNewLine=1;;)
{
if(printOldLine>oldInfo.maxLine )
{
newConsume();
break;
}
if(printNewLine>newInfo.maxLine )
{
oldConsume();
break;
}
if(newInfo.other[printNewLine]<0)
{
if(oldInfo.other[printOldLine]<0)
showChange();
else
showInsert();
}
else if(oldInfo.other[printOldLine]<0)
showDelete();
else if(blocklen[printOldLine]<0)
skipOld();
else if(oldInfo.other[printOldLine].Equals(printNewLine))
showSame();
else
showMove();
}
if(anyPrinted==true)
Console.WriteLine (">>>>End of differences.");
else
Console.WriteLine (">>>>Files are Identical.");
}
/// <summary>
/// newConsume Part of printout. Have run out of old file.
/// Print the rest of the new file, as insert and/or moves.
/// </summary>
void newConsume()
{
for(;;)
{
if(printNewLine>newInfo.maxLine )
break; // end of file
if(newInfo.other[printNewLine]<0)
showInsert();
else
showMove();
}
}
/// <summary>
/// oldConsume Part of printout. Have run of new file.
/// </summary>
void oldConsume()
{
for(;;)
{
if(printOldLine>oldInfo.maxLine )
break; // end of file
printNewLine=oldInfo.other[printOldLine];
if(printNewLine<0)
showDelete();
else if(blocklen[printOldLine]<0)
skipOld();
else
showMove();
}
}
/// <summary>
/// showDelete Part of printout.
/// </summary>
void showDelete()
{
if(printStatus!=delete)
Console.WriteLine(">>>> Delete At "+printOldLine);
printStatus=delete;
oldInfo.symbol[printOldLine].showSymbol();
anyPrinted=true;
printOldLine++;
}
/// <summary>
/// showInsert Part of printout.
/// </summary>
void showInsert()
{
if(printStatus==change)
Console.WriteLine(">>>> Change To ");
else if (printStatus!=insert)
Console.WriteLine(">>>> Insert Before "+printOldLine);
printStatus=insert;
newInfo.symbol[printNewLine].showSymbol();
anyPrinted=true;
printNewLine++;
}
/// <summary>
/// showChange Part of printout.
/// </summary>
void showChange()
{
if(printStatus!=change)
Console.WriteLine(">>>> "+printOldLine+" Change From");
printStatus=change;
oldInfo.symbol[printOldLine].showSymbol();
anyPrinted=true;
printNewLine++;
}
/// <summary>
/// skipOld Part of printout.
/// </summary>
void skipOld()
{
printStatus=idle;
for(;;)
{
if(++printOldLine>oldInfo.maxLine )
break; // end of file.
if(oldInfo.other[printOldLine]<0)
break; // end of block.
if(blocklen[printOldLine]!=0)
break; // start of another.
}
}
/// <summary>
/// skipNew Part of printout.
/// </summary>
void skipNew()
{
int oldLine;
printStatus=idle;
for(;;)
{
if(++printNewLine>newInfo.maxLine )
break; // end of file.
oldLine=newInfo.other[printNewLine];
if(oldLine<0)
break; // end of block.
if(blocklen[oldLine]!=0)
break; // start of another.
}
}
/// <summary>
/// showSame Part of printout.
/// </summary>
void showSame()
{
int count;
printStatus = idle;
if(newInfo.other[printNewLine]!=printOldLine)
{
Console.WriteLine ("Bug In Line Referencing.");
}
count=blocklen[printOldLine];
printOldLine+=count;
printNewLine+=count;
}
/// <summary>
/// showMove Part of printout.
/// </summary>
void showMove()
{
int oldBlock = blocklen[printOldLine];
int newother = newInfo.other[printNewLine];
int newBlock = blocklen[newother];
if(newBlock<0)
skipNew(); // already printed.
else if(oldBlock>=newBlock) // assume new's blk moved.
{
blocklen[newother]=-1; // stamp block as "printed".
Console.WriteLine (">>>> "+newother+" thru "
+(newother+newBlock-1)+" Moved to Before "+ printOldLine);
for(;newBlock>0;newBlock--,printNewLine++)
newInfo.symbol[printNewLine].showSymbol();
anyPrinted=true;
printStatus=idle;
}
else // assume old's block moved.
skipOld(); // target line# not know, display later.
}
}
/// <summary>
/// Class "Node". The symbol table routines in this class all understand
/// the symbol table format, which is a binary tree.
/// The methods are: addSymbol, symbollsUnique, showSymbol.
/// </summary>
class node{ //The tree is made up of these nodes.
node pleft,pright;
internal int lineNum;
static int freshNode=0,oldonce=1,newonce=2,bothnoce=3,other=4;
int lineState;
string line;
static node panchor = null;
/// <summary>
/// Construct a new symbol table node and fill in its fields.
/// </summary>
/// <param name="pline">String A line of the text file</param>
node(string pline){
pleft=null;
pright=null;
lineState=freshNode;
//linenum field is not always valid
line=pline;
}
/// <summary>
/// matchsymbol Searches tree for a mathc to the line
/// </summary>
/// <param name="pline">String pline, a line of text</param>
/// <returns></returns>
static node matchSymbol(string pline){
int comparison;
node pnode = panchor;
if(panchor== null)
return panchor = new node(pline);
for(;;){
comparison = pnode.line.CompareTo(pline);
if(comparison==0) // found
return pnode;
if(comparison<0){
if(pnode.pleft==null){
pnode.pleft=new node(pline);
return pnode.pleft ;
}
pnode= pnode.pleft ;
}
if(comparison>0)
{
if(pnode.pright ==null)
{
pnode.pright=new node(pline);
return pnode.pright ;
}
pnode= pnode.pright ;
}
}
}
/// <summary>
/// addSymbol(string pline) - Saves lines into the symbol table.
/// </summary>
/// <param name="pline"></param>
/// <param name="inoldFile"></param>
/// <param name="lineNum"></param>
/// <returns>Returns a handle to the symtab entry for that unique line.</returns>
internal static node addSymbol(string pline, bool inoldFile, int lineNum){
node pnode;
pnode = matchSymbol(pline); // find the node in the tree.
if(pnode.lineState.Equals(freshNode))
{
pnode.lineState=inoldFile?oldonce:newonce;
}
else if((pnode.lineState.Equals(oldonce)&&!inoldFile)||
(pnode.lineState.Equals(newonce)&& inoldFile)){
pnode.lineState =bothnoce;
}
else
pnode.lineState = other;
if(inoldFile)
pnode.lineNum=lineNum;
return pnode;
}
/// <summary>
/// symbollsUnique Arg is a ptr previously returned by addSymbol.
/// </summary>
/// <returns>
/// Returns true if the line was add to the symbol table exactly once
/// wiht inoldfile true, and exactly once with inoldfile false.
/// </returns>
internal bool symbollsUnique(){
return(lineState==bothnoce);
}
/// <summary>
/// showSymbol Prints the line to stdout.
/// </summary>
internal void showSymbol(){
Console.WriteLine(line);
}
}
}
浙公网安备 33010602011771号