文件批量处理器
目录
- 文件批量处理器概述
- 文件流技术
- 文件解压缩技术
- 获取系统文件及文件夹图标
- 获取指定目录下的所有文件及文件夹
- Word操作技术
- 进度条的显示
- 对ListView控件中的项进行排序
- 主窗体预览
- 批量复制、剪切文件
- 批量复制、剪切文件夹
- 批量重命名文件
- 批量删除文件及文件夹
- 搜索文件及文件夹
- 批量压缩、解压文件
- 分割、合并文件
文件批量处理器概述
文件批量处理器是一款类似于Windows资源管理器的软件,但它相对于Windows资源管理器来说,功能更加强大,主要增加了批量重命名文件、解压缩文件、文件分割及合成、垃圾文件处理等功能。
文件批量处理器的功能结构如图1所示。
文件流技术
文件批量处理器中对文件及文件夹进行批量处理时,主要用到了文件流技术,而操作文件流的类都位于System.IO命名空间下。本模块中主要用到了File类、FileInfo类、Directory类和DirectoryInfo类,下面对它们进行详细讲解。
1.File类
File类支持对文件的基本操作,包括用于创建、复制、删除、移动和打开文件的静态方法,并协助创建FileStream对象。File类中一共包含40多个方法,这里只列出本模块中用到的几种方法,如表1所示。
表1 File类的常用方法及说明
说明:(1)由于File类中的所有方法都是静态的,所以如果只想执行一个操作,那么使用File类中方法的效率比使用相应的FileInfo类中的方法可能更高。
(2)File类的静态方法对所有方法都执行安全检查,因此如果打算多次重用某个对象,可考虑改用FileInfo类中的相应方法,因为并不总是需要安全检查。
2.FileInfo类
FileInfo类和File类的许多方法调用都是相同的,但是FileInfo类没有静态方法,该类中的方法仅可以用于实例化对象。File类是静态类,它的调用需要字符串参数为每一个方法调用规定文件位置。因此如果要在对象上进行单一方法调用,则可以使用静态File类,在这种情况下静态调用速度要快一些,因为.NET框架不必执行实例化新对象并调用其方法的过程;如果要在文件上执行几种操作,则实例化FileInfo对象并使用其方法就更好一些,这样会提高效率,因为对象将在文件系统上引用正确的文件,而静态类就必须每次都寻找文件。
FileInfo类的常用属性及说明如表2所示。
表2 FileInfo类的常用属性及说明
3.Directory类
Directory类公开了用于创建、移动、枚举、删除目录和子目录的静态方法,这里介绍本模块中用到的该类中的方法,如表3所示。
表3 irectory类的常用方法及说明
4.DirectoryInfo类
DirectoryInfo类和Directory类之间的关系与FileInfo类和File类之间的关系十分类似,这里不再赘述。下面介绍DirectoryInfo类的常用属性。
DirectoryInfo类的常用属性及说明如表4所示。
表4 DirectoryInfo类的常用属性及说明
文件解压缩技术
文件批量处理器中实现文件解压缩功能时,用到了ICSharpCode.dll组件,它是一个第三方组件,相对于.NET自带的Copression压缩类,它压缩后的文件更小,而且支持的压缩格式也多,因此这里使用了该组件。
使用该组件时,首先需要在“添加引用”中将ICSharpCode.dll文件添加到项目中,然后在命名空间区域添加如下代码:
using ICSharpCode.SharpZipLib;
using ICSharpCode.SharpZipLib.Zip;
using ICSharpCode.SharpZipLib.Checksums;
实现文件批量处理器中的压缩文件和解压文件功能时,将其实现写在了公共类中的方法中。压缩文件的实现代码如下:
#region 压缩文件及文件夹
/// <summary>
/// 递归压缩文件夹方法
/// </summary>
/// <param name="FolderToZip"></param>
/// <param name="ZOPStream">压缩文件输出流对象</param>
/// <param name="ParentFolderName"></param>
private bool ZipFileDictory(string FolderToZip, ZipOutputStream ZOPStream, string ParentFolderName)
{
bool res = true;
string[] folders, filenames;
ZipEntry entry = null;
FileStream fs = null;
Crc32 crc = new Crc32();
try
{
//创建当前文件夹(加上“/”才会当成是文件夹创建)
entry = new ZipEntry(Path.Combine(ParentFolderName, Path.GetFileName(FolderToZip) + "/"));
ZOPStream.PutNextEntry(entry);
ZOPStream.Flush();
//先压缩文件,再递归压缩文件夹
filenames = Directory.GetFiles(FolderToZip);
foreach (string file in filenames)
{
//打开压缩文件
fs = File.OpenRead(file);
byte[] buffer = new byte[fs.Length];
fs.Read(buffer, 0, buffer.Length); //读取文件内容
entry = new ZipEntry(Path.Combine(ParentFolderName, Path.GetFileName(FolderToZip) + "/" + Path. GetFileName(file))); //实例化ZipEntry对象
entry.DateTime = DateTime.Now; //设置压缩文件时间
entry.Size = fs.Length; //设置压缩文件长度
fs.Close(); //关闭数据流
crc.Reset();
crc.Update(buffer);
entry.Crc = crc.Value;
ZOPStream.PutNextEntry(entry);
ZOPStream.Write(buffer, 0, buffer.Length); //向压缩文件写入内容
}
}
catch
{
res = false;
}
finally
{
if (fs != null)
{
fs.Close();
fs = null;
}
if (entry != null)
{
entry = null;
}
GC.Collect();
GC.Collect(1);
}
folders = Directory.GetDirectories(FolderToZip); //获取压缩文件存放路径
foreach (string folder in folders)
{
if (!ZipFileDictory(folder, ZOPStream, Path.Combine(ParentFolderName, Path.GetFileName(FolderToZip))))
//判断是否存在相同压缩文件
{
return false;
}
}
return res;
}
/// <summary>
/// 压缩目录
/// </summary>
/// <param name="FolderToZip">待压缩的文件夹</param>
/// <param name="ZipedFile">压缩后的文件名</param>
/// <returns></returns>
private bool ZipFileDictory(string FolderToZip, string ZipedFile)
{
bool res;
if (!Directory.Exists(FolderToZip)) //判断是否存在相同压缩文件
{
return false;
}
//实例化压缩文件输出流对象
ZipOutputStream ZOPStream= new ZipOutputStream(File.Create(ZipedFile));
ZOPStream.SetLevel(6);
res = ZipFileDictory(FolderToZip, ZOPStream, ""); //压缩文件夹
ZOPStream.Finish();
ZOPStream.Close(); //关闭压缩文件输出流
return res;
}
/// <summary>
/// 压缩文件
/// </summary>
/// <param name="FileToZip">要进行压缩的文件名</param>
/// <param name="ZipedFile">压缩后生成的压缩文件名</param>
/// <returns></returns>
private bool ZipFile(string FileToZip, string ZipedFile)
{
//如果文件没有找到,则报错
if (!File.Exists(FileToZip))
{
throw new System.IO.FileNotFoundException("指定要压缩的文件: " + FileToZip + " 不存在!");
}
FileStream ZipFile = null; //实例化数据流对象
ZipOutputStream ZipStream = null; //实例化压缩文件输出流对象
ZipEntry ZipEntry = null; //实例化压缩文件对象
bool res = true; //判断是否压缩成功
try
{
ZipFile = File.OpenRead(FileToZip); //打开原文件
byte[] buffer = new byte[ZipFile.Length]; //将原文件内容存储到字节数组中
ZipFile.Read(buffer, 0, buffer.Length); //读取原文件内容
ZipFile.Close(); //关闭原文件读取数据流
ZipFile = File.Create(ZipedFile); //创建压缩文件
ZipStream = new ZipOutputStream(ZipFile); //初始化压缩文件输出流对象
ZipEntry = new ZipEntry(Path.GetFileName(FileToZip)); //初始化压缩文件对象
ZipStream.PutNextEntry(ZipEntry);
ZipStream.SetLevel(6);
ZipStream.Write(buffer, 0, buffer.Length); //向压缩文件中写入内容
}
catch
{
res = false;
}
finally
{
if (ZipEntry != null)
{
ZipEntry = null;
}
if (ZipStream != null)
{
ZipStream.Finish();
ZipStream.Close(); //关闭压缩文件输出流
}
if (ZipFile != null)
{
ZipFile.Close(); //关闭压缩文件
ZipFile = null;
}
GC.Collect();
GC.Collect(1);
}
return res;
}
/// <summary>
/// 压缩文件和文件夹
/// </summary>
/// <param name="FileToZip">待压缩的文件或文件夹</param>
/// <param name="ZipedFile">压缩后生成的压缩文件名,全路径格式</param>
/// <returns></returns>
public bool Zip(String FileToZip, String ZipedFile)
{
if (Directory.Exists(AllPath + FileToZip))
{
return ZipFileDictory(AllPath + FileToZip, ZipedFile); //压缩文件夹
}
else if (File.Exists(AllPath + FileToZip))
{
return ZipFile(AllPath + FileToZip, ZipedFile); //压缩文件
}
else
{
return false; //压缩失败
}
}
#endregion
UnZip方法用来解压指定的压缩文件,其实现代码如下:
#region 解压文件
/// <summary>
/// 解压文件
/// </summary>
/// <param name="FileToUpZip">待解压的文件</param>
/// <param name="ZipedFolder">指定解压目标目录</param>
public void UnZip(string FileToUpZip, string ZipedFolder)
{
if (!File.Exists(AllPath + FileToUpZip)) //判断是否存在要解压的文件
{
return;
}
if (!Directory.Exists(ZipedFolder)) //判断是否存在解压后文件的存放路径
{
Directory.CreateDirectory(ZipedFolder); //创建解压后文件的存放文件夹
}
ZipInputStream ZIPStream = null; //实例化压缩文件写入流对象
ZipEntry theEntry = null; //实例化压缩文件对象
string fileName; //解压后的文件名
FileStream streamWriter = null; //实例化文件流对象
try
{
//初始化压缩文件写入流对象
ZIPStream = new ZipInputStream(File.OpenRead(AllPath + FileToUpZip));
while ((theEntry = ZIPStream.GetNextEntry()) != null)
{
if (theEntry.Name != String.Empty)
{
fileName = Path.Combine(ZipedFolder, theEntry.Name);
//判断文件路径是否是文件夹
if (fileName.EndsWith("/") || fileName.EndsWith("\\"))
{
Directory.CreateDirectory(fileName);
continue;
}
streamWriter = File.Create(fileName); //创建解压后的文件名
int size = 2048;
byte[] data = new byte[2048];
while (true)
{
size = ZIPStream.Read(data, 0, data.Length); //读取压缩文件内容
if (size > 0)
{
streamWriter.Write(data, 0, size); //向解压后的文件写入内容
}
else
{
break;
}
}
}
}
}
finally
{
if (streamWriter != null)
{
streamWriter.Close(); //关闭文件流对象
streamWriter = null;
}
if (theEntry != null)
{
theEntry = null; //清空压缩文件对象
}
if (ZIPStream != null)
{
ZIPStream.Close(); //关闭压缩文件写入流对象
ZIPStream = null;
}
GC.Collect();
GC.Collect(1);
}
}
#endregion
获取系统文件及文件夹图标
文件批量处理器中,当用户选择指定目录时,在右边的显示部分会自动将该目录下的文件及文件夹显示出来,同时将系统中与其匹配的图标显示出来,这样显得更加人性化。下面详细讲解如何获取系统文件及文件夹的图标。
首先,以C#方式重写Windows系统下的API函数SHGetFileInfo,其主要用来获得文件图标句柄,实现代码如下:
/// <summary>
/// 获得文件图标句柄
/// </summary>
/// <param name="pszPath">指定的文件名</param>
/// <param name="dwFileAttribute">文件属性</param>
/// <param name="psfi">记录类型,返回获得的文件信息</param>
/// <param name="cbSizeFileInfo">psfi的比特值</param>
/// <param name="Flags">指明需要返回的文件信息标识符</param>
/// <returns>文件的图标句柄</returns>
[DllImport("shell32.dll", EntryPoint = "SHGetFileInfo")]
public static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttribute, ref SHFILEINFO psfi, uint cbSizeFileInfo, uint Flags);
#endregion
Windows系统下的API函数DestroyIcon用来清除图标,代码如下:
#region 清除图标
/// <summary>
/// 清除图标
/// </summary>
/// <param name="hIcon">图标句柄</param>
/// <returns>非零表示成功,零表示失败</returns>
[DllImport("User32.dll", EntryPoint = "DestroyIcon")]
public static extern int DestroyIcon(IntPtr hIcon);
#endregion
然后,定义一个图标结构,其中包括文件的图标句柄、图标的系统索引号、文件属性值、文件显示名和文件类型名等5个元素。定义图标结构的实现代码如下:
#region 图标结构
/// <summary>
/// 图标结构
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct SHFILEINFO
{
public IntPtr hIcon; //文件的图标句柄
public IntPtr iIcon; //图标的系统索引号
public uint dwAttributes; //文件的属性值
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string szDisplayName; //文件的显示名
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
public string szTypeName; //文件的类型名
}
#endregion
GetListViewItem方法为自定义的无返回值类型方法,它主要用来获取指定路径下的所有文件及图标,该方法有3个参数,分别表示路径、存储图标的ImageList对象和显示图标的ListView对象。GetListViewItem方法实现代码如下:
#region 获取指定路径下所有文件及其图标
/// <summary>
/// 获取指定路径下所有文件及其图标
/// </summary>
/// <param name="path">路径</param>
/// <param name="imglist">ImageList对象</param>
/// <param name="lv">ListView对象</param>
public void GetListViewItem(string path, ImageList imglist, ListView lv)
{
lv.Items.Clear();
SHFILEINFO shfi = new SHFILEINFO();
try
{
string[] dirs = Directory.GetDirectories(path); //获取指定文件夹下的子文件夹
string[] files = Directory.GetFiles(path); //获取指定文件夹下的所有文件
for (int i = 0; i < dirs.Length; i++)
{
string[] info = new string[4]; //存储文件夹信息
DirectoryInfo dir = new DirectoryInfo(dirs[i]);
//判断文件夹类型
if (dir.Name == "RECYCLER" || dir.Name == "RECYCLED" || dir.Name == "Recycled" || dir.Name == "System Volume Information")
{ }
else
{
//获得图标
SHGetFileInfo(dirs[i],
(uint)0x80,
ref shfi,
(uint)System.Runtime.InteropServices.Marshal.SizeOf(shfi),
(uint)(0x100 | 0x400));//取得Icon和TypeName
//添加图标
imglist.Images.Add(dir.Name, (Icon)Icon.FromHandle(shfi.hIcon).Clone());
info[0] = dir.Name; //获取文件夹名称
info[1] = "";
info[2] = "文件夹";
info[3] = dir.LastWriteTime.ToString(); //获取文件夹最后修改时间
//将文件夹信息添加到ListView项中
ListViewItem item = new ListViewItem(info, dir.Name);
lv.Items.Add(item); //将获取的文件夹显示在ListView列表中
DestroyIcon(shfi.hIcon); //销毁图标
}
}
for (int i = 0; i < files.Length; i++)
{
string[] info = new string[5]; //存储文件信息
FileInfo fi = new FileInfo(files[i]);
string Filetype = fi.Name.Substring(fi.Name.LastIndexOf(".") + 1, fi.Name.Length - fi.Name.LastIndex Of(".") - 1);
string newtype = Filetype.ToLower(); //将文件扩展名转换为小写
//判断文件类型
if (newtype == "sys" || newtype == "ini" || newtype == "bin" || newtype == "log" || newtype == "com" || newtype == "bat" || newtype == "db")
{ }
else
{
//获得图标
SHGetFileInfo(files[i],
(uint)0x80,
ref shfi,
(uint)System.Runtime.InteropServices.Marshal.SizeOf(shfi),
(uint)(0x100 | 0x400)); //取得Icon和TypeName
//添加图标
imglist.Images.Add(fi.Name, (Icon)Icon.FromHandle(shfi.hIcon).Clone());
info[0] = fi.Name; //获取文件名称
double dbLength = fi.Length / 1024; //获取文件长度
if (dbLength < 1024)
info[1] = dbLength.ToString("0.00") + " KB";//将文件长度转换为KB
else
//将文件长度转换为MB
info[1] = Convert.ToDouble(dbLength / 1024).ToString("0.00") + " MB";
info[2] = fi.Extension.ToString(); //获取文件扩展名
info[3] = fi.LastWriteTime.ToString(); //获取文件最后修改时间
info[4] = fi.IsReadOnly.ToString(); //获取文件是否只读
//将文件信息添加到ListView项中
ListViewItem item = new ListViewItem(info, fi.Name);
lv.Items.Add(item); //将获得的文件显示在ListView列表中
DestroyIcon(shfi.hIcon); //销毁图标
}
}
}
catch
{
}
}
#endregion
获取指定目录下的所有文件及文件夹
文件批量处理器中,当用户在主窗体左边的ListView列表中双击文件或文件夹时,如果双击的是文件,则调用系统程序打开该文件;如果双击的是文件夹,系统会自动将该文件夹下所包含的文件及子文件夹显示出来。双击打开文件或文件夹的功能是通过调用公共类中的GetPath方法实现的,下面对GetPath方法进行详细讲解。
GetPath方法为自定义的无返回值类型方法,它主要用来将指定路径下的文件及文件夹显示在ListView控件中,该方法有4个参数,分别表示选定的路径、存储文件或文件夹图标的ImageList控件对象、显示文件或文件夹的ListView控件对象、执行操作的标识。GetPath方法实现代码如下:
/// <summary>
/// 将指定路径下的文件及文件夹显示在ListView控件中
/// </summary>
/// <param name="path">路径</param>
/// <param name="imglist">ImageList控件对象</param>
/// <param name="lv">ListView控件对象</param>
/// <param name="ppath">标识要执行的操作</param>
public void GetPath(string path, ImageList imglist, ListView lv, int intflag)
{
string pp = ""; //存储文件夹名称
string uu = ""; //存储文件及文件夹路径
try
{
if (intflag == 0)
{
if (AllPath != path)
{
lv.Items.Clear();
AllPath = path;
GetListViewItem(AllPath, imglist, lv); //获取文件夹所包含的文件列表
}
}
else
{
uu = AllPath + path;
if (Directory.Exists(uu)) //判断是否存在指定路径
{
AllPath = AllPath + path + "\\"; //转换为全路径
pp = AllPath.Substring(0, AllPath.Length - 1); //获取文件夹名称
lv.Items.Clear();
GetListViewItem(pp, imglist, lv); //获取指定文件夹的文件列表
}
else
{
//判断如果不是完整路径,先转换为完整路径,再打开
if (path.IndexOf("\\") == -1)
{
uu = AllPath + path; //转换为文件的全路径
System.Diagnostics.Process.Start(uu); //打开文件
}
else //判断如果是完整路径,则直接打开
System.Diagnostics.Process.Start(path); //打开文件夹
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
#endregion
Word操作技术
文件批量处理器中批量重命名文件时,如果用户选择的是“批量替换文件标题中的文字”选项,并且所选的文件格式为doc格式,程序就会自动将文件名中的相应文字和打开文件后的第一行中的相应文字全部替换掉,这时就需要对Word文档进行操作。
对Word文件进行操作时,首先需要引用Microsoft Word 9.0组件,该组件需要在“添加引用”对话框的“COM”选项卡中添加。添加完Word组件之后,就可以在程序中通过Word类对象对Word文件进行操作了。
本模块中对Word文件进行操作的主要代码如下:
//如果文件为Word文档格式,则替换标题中的文字
if (strFExtention.ToLower() == ".doc")
{
Word.Application newWord = new Word.Application();
object missing = System.Reflection.Missing.Value;
//打开一个Word文档
Word.Document newDocument = newWord.Documents.Open(ref strNewPath, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing);
object Replaceone = Word.WdReplace.wdReplaceOne;
//设置要查找的关键字
newWord.Selection.Find.ClearFormatting();
newWord.Selection.Find.Text = strOldName;
//设置要替换的关键字
newWord.Selection.Find.Replacement.ClearFormatting();
newWord.Selection.Find.Replacement.Text = strNewName;
//执行替换操作
newWord.Selection.Find.Execute(
ref missing, ref missing, ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing, ref missing, ref missing,
ref Replaceone, ref missing, ref missing, ref missing, ref missing);
//保存Word文档
newWord.ActiveDocument.Save();
//关闭Word文档
object objSaveChanges = Word.WdSaveOptions.wdSaveChanges;
Word.DocumentClass doc = newWord.ActiveDocument as Word.DocumentClass;
doc.Close(ref objSaveChanges, ref missing, ref missing);
}
进度条的显示
文件批量处理器中实现文件复制、剪切、删除、分割及合并时,都用到了进度条。进度条的显示主要通过ProgressBar控件来实现。
ProgressBar控件通过在水平条中显示适当数目的矩形块来指示进程的进度。进程完成时,进度栏被填满。进度栏通常用于帮助用户了解等待一项进程(如加载大文件)完成所需的时间。
ProgressBar控件的主要属性有Value、Minimum和Maximum。Minimum和Maximum属性设置进度栏可以显示的最大值和最小值;Value属性表示操作过程中已完成的进度。因为控件中显示的进度栏由块构成,所以ProgressBar控件显示的值只是约等于Value属性的当前值。
更新当前进度值的最常用方法是编写代码来设置Value属性。在加载大文件的例子中,可将最大值设置为以KB为单位的文件大小,例如,如果Maximum属性设置为100,Minimum属性设置为10并且Value属性设置为50,则将显示5个矩形。
但是,除直接设置Value属性外,还有其他方法可以修改ProgressBar控件显示的值。Step属性可以用于指定Value属性递增的值,然后,调用PerformStep方法来递增该值。如果要更改增量值,开发人员可以使用Increment方法并指定Value属性递增的值。
对ListView控件中的项进行排序
在文件批量处理器的右边显示文件及文件夹列表是通过ListView控件实现的,该控件默认情况下,单击列标题不能进行排序。为了使程序更加人性化,单击ListView控件中的列标题时,能够对其中的项进行排序,这里通过ListView控件的ListViewItemSorter属性手动实现了该功能。
首先定义了一个ListViewItemComparer类,该类继承自Icomparer接口,它主要用来比较ListView控件中列的项大小。代码如下:
#region 对ListView控件中的项进行排序
/// <summary>
/// 对ListView控件中的项进行排序
/// </summary>
class ListViewItemComparer : IComparer
{
private int col; //记录单击的列表头索引
public ListViewItemComparer()
{
col = 0; //初始化列表头索引
}
public ListViewItemComparer(int column)
{
col = column; //为列表头索引复制
}
public int Compare(object x, object y) //比较单击的列中的文件名称
{
return String.Compare(((ListViewItem)x).SubItems[col].Text, ((ListViewItem)y).SubItems[col].Text);
}
}
#endregion
然后单击ListView控件中的列标题时,触发其ColumnClick事件,该事件中,使用自定义的ListViewItemComparer类来设置ListView控件的ListViewItemSorter属性,从而实现单击排序的功能。实现代码如下:
//单击ListView控件的列标题时,对项进行排序
private void lvInfo_ColumnClick(object sender, ColumnClickEventArgs e)
{
try
{
//单击ListView控件中的列标题进行排序
lvInfo.ListViewItemSorter = new CommonClass.ListViewItemComparer(e.Column);
}
catch { }
}
主窗体预览
文件批量处理器主窗体如下图所示。
批量复制、剪切文件
在文件批量处理器的主窗体中,选中多个文件,单击鼠标右键,在弹出的快捷菜单中选择“批量复制”或“批量剪切”菜单项,然后选择另外一个目录,单击鼠标右键,在弹出的快捷菜单中选择“批量粘贴”菜单项,即可将选中的文件复制或剪切到另外的目录中。批量复制、剪切文件的运行结果如图2所示。
图2 批量复制、剪切文件
“批量粘贴”菜单项既包括批量复制、剪切文件,也包括批量复制、剪切文件夹,其实现代码如下:
//根据复制或剪切文件及文件夹标识确定执行粘贴操作
private void 粘贴ToolStripMenuItem_Click(object sender, EventArgs e)
{
if (blCopy == true)
{
//复制文件
baseclass.CopyFile(lvInfo, imageList1, list, strFullName, CommonClass.BaseClass.AllPath, 0,toolStrip ProgressBar1);
for (int i = 0; i < list.Count; i++)
{
//复制文件夹
baseclass.CopyDir(CommonClass.BaseClass.AllPath + list[i].ToString(), strFullName + list[i].ToString(), 0);
}
}
else if (blCut == true)
{
//剪切文件
baseclass.CopyFile(lvInfo, imageList1, list, strFullName, CommonClass.BaseClass.AllPath, 1, toolStrip ProgressBar1);
for (int i = 0; i < list.Count; i++)
{
//剪切文件夹
baseclass.CopyDir(CommonClass.BaseClass.AllPath + list[i].ToString(), strFullName + list[i].ToString(), 1);
}
blCut = false;
//粘贴
ToolStripMenuItem.Enabled = false;
}
else
{
MessageBox.Show("没有需要粘贴的内容!", "提示", MessageBoxButtons.OK, MessageBoxIcon. Information);
}
//刷新
ToolStripMenuItem_Click(sender, e);
toolStripProgressBar1.Value = 0;
}
上面的代码中用到了CopyFile方法,该方法为自定义的无返回值类型方法,主要用来批量复制和剪切文件。该方法有6个参数,分别表示显示文件的ListView控件对象、显示文件图标的ImageList控件对象、ListView控件中的选中项、文件原始路径、文件新路径和操作标识。CopyFile方法实现代码如下:
#region 复制或剪切文件(包括批量复制、剪切)
/// <summary>
/// 复制或剪切文件(包括批量复制、剪切)
/// </summary>
/// <param name="lv">显示文件的ListView控件对象</param>
/// <param name="imagelist">显示文件图标的ImageList控件对象</param>
/// <param name="list">ListView控件中的选中项</param>
/// <param name="strPath">文件的原始路径</param>
/// <param name="strNewPath">文件的新路径</param>
/// <param name="intflag">标识是执行复制操作,还是执行剪切操作</param>
public void CopyFile(ListView lv, ImageList imagelist, ArrayList list, string strPath,string strNewPath, int intflag, Tool StripProgressBar TSPBar)
{
try
{
TSPBar.Maximum = list.Count; //设置进度条最大值
foreach (object objFile in list) //循环访问文件列表
{
string strFile = objFile.ToString(); //获取文件名
string strOldFile = strPath + strFile;
string strNewFile = strNewPath + strFile;
if (File.Exists(strOldFile))
{
if (!Directory.Exists(strNewPath))
Directory.CreateDirectory(strNewPath); //创建新路径
if (intflag == 0)
{
File.Copy(strOldFile, strNewFile, true); //复制文件
}
else if (intflag == 1)
{
File.Move(strOldFile, strNewFile); //剪切文件
}
}
TSPBar.Value += 1; //进度条的值加1
}
GetListViewItem(AllPath, imagelist, lv);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
#endregion
批量复制、剪切文件夹
在文件批量处理器的主窗体中,选中多个文件夹,单击鼠标右键,在弹出的快捷菜单中选择“批量复制”或“批量剪切”菜单项,然后选择另外一个目录,单击鼠标右键,在弹出的快捷菜单中选择“批量粘贴”菜单项,即可将选中的文件夹复制或剪切到另外的目录中。批量复制、剪切文件夹的运行结果如图3所示。
图3 批量复制、剪切文件夹
在上面介绍的“批量粘贴”菜单项的Click事件中用到了CopyDir方法,该方法为自定义的无返回值类型方法,主要用来实现批量复制、剪切文件夹功能。该方法有3个参数,分别表示要复制文件夹的新路径,要复制文件夹的原始路径及操作标识。CopyDir方法实现代码如下:
#region复制或剪切文件夹(包括批量复制、剪切)
/// <summary>
/// 复制或剪切文件夹(包括批量复制、剪切)
/// </summary>
/// <param name="Ddir">要复制文件夹的新路径</param>
/// <param name="Sdir">要复制文件夹的原始路径</param>
/// <param name="intflag">标识执行复制操作,还是执行剪切操作</param>
public void CopyDir(string Ddir, string Sdir, int intflag)
{
DirectoryInfo dir = new DirectoryInfo(Sdir);
string SbuDir = Ddir;
try
{
if (!dir.Exists) //判断所指的文件或文件夹是否存在
{
return;
}
DirectoryInfo dirD = dir as DirectoryInfo; //如果给定参数不是文件夹则退出
string UpDir = UpAndDown_Dir(Ddir);
if (dirD == null) //判断文件夹是否为空
{
Directory.CreateDirectory(UpDir + "\\" + dirD.Name); //如果为空,创建文件夹并退出
return;
}
else
{
Directory.CreateDirectory(UpDir + "\\" + dirD.Name);
}
SbuDir = UpDir + "\\" + dirD.Name + "\\";
FileSystemInfo[] files = dirD.GetFileSystemInfos(); //获取文件夹中所有文件和文件夹
//对单个FileSystemInfo进行判断,如果是文件夹则进行递归操作
foreach (FileSystemInfo FSys in files)
{
FileInfo file = FSys as FileInfo;
if (file != null)//如果是文件,进行文件的复制操作
{
//获取文件所在的原始路径
FileInfo SFInfo = new FileInfo(file.DirectoryName + "\\" + file.Name);
SFInfo.CopyTo(SbuDir + "\\" + file.Name, true); //将文件复制到指定的路径中
}
else
{
string pp = FSys.Name; //获取当前搜索到的文件夹名称
//如果是文件,进行递归调用
CopyDir(SbuDir + FSys.ToString(), Sdir + "\\" + FSys.ToString(), intflag);
}
}
if (intflag == 1)
Directory.Delete(Sdir, true);
}
catch
{
MessageBox.Show("文件夹复制失败。");
}
}
CopyDir方法中调用了UpAndDown方法,该方法用来返回上一级目录,其返回值为string类型,它有一个参数,用来表示当前目录。UpAndDown方法实现代码如下:
/// <summary>
/// 返回上一级目录
/// </summary>
/// <param dir="string">目录</param>
/// <returns>返回String对象</returns>
public string UpAndDown_Dir(string dir)
{
string Change_dir = "";
Change_dir = Directory.GetParent(dir).FullName; //获取指定目录的父目录
return Change_dir;
}
#endregion
批量重命名文件
在文件批量处理器的主窗体中,在菜单栏中选择“批量文件处理”/“批量重命名”菜单项,弹出“批量重命名”窗体,该窗体中,用户可以选择要重命名的文件,然后选择重命名方式,单击“确定”按钮,即可按指定的方式重命名文件。批量重命名窗体运行结果如图4所示。
图4。
实现批量重命名文件时,自定义了一个RepeatFile方法,该方法为可重载方法,它主要用来按指定的重命名方式重命名选定的文件,这里需要注意的是,当要重命名的文件为Word文档时,同时修改其文件名和打开文件后的第一行中的相应文字。RepeatFile方法实现代码如下:
#region 重命名文件及文件夹(包括批量重命名文件),该方法为重载方法
/// <summary>
/// 重命名文件及文件夹
/// </summary>
/// <param name="lv">显示文件及文件夹的ListView控件对象</param>
/// <param name="imagelist">显示文件及文件夹图标的ImageList控件对象</param>
/// <param name="strName">文件或文件夹的原名称</param>
/// <param name="strNewName">文件或文件夹的新名称</param>
public void RepeatFile(ListView lv, ImageList imagelist, string strName, string strNewName)
{
string strPath = AllPath + strName; //旧文件及路径
string strNewPath = AllPath + strNewName; //新文件及路径
if (strNewName != null)
{
if (File.Exists(strPath)) //判断要重命名的文件是否存在
{
if (strPath != strNewPath)
{
File.Move(strPath, strNewPath); //将重命名的文件剪切到新路径及文件名
}
}
if (Directory.Exists(strPath)) //判断如果重命名的是文件夹
{
DirectoryInfo dir = new DirectoryInfo(strPath);
dir.MoveTo(strNewPath); //重命名文件夹
}
lv.Items.Clear();
GetListViewItem(AllPath, imagelist, lv);
}
}
/// <summary>
/// 批量重命名文件(当文件为Word时,修改标题中的文字)
/// </summary>
/// <param name="lbox">显示要重命名文件的ListBox控件对象</param>
/// <param name="intFlag">标识按编号重命名,还是按扩展名重命名</param>
/// <param name="strExten">要重命名的扩展名</param>
/// <param name="PBar">进度条显示</param>
public void RepeatFile(ListBox lbox, int intFlag,string strExten,string strOldName,string strNewName,ProgressBar PBar)
{
FileInfo FInfo = null;
PBar.Maximum = lbox.Items.Count; //设置进度条最大值
for (int i = 0; i < lbox.Items.Count; i++)
{
string strFile = lbox.Items[i].ToString(); //获取要重命名的文件列表
if (File.Exists(strFile))
{
FInfo = new FileInfo(strFile);
string strPath = FInfo.DirectoryName; //获取文件路径
string strFName = FInfo.Name; //获取文件名
string strFExtention = FInfo.Extension; //获取文件扩展名
switch (intFlag)
{
case 0: //在文件前面加编号
File.Move(strFile, strPath + "\\" + i.ToString().PadLeft(4, '0') + strFName);
break;
case 1: //在文件后面加编号
File.Move(strFile, strPath + "\\" + strFName.Substring(0, strFName.LastIndexOf(".")) + i.ToS tring().PadLeft(4, '0') + strFExtention);
break;
case 2: //批量修改文件扩展名
File.Move(strFile, strPath + "\\" + strFName.Substring(0, strFName.LastIndexOf(".")) + "." + strExten);
break;
case 3: //如果修改的是Word文档
frmRepeat frmrepeat=new frmRepeat();
object strNewPath = strPath + "\\" + strFName.Replace(strOldName, strNewName);
File.Move(strFile, strNewPath.ToString());
//如果文件为Word文档格式,则替换标题中的文字
if (strFExtention.ToLower() == ".doc")
{
Word.Application newWord = new Word.Application();
object missing = System.Reflection.Missing.Value;
//打开一个Word文档
Word.Document newDocument = newWord.Documents.Open(ref strNewPath, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing);
object Replaceone = Word.WdReplace.wdReplaceOne;
//设置要查找的关键字
newWord.Selection.Find.ClearFormatting();
newWord.Selection.Find.Text = strOldName;
//设置要替换的关键字
newWord.Selection.Find.Replacement.ClearFormatting();
newWord.Selection.Find.Replacement.Text = strNewName;
//执行替换操作
newWord.Selection.Find.Execute(
ref missing, ref missing, ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing, ref missing, ref missing,
ref Replaceone, ref missing, ref missing, ref missing, ref missing);
//保存Word文档
newWord.ActiveDocument.Save();
//关闭Word文档
object objSaveChanges = Word.WdSaveOptions.wdSaveChanges;
Word.DocumentClass doc = newWord.ActiveDocument as Word.DocumentClass;
doc.Close(ref objSaveChanges, ref missing, ref missing);
}
break;
}
PBar.Value = i + 1;
}
}
}
#endregion
在frmMain主窗体中,用户可以对选中的单个文件或文件夹进行重命名,其实现代码如下:
#region 重命名文件及文件夹
private void ToolStripMenuItem_Click(object sender, EventArgs e)
{
if (lvInfo.SelectedItems.Count != 0)
{
lvInfo.SelectedItems[0].BeginEdit(); //显示重命名文件或文件夹
}
}
private void lvInfo_AfterLabelEdit(object sender, LabelEditEventArgs e)
{
baseclass.RepeatFile(lvInfo, imageList1, lvInfo.SelectedItems[0].Text, e.Label); //重命名文件或文件夹
}
在主窗体的菜单栏中选择“批量文件处理”/“批量重命名”菜单项,弹出“批量重命名”窗体frmRepeat,该窗体加载时,首先在TreeView控件中显示当前硬盘中的磁盘分区。frmRepeat窗体的Load事件代码如下:
//窗体初始化时,在树控件中添加“我的电脑”节点
private void frmRepeat_Load(object sender, EventArgs e)
{
TreeNode TNode = new TreeNode("我的电脑");
tvMenu.Nodes.Add(TNode);
}
当用户在frmRepeat窗体的TreeView控件中选择节点时,调用公共类中的方法显示相应节点下的所有文件及文件夹,实现代码如下:
//选择树控件节点时,显示该节点下的所有文件夹及文件名(以全路径格式显示)
private void tvMenu_AfterSelect(object sender, TreeViewEventArgs e)
{
baseclass.TVShow(e.Node); //显示指定目录下的所有文件及文件夹
}
在frmRepeat窗体中,单击 按钮,将树控件中选择的文件添加到右边的ListBox控件中,实现代码如下:
//将树控件中选择的文件添加到ListBox控件中
private void btnSelect_Click(object sender, EventArgs e)
{
if (tvMenu.SelectedNode != null)
{
string strFile = tvMenu.SelectedNode.Text; //记录选择的文件
if (lboxMenu.Items.Contains(strFile))
MessageBox.Show("该文件已经存在!", "提示", MessageBoxButtons.OK, MessageBoxIcon. Information);
else
lboxMenu.Items.Add(strFile); //添加重命名文件列表
}
}
单击 按钮,将ListBox控件中选中的文件移除,实现代码如下:
//取消选中的要重命名的文件
private void btnCSelect_Click(object sender, EventArgs e)
{
if (lboxMenu.SelectedItem != null)
lboxMenu.Items.Remove(lboxMenu.SelectedItem); //移除选中的要重命名的文件
else
MessageBox.Show("请选择要删除的文件!", "提示", MessageBoxButtons.OK, MessageBoxIcon. Information);
}
单击 按钮,将ListBox控件中的所有文件移除,实现代码如下:
//清除所有要重命名的文件
private void btnDSelect_Click(object sender, EventArgs e)
{
lboxMenu.Items.Clear(); //移除所有要重命名的文件
}
当用户在frmRepeat窗体中单击下方的单选按钮时,控制其他单选按钮的可用状态及相应文本框、下拉列表框的可用状态,具体实现代码如下:
//当选择“按编号”重命名时,其他单选按钮的可用状态
private void rbtnID_CheckedChanged(object sender, EventArgs e)
{
if (rbtnID.Checked)
{
rbtnExtention.Checked = rbtnTitle.Checked = cboxExtention.Enabled = false;
rbtnStart.Enabled = rbtnEnd.Enabled = txtNewText.ReadOnly = txtOldText.ReadOnly = true;
}
}
//当选择“按扩展名”重命名时,其他单选按钮的可用状态
private void rbtnExtention_CheckedChanged(object sender, EventArgs e)
{
if (rbtnExtention.Checked)
{
rbtnStart.Enabled = rbtnEnd.Enabled = rbtnID.Checked = rbtnTitle.Checked = rbtnStart.Checked = rbtnEnd. Checked = false;
cboxExtention.Enabled = txtNewText.ReadOnly = txtOldText.ReadOnly = true;
}
}
//当选择“批量替换文件标题中的文字”重命名时,其他单选按钮的可用状态
private void rbtnTitle_CheckedChanged(object sender, EventArgs e)
{
if (rbtnTitle.Checked)
{
rbtnExtention.Checked = rbtnID.Checked = rbtnStart.Enabled = rbtnEnd.Enabled = cboxExtention.Enabled = false;
txtNewText.ReadOnly = txtOldText.ReadOnly = false;
}
}
在frmRepeat窗体中单击“确定”按钮,判断是否已经选择了要重命名的文件,如果已经选择,则按照选择的重命名方式对这些文件进行重命名,否则,弹出信息提示。“确定”按钮的Click事件代码如下:
//根据选择的重命名方式执行批量重命名文件操作
private void btnSure_Click(object sender, EventArgs e)
{
if (lboxMenu.Items.Count > 0)
{
if (rbtnStart.Checked)
baseclass.RepeatFile(lboxMenu, 0, "", "", "",progressBar); //在文件名前加编号
else if (rbtnEnd.Checked)
baseclass.RepeatFile(lboxMenu, 1, "", "", "", progressBar); //在文件名后加编号
else if (rbtnExtention.Checked)
{
if (cboxExtention.Text != "")
//批量修改文件扩展名
baseclass.RepeatFile(lboxMenu, 2, cboxExtention.Text, "", "", progressBar);
}
else if (rbtnTitle.Checked)
{
if (txtOldText.Text != "" && txtNewText.Text != "")
//批量修改Word文件名及文档标题中的相应文字
baseclass.RepeatFile(lboxMenu, 3, "", txtOldText.Text, txtNewText.Text, progressBar);
}
MessageBox.Show("批量重命名文件成功!", "提示", MessageBoxButtons.OK, MessageBoxIcon. Information);
lboxMenu.Items.Clear();
}
else
MessageBox.Show("请选择要重命名的文件!", "提示", MessageBoxButtons.OK, MessageBoxIcon. Information);
}
如果用户选择的是“批量替换文件标题中的文字”单选按钮,则当用户输入“要替换的文字”和“替换后的文字”后,按回车键,即可执行重命名功能,实现代码如下:
//在替换为的文字文本框中按下回车键时,执行批量重命名文件操作
private void txtNewText_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == 13) //判断是否按下回车键
{
btnSure_Click(sender, e);
}
}
批量删除文件及文件夹
在文件批量处理器的主窗体中,选中多个文件或文件夹,单击鼠标右键,在弹出的快捷菜单中选择“批量删除”菜单项,即可将选中的文件或文件夹删除。批量删除文件及文件夹的运行结果如图5所示。
图5。
在公共类BaseClass中自定义了一个DeleteFile方法,该方法用来批量删除文件及文件夹,它有3个参数,分别用来表示显示文件及文件夹的ListView控件对象,显示文件及文件夹图标的ImageList控件对象,显示删除进度条的ToolStripProgressBar对象。DeleteFile方法实现代码如下:
#region 删除文件/文件夹(包括批量删除)
/// <summary>
/// 删除文件/文件夹(包括批量删除)
/// </summary>
/// <param name="lv">显示文件及文件夹的ListView控件对象</param>
/// <param name="imagelist">显示文件及文件夹图标的ImageList控件对象</param>
/// <param name=" TSPBar ">进度条显示</param>
public void DeleteFile(ListView lv, ImageList imagelist,ToolStripProgressBar TSPBar)
{
TSPBar.Maximum = lv.SelectedItems.Count; //设置进度条的最大值
foreach (object objFile in lv.SelectedItems) //循环访问要删除的文件列表
{
string strFile = objFile.ToString(); //获取文件名
string strFullFile = AllPath + strFile.Substring(strFile.IndexOf("{"} + 1, strFile.LastIndexOf(")") - strFile. IndexOf("{"} - 1); //获取文件全路径名
if (File.Exists(strFullFile))
File.Delete(strFullFile); //删除文件
else if (Directory.Exists(strFullFile))
Directory.Delete(strFullFile, true); //删除文件夹
TSPBar.Value += 1; //将进度条的值加1
}
GetListViewItem(AllPath, imagelist, lv);
}
#endregion
在frmMain主窗体中,选择“批量删除”菜单项,调用公共类中的DeleteFile方法批量删除选中的文件及文件夹。“批量删除”菜单项的Click事件代码如下:
//删除文件及文件夹
private void 删除ToolStripMenuItem_Click(object sender, EventArgs e)
{
try
{
baseclass.DeleteFile(lvInfo, imageList1, toolStripProgressBar1); //批量删除文件及文件夹
toolStripProgressBar1.Value = 0;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
搜索文件及文件夹
在文件批量处理器的主窗体中,在工具栏的文本框中输入要搜索的关键字,然后单击工具栏中的“搜索”按钮,程序根据用户输入的关键字自动搜索符合条件的文件及文件夹。搜索文件及文件夹的运行结果如图6所示。
图6。
在公共类BaseClass中自定义了一个SearchFile方法,该方法用来从指定目录下根据指定的关键字搜索文件及文件夹,并显示在ListView控件中。它有两个参数,分别表示显示搜索结果的ListView控件对象,要搜索的文件或文件夹关键字。SearchFile方法实现代码如下:
#region 搜索文件及文件夹
/// <summary>
/// 搜索文件及文件夹
/// </summary>
/// <param name="lv">显示搜索结果的ListView控件对象</param>
/// <param name="strName">要搜索的文件或文件夹关键字</param>
public void SearchFile(ListView lv, string strName)
{
try
{
DirectoryInfo dir = new DirectoryInfo(AllPath);
FileSystemInfo[] files = dir.GetFileSystemInfos();
FileManage.frmMain frmmain = new FileManage.frmMain();
//对单个FileSystemInfo进行判断,如果是文件夹则进行递归操作
foreach (FileSystemInfo FSInfo in files)
{
FileInfo file = FSInfo as FileInfo;
if (file != null) //判断是不是文件
{
if (file.Name.IndexOf(strName) != -1)
{
string[] info = new string[5];
info[0] = AllPath + file.Name; //获取文件名
double dbLength = file.Length / 1024; //获取文件大小
if (dbLength < 1024)
info[1] = dbLength.ToString("0.00") + " KB";
else
info[1] = Convert.ToDouble(dbLength / 1024).ToString("0.00") + " MB";
info[2] = file.Extension.ToString(); //获取文件扩展名
info[3] = file.LastWriteTime.ToString(); //获取文件最后修改时间
info[4] = file.IsReadOnly.ToString(); //获取文件是否只读
ListViewItem item = new ListViewItem(info, Convert.ToString(AllPath + file.Name).Remove(0, 3));
lv.Items.Add(item); //添加文件列表
}
}
else //如果是文件夹
{
if (FSInfo.Name.IndexOf(strName) != -1)
{
string[] info = new string[4];
info[0] = AllPath + FSInfo.Name; //获取文件夹名
info[1] = "";
info[2] = "文件夹";
info[3] = FSInfo.LastWriteTime.ToString(); //获取文件夹最后修改时间
ListViewItem item = new ListViewItem(info, AllPath + FSInfo.Name);
lv.Items.Add(item);
}
AllPath += FSInfo.Name + "\\";
while (!Directory.Exists(AllPath))
{
string strNewPath = AllPath.Substring(0, AllPath.LastIndexOf("\\"));
AllPath = Directory.GetParent(strNewPath.Substring(0, strNewPath.LastIndexOf("\\"))). Full Name + "\\" + FSInfo.Name + "\\";
}
SearchFile(lv, strName);
}
}
}
catch { }
}
#endregion
在frmMain主窗体中,单击工具栏中的“搜索”按钮,程序首先判断关键字文本框是否为空,如果为空,弹出提示信息,否则调用公共类中的SearchFile方法,根据输入的关键字搜索文件,并显示在ListView控件中。“搜索”按钮的Click事件代码如下:
#region 搜索文件或文件夹
//搜索文件或文件夹
private void tsbtnSearch_Click(object sender, EventArgs e)
{
lvInfo.Items.Clear();
if (ttxtKeyWord.Text != "")
{
baseclass.SearchFile(lvInfo, ttxtKeyWord.Text); //搜索文件
}
else
{
MessageBox.Show("搜索关键字不能为空!", "提示", MessageBoxButtons.OK, MessageBoxIcon. Information);
刷新ToolStripMenuItem_Click(sender, e);
}
toolStripProgressBar1.Value = 0;
}
当用户在关键字文本框中输入要搜索的关键字后,按〈回车〉键,即可执行文件搜索操作,其实现代码如下:
//在搜索关键字文本框中按下〈回车〉键时,执行搜索文件或文件夹操作
private void ttxtKeyWord_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == 13) //判断是否按下〈回车〉键
{
tsbtnSearch_Click(sender, e);
}
}
#endregion
批量压缩、解压文件
在文件批量处理器的主窗体中,选中多个文件及文件夹,在菜单栏中选择“批量文件处理”/“批量压缩文件”菜单项,可以将选中的文件及文件夹压缩到一个文件中。当用户选择一个压缩文件时,在菜单栏中选择“批量文件处理”/“解压文件”菜单项,可以将选中的压缩文件解压到指定的文件夹中。批量压缩、解压文件的运行结果如图7所示。
图7。
在frmMain主窗体中,选择要压缩的文件,在菜单栏中选择“批量文件处理”/“批量压缩文件”菜单项,弹出“另存为”对话框,输入压缩后的文件名,单击“保存”按钮,即可将选择的文件压缩。“批量压缩文件”菜单项的Click事件代码如下:
#region 解压缩文件
//压缩文件及文件夹
private void 压缩文件ToolStripMenuItem_Click(object sender, EventArgs e)
{
saveFileDialog.ShowDialog();
toolStripProgressBar1.Maximum = list.Count; //设置进度条最大值
if (list.Count > 1)
{
string strNewPath = DateTime.Now.ToString("yyyyMMddhhmmss"); //要压缩的新文件夹名
//将要压缩的文件复制到新文件夹中
baseclass.CopyFile(lvInfo, imageList1, list, CommonClass.BaseClass.AllPath, CommonClass.BaseClass.AllP ath + strNewPath + "\\", 0, toolStripProgressBar1);
for (int i = 0; i < list.Count; i++)
{
baseclass.CopyDir(CommonClass.BaseClass.AllPath + strNewPath + "\\" + list[i].ToString(),
Common Class.BaseClass.AllPath + list[i].ToString(), 0);
if (toolStripProgressBar1.Value < toolStripProgressBar1.Maximum)
toolStripProgressBar1.Value += 1;
}
baseclass.Zip(strNewPath, saveFileDialog.FileName); //压缩文件
Directory.Delete(CommonClass.BaseClass.AllPath + strNewPath, true); //删除临时文件夹
MessageBox.Show("压缩文件成功");
}
else if (lvInfo.SelectedIndices.Count > 0)
{
baseclass.Zip(lvInfo.SelectedItems[0].Text, saveFileDialog.FileName); //压缩文件
MessageBox.Show("压缩文件成功");
}
//刷新
ToolStripMenuItem_Click(sender, e);
toolStripProgressBar1.Value = 0;
}
技巧:压缩文件时,由于公共类中的Zip方法只支持单文件、文件夹压缩,如果用户选择了多个文件,则可以首先将这些文件复制到一个临时文件夹中,然后压缩这个临时文件夹,压缩完成之后,将新建的临时文件夹删除即可。
在frmMain主窗体中,选择要解压的压缩文件,在菜单栏中选择“批量文件处理”/“解压文件”菜单项,弹出“浏览文件夹”对话框,选择解压到的路径后,单击“确定”按钮,即可将选择的压缩文件解压。“解压文件”菜单项的Click事件代码如下:
//解压文件
private void ToolStripMenuItem_Click(object sender, EventArgs e)
{
folderBrowserDialog.ShowDialog();
if (lvInfo.SelectedIndices.Count > 0) //判断是否选择了要解压的文件
{
FileInfo FInfo = new FileInfo(CommonClass.BaseClass.AllPath + lvInfo.SelectedItems[0].Text);
if (FInfo.Exists && (FInfo.Extension.ToLower() == ".rar" || FInfo.Extension.ToLower() == ".zip"))
{
//解压文件到指定路径
baseclass.UnZip(lvInfo.SelectedItems[0].Text, folderBrowserDialog.SelectedPath);
MessageBox.Show("解压文件成功");
}
}
}
#endregion
分割、合并文件
在文件批量处理器中,在主窗体的菜单栏中选择“批量文件处理”/“文件分割”菜单项,弹出“文件分割与合成”窗体,该窗体中默认选择“文件分割”面板,在该面板中,选择要分割的文件,然后设置分割后的文件大小和存放路径,单击“分割”按钮,执行文件分割操作。文件分割运行结果如图8所示。
图8。
在文件批量处理器中,在主窗体的菜单栏中选择“批量文件处理”/“文件合成”菜单项,弹出“文件分割与合成”窗体,该窗体中默认选择“文件合成”面板,在该面板中,选择要合成的文件,这里可以选择多个文件,然后设置合成后的文件存放路径,单击“合并”按钮,执行文件合成操作。文件合成运行结果如图9所示。
图9。
说明:合成文件时,选择的要合成的文件必须大于等于两个,并且中间用“,”隔开。
在公共类BaseClass中自定义了一个SplitFile方法,该方法将指定的文件按照指定大小分割为多个小文件进行存放,它有5个参数,分别表示分割单位、分割大小、分割后的文件存放路径、要分割的文件和显示分割进度条的ProgressBar对象。SplitFile方法实现代码如下:
#region 分割文件
/// <summary>
/// 分割文件
/// </summary>
/// <param name="strFlag">分割单位</param>
/// <param name="intFlag">分割大小</param>
/// <param name="strPath">分割后的文件存放路径</param>
/// <param name="strFile">要分割的文件</param>
/// <param name="PBar">进度条显示</param>
public void SplitFile(string strFlag,int intFlag,string strPath,string strFile,ProgressBar PBar)
{
int iFileSize=0;
//根据选择来设定分割的小文件的大小
switch (strFlag)
{
case "Byte":
iFileSize = intFlag;
break;
case "KB":
iFileSize = intFlag * 1024;
break;
case "MB":
iFileSize = intFlag * 1024 * 1024;
break;
case "GB":
iFileSize = intFlag * 1024 * 1024 * 1024;
break;
}
//如果计算机存在存放分割文件的目录,则全部删除此目录所有文件
if (Directory.Exists(strPath))
Directory.Delete(strPath, true);
Directory.CreateDirectory(strPath);
//以文件的全路径对应的字符串和文件打开模式来初始化FileStream文件流实例
FileStream SplitFileStream = new FileStream(strFile, FileMode.Open);
//以FileStream文件流来初始化BinaryReader文件阅读器
BinaryReader SplitFileReader = new BinaryReader(SplitFileStream);
//每次分割读取的最大数据
byte[] TempBytes;
//小文件总数
int iFileCount = (int)(SplitFileStream.Length / iFileSize);
PBar.Maximum = iFileCount;
if (SplitFileStream.Length % iFileSize != 0) iFileCount++;
string[] TempExtra = strFile.Split('.');
//循环将大文件分割成多个小文件
for (int i = 1; i <= iFileCount; i++)
{
//确定小文件的文件名称
string sTempFileName = strPath + @"\" + i.ToString().PadLeft(4, '0') + "." + TempExtra[TempExtra.Length - 1];
//根据文件名称和文件打开模式来初始化FileStream文件流实例
FileStream TempStream = new FileStream(sTempFileName, FileMode.OpenOrCreate);
//以FileStream实例来创建、初始化BinaryWriter书写器实例
BinaryWriter TempWriter = new BinaryWriter(TempStream);
//从大文件中读取指定大小的数据
TempBytes = SplitFileReader.ReadBytes(iFileSize);
//把此数据写入小文件
TempWriter.Write(TempBytes);
//关闭书写器,形成小文件
TempWriter.Close();
//关闭文件流
TempStream.Close();
PBar.Value = i-1;
}
//关闭大文件阅读器
SplitFileReader.Close();
SplitFileStream.Close();
MessageBox.Show("文件分割成功!");
}
#endregion
在公共类BaseClass中自定义了一个CombinFile方法,该方法用来将指定的文件集合合并为一个文件进行存放。它有3个参数,分别用来表示要合并的文件集合,合并后的文件名称及显示合并文件进度条的ProgressBar对象。CombinFile方法实现代码如下:
#region 合并文件
/// <summary>
/// 合并文件
/// </summary>
/// <param name="list">要合并的文件集合</param>
/// <param name="strPath">合并后的文件名称</param>
/// <param name="PBar">进度条显示</param>
public void CombinFile(string[] strFile, string strPath, ProgressBar PBar)
{
PBar.Maximum = strFile.Length;
FileStream AddStream = null;
//以合并后的文件名称和打开方式来创建、初始化FileStream文件流
AddStream = new FileStream(strPath, FileMode.Append);
//以FileStream文件流来初始化BinaryWriter书写器,用以合并分割的文件
BinaryWriter AddWriter = new BinaryWriter(AddStream);
FileStream TempStream = null;
BinaryReader TempReader = null;
//循环合并小文件,并生成合并文件
for (int i = 0; i < strFile.Length; i++)
{
//以小文件所对应的文件名称和打开模式来初始化FileStream文件流,起读取分割作用
TempStream = new FileStream(strFile[i].ToString(), FileMode.Open);
TempReader = new BinaryReader(TempStream);
//读取分割文件中的数据,并生成合并后的文件
AddWriter.Write(TempReader.ReadBytes((int)TempStream.Length));
//关闭BinaryReader文件阅读器
TempReader.Close();
//关闭FileStream文件流
TempStream.Close();
PBar.Value = i + 1;
}
//关闭BinaryWriter文件书写器
AddWriter.Close();
//关闭FileStream文件流
AddStream.Close();
MessageBox.Show("文件合并成功!");
}
#endregion
在frmMain主窗体中,在菜单栏中选择“批量文件处理”/“文件分割”菜单项,弹出“文件分割与合成”窗体,该窗体中默认选择“文件分割”面板,实现代码如下:
//分割文件,打开“分割文件”窗体
private void 文件分割ToolStripMenuItem_Click(object sender, EventArgs e)
{
frmSplit frmsplit = new frmSplit();
frmsplit.tabControl1.SelectedIndex = 0; //默认显示文件分割面板
frmsplit.ShowDialog(); //显示文件分割与合成窗体
}
在frmMain主窗体中,在菜单栏中选择“批量文件处理”/“文件合成”菜单项,弹出“文件分割与合成”窗体,该窗体中默认选择“文件合成”面板,实现代码如下:
//合成文件,打开“合成文件”窗体
private void 文件合成ToolStripMenuItem_Click(object sender, EventArgs e)
{
frmSplit frmsplit = new frmSplit();
frmsplit.tabControl1.SelectedIndex = 1; //默认显示文件合成窗体
frmsplit.ShowDialog(); //显示文件分割与合成窗体
}
“文件分割与合成”窗体frmSplit加载时,首先启动计时器,计时器主要用来监视“分割”按钮和“合成”按钮的可用状态,具体实现代码如下:
private void frmSplit_Load(object sender, EventArgs e)
{
timer1.Start(); //启动计时器
}
//监视“分割”/“合并”按钮的可用状态
private void timer1_Tick(object sender, EventArgs e)
{
if (txtFile.Text != "" && txtPath.Text != "")
btnSplit.Enabled = true;
else
btnSplit.Enabled = false;
if (txtCFile.Text != "" && txtCPath.Text != "")
btnCombin.Enabled = true;
else
btnCombin.Enabled = false;
}
在frmSplit窗体的“文件分割”面板中,单击第1个 按钮,弹出“打开”对话框,选择要分割的文件,单击“打开”按钮,将选择的文件显示在左边的文本框中,实现代码如下:
//选择要分割的文件
private void btnSFile_Click(object sender, EventArgs e)
{
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
txtFile.Text = openFileDialog.FileName; //选择要分割的文件
}
}
在frmSplit窗体的“文件分割”面板中,单击第2个 按钮,弹出“浏览文件夹”对话框,选择分割后的文件存放路径,单击“确定”按钮,将选择的路径显示在左边的文本框中,实现代码如下:
//选择分割后的文件存放路径
private void btnSPath_Click(object sender, EventArgs e)
{
if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
{
txtPath.Text = folderBrowserDialog.SelectedPath; //选择分割后文件的存放路径
}
}
在frmSplit窗体的“文件分割”面板中,单击“分割”按钮,判断是否设置了分割后文件的大小和单位,如果没有设置,弹出信息提示,否则,调用公共类BaseClass中的SplitFile方法分割选择的文件。“分割”按钮的Click事件代码如下:
//执行文件分割操作
private void btnSplit_Click(object sender, EventArgs e)
{
if (txtLength.Text == "")
{
MessageBox.Show("请输入要分割的文件大小!", "提示", MessageBoxButtons.OK, MessageBoxIcon. Information);
txtLength.Focus();
}
else if (cboxUnit.Text == "")
{
MessageBox.Show("请选择要分割的文件单位!", "提示", MessageBoxButtons.OK, MessageBoxIcon. Information);
cboxUnit.Focus();
}
else
{
//分割文件
baseclass.SplitFile(cboxUnit.Text, Convert.ToInt32(txtLength.Text.Trim()), txtPath.Text, txtFile.Text, progressBar);
}
}
在frmSplit窗体的“文件合成”面板中,单击第1个 按钮,弹出“打开”对话框,选择要合成的文件,单击“打开”按钮,将选择的文件显示在左边的文本框中,如果选择了多个要合成的文件,中间用“,”隔开,实现代码如下:
//选择要合成的文件
private void btnCFile_Click(object sender, EventArgs e)
{
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
if (txtCFile.Text == "")
txtCFile.Text = openFileDialog.FileName; //选择要合成的文件
else
txtCFile.Text += "," + openFileDialog.FileName; //将合成的多文件用逗号隔开
}
}
在frmSplit窗体的“文件合成”面板中,单击第2个 按钮,弹出“另存为”对话框,选择合成后的文件存放路径,并输入合成后的文件名,单击“保存”按钮,将选择的路径及输入的文件名显示在左边的文本框中,实现代码如下:
//选择合成后的文件存放路径
private void btnCPath_Click(object sender, EventArgs e)
{
if (saveFileDialog.ShowDialog() == DialogResult.OK)
{
txtCPath.Text = saveFileDialog.FileName; //选择合成后文件的存放路径
}
}
在frmSplit窗体的“文件合成”面板中,单击“合并”按钮,判断选择的要合成的文件是否大于等于两个,如果只有一个,弹出信息提示,否则,调用公共类BaseClass中的CombinFile方法合成选择的文件。“合并”按钮的Click事件代码如下:
//执行合成文件操作
private void btnCombin_Click(object sender, EventArgs e)
{
if (txtCFile.Text.IndexOf(",") == -1)
MessageBox.Show("请选择要合成的文件,最少为两个!", "提示", MessageBoxButtons.OK, Message oxIcon.Information);
else
{
string[] strFiles = txtCFile.Text.Split(',');
baseclass.CombinFile(strFiles, txtCPath.Text,progressBar); //合成文件
}
}