目录:
引言:
汁粥嗦粽,C#呢,有n种复制文件的方法,如Copy()方法,CopyTo()方法.
两种复制的用法:
1. Copy():
File.Copy(SourcePath, TargetPath, IsOverWrite);
(1) SourcePath:要复制的文件路径 类型:string
(2) TargetPath:复制后文件存放文件夹 类型:string
(3) IsOverWrite:是否覆盖写入 类型:bool
2. CopyTo():
File Source = new File(SourcePath);
Source.CopyTo(TargetPath, IsOverWrite);
(1) SourcePath:要复制的文件路径 类型:string
(2) TargetPath:复制后文件存放文件夹 类型:string
(3) IsOverWrite:是否覆盖写入 类型:bool
(4) Source:File类的对象 类型:File
但是它们都不能显示进度条.
对啊,这一搜,没有一个趁我心的,难道这个就无解了吗?
当然不.
所以我做了这个教程.
实战引入:我要做一个复制文件的WPF项目,既追求效率、性能还需要进度条显示.
一、布局
先在你要复制的Window中(我这里是MainWindow.xaml),创建
序号 | 类型 | 名称 | 作用 |
1. | TextBox | PathShower | 显示选择的路径 |
2. | Button | Select | 打开OpenFileDialog选择文件 |
3. | Button | CopyBtn | 点击后复制文件 |
4. | TextBox | DisplayCopyInfo | 显示复制信息 |
5. | ProgressBar | CopyProgress | 显示复制进度 |
6. | Button | OpenDirectory | 打开复制后的文件夹 |
可以自定义名称,但是在后面的代码部分要跟着改.
这里还是贴出我的MainWindow.xaml
<Window x:Name="MainWindow1" x:Class="Main.UI.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Main.UI"
mc:Ignorable="d"
Title="Main.UI" Height="720" Width="1280" ResizeMode="NoResize" WindowStartupLocation="CenterScreen" FontSize="16" Closing="MainWindow_Closing">
<Grid>
<Button x:Name="CopyBtn" Content="复制" Margin="70,145,944,489" Click="CopyBtn_Click"/>
<TextBox x:Name="PathShower" Margin="70,70,944,565" TextWrapping="Wrap" Height="70.0766666666667" UndoLimit="1000">
<TextBox.Resources>
<VisualBrush x:Key="HelpBrush" TileMode="None" Opacity="0.3" Stretch="None" AlignmentX="Left">
<VisualBrush.Visual>
<TextBlock FontStyle="Italic" Text="[Click Botton Or Input There]"/>
</VisualBrush.Visual>
</VisualBrush>
</TextBox.Resources>
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<Trigger Property="Text" Value="{x:Null}">
<Setter Property="Background" Value="{StaticResource HelpBrush}"/>
</Trigger>
<Trigger Property="Text" Value="">
<Setter Property="Background" Value="{StaticResource HelpBrush}"/>
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
<Button x:Name="Select" Content="选择..." Margin="341,70,869,564" Click="Select_Click"/>
<ProgressBar x:Name="CopyProgress" Margin="70,295,944,339" d:LayoutOverrides="VerticalAlignment"/>
<TextBox x:Name="DisplayCopyInfo" Margin="70,220,944,415" TextWrapping="Wrap" Text="就绪" FontSize="16" Height="70.0766666666667"/>
<Button x:Name="OpenDirectory" Content="打开复制后文件的存放文件夹" Margin="70,370,944,264" Click="OpenDirectory_Click"/>
</Grid>
</Window>
二、主程序
1. 定义变量:
public string FilePath = string.Empty;
public string LocalPath = string.Empty;
private string Creator = Environment.CurrentDirectory + @"\res";
private Thread CopyThread;
注:
(1) FilePath:要复制的文件路径
(2) LocalPath:复制后文件存放文件夹
(3) Creator:当文件夹不存在时,创建该文件夹所用到的字符串
(4) CopyThread:复制线程
2. 选择文件
private void Select_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Title = "请选择要上传的文件.";
openFileDialog.Filter = "所有类型的文件|*.*";
openFileDialog.FileName = string.Empty;
openFileDialog.FilterIndex = 1;
openFileDialog.Multiselect = false;
openFileDialog.RestoreDirectory = false;
openFileDialog.CheckFileExists= true;
try
{
openFileDialog.ShowDialog();
FilePath = Path.GetFullPath(openFileDialog.FileName);
if (!Directory.Exists(Creator)) Directory.CreateDirectory(Creator);
LocalPath = Environment.CurrentDirectory + @"\res\" + Path.GetFileName(openFileDialog.FileName);
PathShower.Text = LocalPath;
}
catch (ArgumentException)
{
MessageBox.Show("请选择一个文件.");
}
catch (Exception)
{
MessageBox.Show("请合理输入文件路径.");
}
}
注:
这里主要运用了OpenFileDialog用于选择文件(当然文本框也可以).
3. 复制
(1) 复制信息类
public class CopyFileInfo
{
public string SourcePath { get; set; }
public string TargetPath { get; set; }
}
注:
原理很简单,就是定义两个属性,不多赘述.
(2) 复制文件方法
private void CopyFile(object obj)
{
CopyFileInfo? c = obj as CopyFileInfo;
CopyFile(c.SourcePath, c.TargetPath);
}
private void CopyFile(string SourcePath, string TargetPath)
{
FileInfo F = new FileInfo(SourcePath);
FileStream FSR = F.OpenRead();
FileStream FSW = File.Create(TargetPath);
long FileLength = F.Length;
byte[] Buffer = new byte[2097152];
int n = 0;
while (true)
{
DisplayCopyInfo.Dispatcher.BeginInvoke(DispatcherPriority.SystemIdle,
new Action<long, long>(UpdateCopyProgress), FileLength, FSR.Position);
n=FSR.Read(Buffer, 0, 2097152);
if (n==0)
{
break;
}
FSW.Write(Buffer, 0, n);
FSW.Flush();
}
FSR.Close();
FSW.Close();
}
这里就是一个很基本的复制文件的方法了.
注:
byte[] Buffer = new byte[2097152];
这行代码中的2097152代表每次复制文件的长度,可以改动,但不能太大,会报错. 这个速度已经很快了,没有特殊需求默认即可.
(3) 事件触发
private void CopyBtn_Click(object sender, RoutedEventArgs e)
{
try
{
CopyProgress.Maximum = new FileInfo(FilePath).Length;
//保存文件信息
CopyFileInfo copy = new CopyFileInfo() { SourcePath = FilePath, TargetPath = LocalPath };
//异步调用
CopyThread = new Thread(new ParameterizedThreadStart(CopyFile));
//实例化线程
CopyThread.Start(copy);
//启动线程
}
catch
{
MessageBox.Show("请选择或输入文件路径及名称!");
}
}
4. 更新进度条
private void UpdateCopyProgress(long FileLength, long CurrentLength)
{
DisplayCopyInfo.Text = string.Format("总长度:{0}, 已复制:{1}", FileLength, CurrentLength);
CopyProgress.Value = CurrentLength;
}
注:
这里使用了ProgressBar类型的CopyProgress对象的属性Value.
5. 打开本地文件夹
public static void command(string input)
{
Process CmdProcess = new Process();
CmdProcess.StartInfo.FileName = "cmd.exe";
CmdProcess.StartInfo.CreateNoWindow = true;
CmdProcess.StartInfo.UseShellExecute = false;
CmdProcess.StartInfo.RedirectStandardInput = true;
CmdProcess.StartInfo.RedirectStandardOutput = true;
CmdProcess.StartInfo.RedirectStandardError = true;
CmdProcess.StartInfo.Arguments = "/c " + input;
CmdProcess.Start();
CmdProcess.WaitForExit();
CmdProcess.Close();
}
private void OpenDirectory_Click(object sender, RoutedEventArgs e)
{
if (!Directory.Exists(Creator)) Directory.CreateDirectory(Creator);
command("explorer \"" + Environment.CurrentDirectory + "\\res\"");
}
注:
这里使用了Process类来达到打开文件夹的效果.
6. 关闭窗口确认
private void MainWindow_Closing(object sender, CancelEventArgs e)
{
MessageBoxResult result = MessageBox.Show("是否退出?", "退出确认", MessageBoxButton.OKCancel, MessageBoxImage.Question);
if (result == MessageBoxResult.Cancel)
{
e.Cancel = true;
}
else
{
Environment.Exit(0);
}
}
注:
需要在xaml里添加关闭事件:Closing="MainWindow_Closing".
三、完整代码
using Microsoft.Win32;
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Threading;
namespace Advanced_Copy
{
public partial class MainWindow : Window
{
public string FilePath = string.Empty;
public string LocalPath = string.Empty;
private string Creator = Environment.CurrentDirectory + @"\res";
private Thread CopyThread;
public MainWindow()
{
InitializeComponent();
}
private void CopyBtn_Click(object sender, RoutedEventArgs e)
{
try
{
CopyProgress.Maximum = new FileInfo(FilePath).Length;
CopyFileInfo copy = new CopyFileInfo() { SourcePath = FilePath, TargetPath = LocalPath };
CopyThread = new Thread(new ParameterizedThreadStart(CopyFile));
CopyThread.Start(copy);
}
catch
{
MessageBox.Show("请选择或输入文件路径及名称!");
}
}
private void Select_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Title = "请选择要上传的文件.";
openFileDialog.Filter = "所有类型的文件|*.*";
openFileDialog.FileName = string.Empty;
openFileDialog.FilterIndex = 1;
openFileDialog.Multiselect = false;
openFileDialog.RestoreDirectory = false;
openFileDialog.CheckFileExists= true;
try
{
openFileDialog.ShowDialog();
FilePath = Path.GetFullPath(openFileDialog.FileName);
if (!Directory.Exists(Creator)) Directory.CreateDirectory(Creator);
LocalPath = Environment.CurrentDirectory + @"\res\" + Path.GetFileName(openFileDialog.FileName);
PathShower.Text = LocalPath;
}
catch (ArgumentException)
{
MessageBox.Show("请选择一个文件.");
}
catch (Exception)
{
MessageBox.Show("请合理输入文件路径.");
}
}
private void CopyFile(object obj)
{
CopyFileInfo? c = obj as CopyFileInfo;
CopyFile(c.SourcePath, c.TargetPath);
}
private void CopyFile(string SourcePath, string TargetPath)
{
FileInfo F = new FileInfo(SourcePath);
FileStream FSR = F.OpenRead();
FileStream FSW = File.Create(TargetPath);
long FileLength = F.Length;
byte[] Buffer = new byte[2097152];
int n = 0;
while (true)
{
DisplayCopyInfo.Dispatcher.BeginInvoke(DispatcherPriority.SystemIdle,
new Action<long, long>(UpdateCopyProgress), FileLength, FSR.Position);
n=FSR.Read(Buffer, 0, 2097152);
if (n==0)
{
break;
}
FSW.Write(Buffer, 0, n);
FSW.Flush();
}
FSR.Close();
FSW.Close();
}
private void UpdateCopyProgress(long FileLength, long CurrentLength)
{
DisplayCopyInfo.Text = string.Format("总长度:{0}, 已复制:{1}", FileLength, CurrentLength);
CopyProgress.Value = CurrentLength;
}
private void OpenDirectory_Click(object sender, RoutedEventArgs e)
{
if (!Directory.Exists(Creator)) Directory.CreateDirectory(Creator);
Command.command("explorer \"" + Environment.CurrentDirectory + "\\res\"");
}
private void MainWindow_Closing(object sender, CancelEventArgs e)
{
MessageBoxResult result = MessageBox.Show("是否退出?", "退出确认", MessageBoxButton.OKCancel, MessageBoxImage.Question);
if (result == MessageBoxResult.Cancel)
{
e.Cancel = true;
}
else
{
Environment.Exit(0);
}
}
}
public class CopyFileInfo
{
public string SourcePath { get; set; }
public string TargetPath { get; set; }
}
}
四、效果图
教程到此结束,感谢参考!
Made By HXLyxx On 2022.12.15