R0berto[] (J. Saulus), December 2007
Inleiding
Ik ben bezig met C# leren, en maak daarom een aantal triviale programma's om niet meteen met eigen inspiratie te moeten komen.
Allereerst kwam een zoekprogramma in mij op. Text Searcher doet precies wat de naam zegt, het zoekt in bestanden naar een bepaalde text.
Talen gebruikt
Alleen C#. Deels van mezelf, deels opgehoest door Visual Studio 2005 (vooral dus de looks, die heb ik maar ff ge-WYSIWYG'd)
Plaatjes
Source
Bij deze de enige belangrijke source in principe... De looks enzo moet je zelf maar even klussen, en als je de benodigde events niet goed krijgt, kijk je in de zip
- Code: Selecteer alles
# region CopyrightNotice
/************************************************************************************************
* Text Searcher *
* - TXTsearcher.cs - *
************************************************************************************************
************************************************************************************************
* *
* Author: R0berto[] ( J. Saulus ) *
* Date: December 10, 2007 *
* Email: PM via TWNet.nl ( http://www.twnet.nl/ucp.php?i=pm&mode=compose&u=5 ) *
* PM via GoT ( http://gathering.tweakers.net/forum/pm_new_message/2/user/R0berto ) *
* *
* Copyright (c) 2007 R0berto[] *
* *
* Permission to use, copy, modify, and distribute this software for any purpose with or *
* without fee is hereby granted, provided that the above copyright notice and this permission *
* notice appear in all copies. *
* *
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO *
* THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT *
* SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR *
* ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF *
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE *
* OR PERFORMANCE OF THIS SOFTWARE. *
************************************************************************************************/
#endregion CopyrightNotice
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Windows.Forms;
using System.Threading;
using System.ComponentModel;
namespace Text_Searcher
{
/// <summary>
/// Searches a directory (evt subdirectories) for files containing a certain piece of text
/// </summary>
class TXTsearcher
{
/// <summary>
/// The root directory to start the search from
/// </summary>
private DirectoryInfo dir_DirToSearch;
/// <summary>
/// Whether or not to search sub-directories
/// </summary>
private Boolean bool_SearchSubDirs;
/// <summary>
/// What to search for
/// </summary>
private String str_Query;
/// <summary>
/// The text has been found in a file
/// </summary>
/// <remarks>
/// Initiated in -
/// IsInFile( FileInfo fi_File )
/// Returns the filename of the file in which the text has been found
/// </remarks>
public event TextFoundEventHandler TextFound;
/// <summary>
/// The search has started
/// </summary>
/// <remarks>
/// Is initiated by -
/// Search()
/// </remarks>
public event EventHandler SearchStarted;
/// <summary>
/// The search has stopped
/// </summary>
/// <remarks>
/// Initiated at the end of -
/// BGWSearch ( Object sender, DoWorkEventArgs e )
/// </remarks>
public event EventHandler SearchStopped;
/// <summary>
/// An announcement has been made
/// </summary>
/// <remarks>Used to announce which file is being searched</remarks>
public event Announcement Announcement;
/// <summary>
/// This backgroundworker does the actual searching
/// </summary>
public BackgroundWorker bgw_Search;
/// <summary>
/// A list of files to be searched for the given piece of text
/// </summary>
private List<FileInfo> lst_Files;
/// <summary>
/// Constructor
/// </summary>
/// <remarks>
/// Sets all values to default
/// Essentially unnecessary since no search can be done. If - SetQuery( String str_Query)
/// - and -
/// SetDir( String str_Directory
/// - were added, this could be useful
/// </remarks>
public TXTsearcher ()
{
// No dir to search in
this.dir_DirToSearch = null;
// Don't look into subdirectories
this.bool_SearchSubDirs = false;
// Search for an empty string
this.str_Query = String.Empty;
// Create an empty file list
this.lst_Files = new List<FileInfo> ();
// Create the backgroundworker
this.bgw_Search = new BackgroundWorker ();
// The backgroundworker reports its progress
this.bgw_Search.WorkerReportsProgress = true;
// The backgroundworker supports cancellation
this.bgw_Search.WorkerSupportsCancellation = true;
// let BGWSearch do the work
this.bgw_Search.DoWork += this.BGWSearch;
// Call DoneSearching when the backgroundworker has finished
this.bgw_Search.RunWorkerCompleted += this.DoneSearching;
} // TXTsearcher ()
/// <summary>
/// Constructor
/// </summary>
/// <remarks>
/// Sets all values to default, except the text to search for.
/// Relevant values:
/// Directory: "C:\"
/// Query: user-input
/// Search through subdirectories: false
/// </remarks>
public TXTsearcher ( String Query )
{
// Search in C:\
this.dir_DirToSearch = new DirectoryInfo ( @"C:\" );
// Don't look into subdirectories
this.bool_SearchSubDirs = false;
// Search for the string user has put in
this.str_Query = Query;
// Create an empty file list
this.lst_Files = new List<FileInfo> ();
// Create the backgroundworker
this.bgw_Search = new BackgroundWorker ();
// The backgroundworker reports its progress
this.bgw_Search.WorkerReportsProgress = true;
// The backgroundworker supports cancellation
this.bgw_Search.WorkerSupportsCancellation = true;
// let BGWSearch do the work
this.bgw_Search.DoWork += this.BGWSearch;
// Call DoneSearching when the backgroundworker has finished
this.bgw_Search.RunWorkerCompleted += this.DoneSearching;
} // TXTsearcher ( String Query )
/// <summary>
/// Constructor
/// </summary>
/// <remarks>
/// Sets all values to default, except the text to search for.
/// Relevant values:
/// Directory: user-input
/// Query: user-input
/// Search through subdirectories: false
/// </remarks>
public TXTsearcher ( String Query, String Dir )
{
// Search in the directory the user has put in
this.dir_DirToSearch = new DirectoryInfo ( Dir );
// Don't look into subdirectories
this.bool_SearchSubDirs = false;
// Search for the string user has put in
this.str_Query = Query;
// Create an empty file list
this.lst_Files = new List<FileInfo> ();
// Create the backgroundworker
this.bgw_Search = new BackgroundWorker ();
// The backgroundworker reports its progress
this.bgw_Search.WorkerReportsProgress = true;
// The backgroundworker supports cancellation
this.bgw_Search.WorkerSupportsCancellation = true;
// let BGWSearch do the work
this.bgw_Search.DoWork += this.BGWSearch;
// Call DoneSearching when the backgroundworker has finished
this.bgw_Search.RunWorkerCompleted += this.DoneSearching;
} // TXTsearcher ( String Query, String Dir )
/// <summary>
/// Constructor
/// </summary>
/// <remarks>
/// Sets all values to default, except the text to search for.
/// Relevant values:
/// Directory: user-input
/// Query: user-input
/// Search through subdirectories: user-input
/// </remarks>
public TXTsearcher ( String Query, String Dir, Boolean Subs )
{
// Search in the directory the user has put in
this.dir_DirToSearch = new DirectoryInfo ( Dir );
// User puts in whether subdirectories must be searched in
this.bool_SearchSubDirs = Subs;
// Search for the string user has put in
this.str_Query = Query;
// Create an empty file list
this.lst_Files = new List<FileInfo> ();
// Create the backgroundworker
this.bgw_Search = new BackgroundWorker ();
// The backgroundworker reports its progress
this.bgw_Search.WorkerReportsProgress = true;
// The backgroundworker supports cancellation
this.bgw_Search.WorkerSupportsCancellation = true;
// let BGWSearch do the work
this.bgw_Search.DoWork += this.BGWSearch;
// Call DoneSearching when the backgroundworker has finished
this.bgw_Search.RunWorkerCompleted += this.DoneSearching;
} // TXTsearcher ( String Query, String Dir, Boolean Subs )
/// <summary>
/// Create a list of files from the root directory,
/// and if necessary from the subdirectories
/// </summary>
/// <remarks>
/// If subdirectories have to be searched, it calls -
/// MakeSearchList( DirectoryInfo SubDirectory )
/// - which adds the files from the subdirectory to the file-list
/// </remarks>
private void MakeSearchList ()
{
// If the Announcement event has any listeners
if ( this.Announcement != null )
{
// initiate with String "Creating search list"
this.Announcement( this, new AnnouncementArgs("Creating search list") );
} // if
// Add the files in the root directory to the search list
this.lst_Files.AddRange ( this.dir_DirToSearch.GetFiles () );
// If subdirectories must be searched in
if ( this.bool_SearchSubDirs )
{
// From each directory
foreach ( DirectoryInfo Dir in this.dir_DirToSearch.GetDirectories () )
{
// Add files to search list
MakeSearchList ( Dir );
// If the backgroundworker is cancelled
if ( this.bgw_Search.CancellationPending )
{
// Break out
break;
} // if
} // foreach
} // if
} // MakeSearchList ()
/// <summary>
/// Create a list of files from the directory passed as an argument
/// </summary>
/// <remarks>Calls itself if the directory contains any subdirectories</remarks>
private void MakeSearchList ( DirectoryInfo DirToSearch )
{
// Add files from the given directory to the search list
this.lst_Files.AddRange ( DirToSearch.GetFiles () );
// ( no check for this.bool_SearchSubDirs,
// this point is only reached if TRUE )
// From each directory
foreach ( DirectoryInfo Dir in DirToSearch.GetDirectories () )
{
// Add files to search list
MakeSearchList ( Dir );
// If the backgroundworker is cancelled
if ( this.bgw_Search.CancellationPending )
{
// break out
break;
} // if
} // foreach
} // MakeSearchList ( DirectoryInfo DirToSearch )
/// <summary>
/// Is the given piece of text in the file?
/// </summary>
/// <remarks>Works with a 512kB buffer, changing this buffer could increase performance.</remarks>
/// <returns>
/// True if the file contains the given piece of text
/// False if not
/// </returns>
private Boolean IsInFile ( FileInfo fi_File )
{
// Create a FileStream
FileStream strm_File;
// Try to open the file
try
{
strm_File = fi_File.OpenRead ();
} // try
// If file open fails
catch
{
// Just return false
return false;
} // catch
// If the file is not big enough to be able to contain the given text
if ( strm_File.Length < this.str_Query.Length )
{
// return false
return false;
} // if
// File is opened, time to read it
// Create an empty buffer
Byte[] bytes_Buffer;
// Store the total file size
long lng_Total = strm_File.Length;
// While the stream hasn't reached its end
while ( strm_File.Position != lng_Total )
{
// Set a buffer size
int int_BytesToRead = 524288;
// If the buffer can't be filled completely
if ( lng_Total - strm_File.Position < 524288 )
{
// Set appropriate buffer size
int_BytesToRead = (int) (lng_Total - strm_File.Position);
} // if
// Create a buffer of the right length
bytes_Buffer = new Byte[ int_BytesToRead ];
// Fill the buffer with new data
strm_File.Read ( bytes_Buffer, 0, int_BytesToRead );
// Make a string from the buffer
String str_ToCheck = Encoding.GetEncoding ( 1252 ).GetString ( bytes_Buffer );
// If the buffer contains the given text
if ( str_ToCheck.Contains ( this.str_Query ) )
{
// return true
return true;
} // if
// otherwise
else
{
// Read on
// If the stream hasn't reached its end
if ( strm_File.Position != strm_File.Length )
{
// Place the pointer back the given string length minus 1
// This is to ensure the string isn't cut in two due to the buffering
strm_File.Position -= ( this.str_Query.Length - 1 );
} // if
} // else
} // while
// If this point is reached, the string has not been found
// so return false
return false;
} // IsInFile ( FileInfo fi_File )
/// <summary>
/// Initiates the search
/// </summary>
/// <remarks>Tells the backgroundworker to do its job</remarks>
public void Search ()
{
// Tell the backgroundworker to do its job
this.bgw_Search.RunWorkerAsync ();
} // Search ()
/// <summary>
/// Walks through the files and searches through them
/// </summary>
/// <remarks>
/// Is initiated by backgroundworker
/// Calls MakeSearchList to create the file-list
/// Walks through the list and calls SearchThroughFile for each file
/// Also reports the progress to the backgroundworker
/// </remarks>
private void BGWSearch ( Object sender, DoWorkEventArgs e )
{
// If the SearchStarted event has any subscribers
if ( this.SearchStarted != null )
{
// initiate
this.SearchStarted ( this, new EventArgs () );
}// if
// Set progress to 0%
this.bgw_Search.ReportProgress ( 0 );
// Create a list of files to search through
this.MakeSearchList ();
// Loop through file list
foreach ( FileInfo fi_File in this.lst_Files.ToArray () )
{
// Search through file
SearchThroughFile ( fi_File );
// Calculate progress
int int_Progress = (int) ( ( this.lst_Files.IndexOf ( fi_File ) + 1 ) / this.lst_Files.Count ) * 100;
// Report progress
this.bgw_Search.ReportProgress ( int_Progress );
// If search is cancelled
if ( this.bgw_Search.CancellationPending )
{
// Set Cancel to true
e.Cancel = true;
// Break out of file list loop
break;
} // if
} // foreach
// If the SearchStopped event has any listeners
if ( this.SearchStopped != null )
{
// initiate
this.SearchStopped ( this, new EventArgs () );
} // if
} // BGWSearch ( Object sender, DoWorkEventArgs e )
/// <summary>
/// Searches through the file
/// </summary>
/// <remarks>
/// Announces file being searched
/// if -
/// IsInFile( FileInfo fi_File )
/// - returns TRUE, initiates event TextFound
/// </remarks>
private void SearchThroughFile ( FileInfo fi_File )
{
// If the Announcement event has any listeners
if ( this.Announcement != null )
{
// initiate with String "Searching through " + filepath relative to search-root
this.Announcement ( this, new AnnouncementArgs ( "Searching through '" + fi_File.FullName.TrimStart( this.dir_DirToSearch.FullName.ToCharArray() ) + "'" ) );
} // if
// If the file contains the given piece of text
if ( this.IsInFile ( fi_File ) )
{
// If the TextFound event has any listeners
if ( this.TextFound != null )
{
// initiate with FileInfo fi_File
this.TextFound ( this, new TextFoundEventArgs ( fi_File ) );
} // if
} // if
} // SearchThroughFile ( FileInfo fi_File )
/// <summary>
/// Stops the search
/// </summary>
/// <remarks>Cancels the backgroundworker, which exits nicely</remarks>
public void StopSearch ()
{
// If the backgroundworker is busy
if ( this.bgw_Search.IsBusy )
{
// tell it to cancel
this.bgw_Search.CancelAsync ();
} // if
} // StopSearch ()
/// <summary>
/// Is called when the backgroundworker has done its job
/// </summary>
private void DoneSearching ( Object sender, RunWorkerCompletedEventArgs e )
{
// if the SearchStopped event has any listeners
if ( this.SearchStopped != null )
{
// initiate
this.SearchStopped ( this, new EventArgs () );
} // if
} // DoneSearching ( Object sender, RunWorkerCompletedEventArgs e )
} // TXTsearcher
/// <summary>
/// EventHandler for the Announcement event
/// </summary>
/// <param name="sender">The object which initiated the Announcement event</param>
/// <param name="e">Info relevant for the Announcement event</param>
public delegate void Announcement ( Object sender, AnnouncementArgs e );
/// <summary>
/// Relevant info for the Announcement event
/// </summary>
/// <remarks>
/// Available info:
/// String Announcement
/// </remarks>
public class AnnouncementArgs : EventArgs
{
/// <summary>
/// The announcement that has been made
/// </summary>
String str_Announcement;
/// <summary>
/// Constructor
/// </summary>
/// <remarks>
/// Stores -
/// String Announcement
/// </remarks>
public AnnouncementArgs ( String Announcement )
{
// Store the announcement
this.str_Announcement = Announcement;
} // AnnouncementArgs ( String Announcement )
/// <summary>
/// Gets the announcement that has been made
/// </summary>
/// <value>A string containing the announcement made</value>
public String Announcement
{
// read-only
get
{
// return the stored announcement
return this.str_Announcement;
} // get
} // Announcement
} // AnnouncementArgs
/// <summary>
/// Eventhandler for the TextFound event
/// </summary>
/// <param name="sender">The object which initiated the TextFound event</param>
/// <param name="e">Info relevant for the TextFound event</param>
public delegate void TextFoundEventHandler ( Object sender, TextFoundEventArgs e );
/// <summary>
/// Info relevant for the TextFound event
/// </summary>
/// <remarks>
/// Available info:
/// String FileName - Filename of the file
/// String Location - Location of the file
/// String Size - Size with units of the file
/// </remarks>
public class TextFoundEventArgs : EventArgs
{
/// <summary>
/// The filename of the file in which the given piece of text was found
/// </summary>
/// <remarks>
/// Only the filename,
/// the location is stored in -
/// str_Location
/// </remarks>
String str_Filename;
/// <summary>
/// The location of the file in which the given piece of text has been found
/// </summary>
/// <remarks>
/// Only the location,
/// the filename is stored in -
/// str_Filename
/// </remarks>
String str_Location;
/// <summary>
/// The size of the file (in Bytes) in which the given piece of text has been found
/// </summary>
/// <remarks>
/// The size is in Bytes, -
/// String Size
/// - translates to kB, MB or GB (if appropriate)
/// </remarks>
long lng_Size;
/// <summary>
/// Constructor
/// </summary>
/// <remarks>
/// Gets size, filename and location from -
/// FileInfo File
/// - and stores them
/// </remarks>
public TextFoundEventArgs ( FileInfo File )
{
// Store filename
this.str_Filename = File.Name;
// Store file location
this.str_Location = File.DirectoryName;
// Store filesize
this.lng_Size = File.Length;
} // TextFoundEventArgs ( FileInfo File )
/// <summary>
/// Gets the filename of the file in which the given piece of text has been found
/// </summary>
/// <remarks>
/// Filename only,
/// the location can be obtained with -
/// Location
/// </remarks>
/// <value>A String containing the filename</value>
public String FileName
{
// read-only
get
{
// return stored filename
return this.str_Filename;
} // get
} // FileName
/// <summary>
/// The location of the file in which the given piece of text has been found
/// </summary>
/// <remarks>
/// Location only,
/// the filename can be obtained with -
/// FileName
/// </remarks>
/// <value>A string containing the location of the file</value>
public String Location
{
// read-only
get
{
// return stored file location
return this.str_Location;
} // get
} // Location
/// <summary>
/// Get the filesize of the file in which the given piece of text has been found
/// </summary>
/// <remarks>Rounds to 3 decimals and add unit: Bytes, kB, MB or GB</remarks>
/// <value>A string containing the filesize with unit</value>
public String Size
{
// read-only
get
{
// Create a string which will be returned in the end
String str_Return;
// Create a temporary double to hold the new filesize
double dbl_TempSize;
// GB, MB, kB or Bytes if/else
#region UnitIfElse
// If size is greater than 1 GB
if ( this.lng_Size > Math.Pow ( 1024, 3 ) )
{
// Translate to GBs
dbl_TempSize = this.lng_Size / Math.Pow ( 1024, 3 );
// Right amount of decimals switch
#region GBDecimalIfElse
// If greater than 1000 GB, no decimals
if ( dbl_TempSize > 1000 )
{
// Set the string to return
str_Return = Math.Round ( dbl_TempSize, 0 ).ToString () + " GB";
} // if
// If not greater than 1000 GB, but still greater than 100 GB, 1 decimal
else if ( dbl_TempSize > 100 )
{
// Set the string to return
str_Return = Math.Round ( dbl_TempSize, 1 ).ToString () + " GB";
} // else if
// If not greater than 100 GB, but still greater than 10 GB, 2 decimal
else if ( dbl_TempSize > 10 )
{
// Set the string to return
str_Return = Math.Round ( dbl_TempSize, 2 ).ToString () + " GB";
} // else if
// If smaller than 10 GB, 3 decimals
else
{
// Set the string to return
str_Return = Math.Round ( dbl_TempSize, 3 ).ToString () + " GB";
} // else
#endregion GBDecimalIfElse
}
// If size not greater than 1 GB, but still greater than 1 MB
else if ( this.lng_Size > Math.Pow ( 1024, 2 ) )
{
// Translate to MBs
dbl_TempSize = this.lng_Size / Math.Pow ( 1024, 2 );
// Right amount of decimals if/else
#region MBDecimalIfElse
// If greater than 1000 MB, no decimals
if ( dbl_TempSize > 1000 )
{
// Set the string to return
str_Return = Math.Round ( dbl_TempSize, 0 ).ToString () + " MB";
} // if
// If not greater than 1000 MB, but still greater than 100 MB, 1 decimal
else if ( dbl_TempSize > 100 )
{
// Set the string to return
str_Return = Math.Round ( dbl_TempSize, 1 ).ToString () + " MB";
} // else if
// If not greater than 100 MB, but still greater than 10 MB, 2 decimal
else if ( dbl_TempSize > 10 )
{
// Set the string to return
str_Return = Math.Round ( dbl_TempSize, 2 ).ToString () + " MB";
} // else if
// If smaller than 10 MB, 3 decimals
else
{
// Set the string to return
str_Return = Math.Round ( dbl_TempSize, 3 ).ToString () + " MB";
} // else
#endregion MBDecimalIfElse
}
// If the size is not greater than 1 MB, but still greater than 1 kB
else if ( this.lng_Size > 1024 )
{
// Translate to kBs
dbl_TempSize = this.lng_Size / 1024;
// Right amount of decimals if/else
#region kBDecimalIfElse
// If greater than 1000 kB, no decimals
if ( dbl_TempSize > 1000 )
{
// Set the string to return
str_Return = Math.Round ( dbl_TempSize, 0 ).ToString () + " kB";
} // if
// If not greater than 1000 kB, but still greater than 100 kB, 1 decimal
else if ( dbl_TempSize > 100 )
{
// Set the string to return
str_Return = Math.Round ( dbl_TempSize, 1 ).ToString () + " kB";
} // else if
// If not greater than 100 kB, but still greater than 10 kB, 2 decimal
else if ( dbl_TempSize > 10 )
{
// Set the string to return
str_Return = Math.Round ( dbl_TempSize, 2 ).ToString () + " kB";
} // else if
// If smaller than 10 kB, 3 decimals
else
{
// Set the string to return
str_Return = Math.Round ( dbl_TempSize, 3 ).ToString () + " kB";
} // else
#endregion kBDecimalIfElse
}
// If smaller than 1 kB
else
{
// Set the string to return
str_Return = this.lng_Size.ToString () + " Bytes";
// break out
}
#endregion UnitIfElse
// Return the correct string
return str_Return;
} // get
} // Size
} // TextFoundEventArgs
} // Text_Searcher


