所以,基本上,我正在制作一个程序,其中25个任务将相同的随机任务写入一个文件,直到它达到一定的大小,并且我希望以0.5秒的间隔动态显示所选文件的文件大小,所以我制作了一个与Timer_Elapsed
挂钩的计时器,它应该每0.5秒执行一次,并在UI上显示,我在mainWindow.xaml的文本块x:Name=“fileSize”中指定了这个UI,所以我将createTimer
函数放在mainwindow.xaml.cs中的btnGo_Click
函数中,这样事件将提取selectedFile
的正确fileInfo
。如果有任何错误的建议,我将不胜感激。我还在需要的情况下共享FileIO
类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Windows;
using System.Threading;
namespace WriteFile
{
internal class FileIO
{
private object _lock = new object();
public volatile bool sizeReached = false;
private StreamWriter sw = null;
Mutex mut = null;
public FileIO()
{
if (!Mutex.TryOpenExisting("MyMutex", out mut))
{
mut = new Mutex(true, "MyMutex");
mut.ReleaseMutex();
}
}
internal void WriteFile(string FilePath)
{
while (!sizeReached)
{
mut.WaitOne();
try
{
using (sw = new StreamWriter(FilePath, true))
{
sw.WriteLine(Guid.NewGuid());
}
}
catch (Exception ex)
{
MessageBox.Show("Exception: " + ex.Message);
}
finally
{
if (sw != null)
{
sw.Close();
}
}
mut.ReleaseMutex();
}
}
internal void SizeMonitor(string FPath, int MaxSize, Task[] tasks)
{
FileInfo fi = null;
while (!sizeReached)
{
if (File.Exists(FPath))
{
fi = new FileInfo(FPath);
if (fi.Length >= MaxSize)
{
sizeReached = true;
}
}
if (sizeReached)
{
foreach (Task task in tasks)
{
task.Wait();
}
}
Thread.Sleep(1);
}
MessageBox.Show(fi.Length.ToString());
MessageBox.Show("Done");
}
}
}
mainWindow.xaml
<Window x:Class="WriteFile.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:WriteFile"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<TextBlock x:Name="fileSize"/>
<TextBox Name ="TargetSize" VerticalAlignment="Center" FontSize="20">
</TextBox>
<Label Content="Target Size" HorizontalAlignment="Left" Margin="92,150,0,0" VerticalAlignment="Top"/>
<Button Name ="btnGo" Content="Write to file" HorizontalAlignment="Left" Margin="92,267,0,0" VerticalAlignment="Top" Width="100" Click="btnGo_Click"/>
</Grid>
</Window>
mainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO;
using Microsoft.Win32;
using System.ComponentModel;
using System.Timers;
using System.Threading;
using System.Runtime.CompilerServices;
namespace WriteFile
{
public partial class MainWindow : Window
{
System.Timers.Timer timer = new System.Timers.Timer();
Task[] tasks;
Task MonitorTask;
static FileIO fio = new FileIO();
static string fPath;
static FileInfo fileInfo;
public MainWindow()
{
InitializeComponent();
CreateTimer();
}
public void CreateTimer()
{
var timer = new System.Timers.Timer(500); // fire every 0.5 second
timer.Enabled = true;
timer.Elapsed += Timer_Elapsed;
}
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
fileSize.Text = fileInfo.Length.ToString();
}
private void btnGo_Click(object sender, RoutedEventArgs e)
{
SaveFileDialog saveFileDialog = new SaveFileDialog();
saveFileDialog.ShowDialog();
Stream myStream;
saveFileDialog.FilterIndex = 2;
saveFileDialog.RestoreDirectory = true;
if (File.Exists(saveFileDialog.FileName))
{
File.Delete(saveFileDialog.FileName);
}
if ((myStream = saveFileDialog.OpenFile()) != null)
{
StreamWriter sw = new StreamWriter(myStream);
sw.Write(" your text");
myStream.Close();
}
int NoOfTasks = 25;
int Target = Convert.ToInt32(TargetSize.Text);
fPath = saveFileDialog.FileName;
tasks = new Task[NoOfTasks];
fio.sizeReached = false;
fileInfo = new FileInfo(fPath);
for (int i = 0; i < NoOfTasks; i++)
{
tasks[i] = new Task(() => fio.WriteFile(fPath));
tasks[i].Start();
}
MonitorTask = new Task(() => fio.SizeMonitor(fPath, Target, tasks));
MonitorTask.Start();
}
}
}
2条答案
按热度按时间rryofs0p1#
正如其他人所提到的,
FileInfo.Length
值是预先缓存的。如果关联的文件已经更改,FileInfo
需要刷新那些缓存的值。要完成此操作,您必须显式调用FileInfo.Refresh
方法。FileInfo
不监视关联的文件。此外,
System.Threading.Timer
在后台线程上执行回调。在WPF中,您只能从调度程序线程(UI线程)引用DispatcherObject
(例如TextBlock
)。因此,您应该使用DispatcherTimer
。DispatcherTimer
在调度程序线程上执行回调。此外,您可能希望在写入文件完成后停止计时器。
您不应该使用
Task.Start
。除了Task.Start
和Mutex
之外,您只应该使用await
来取代Task
。在您的内容中,您可以使用Task.WhenALl
来await
Task
对象的集合。您应该使用
StreamWriter
的async
API,而不是显式创建Task
。您实际上没有并发代码(您也不会从中受益):
volatile
字段的Mutex
、声明和锁定对象是冗余的。此外,由于您已经使用using
块来处理示例的生存期,因此不需要在finally
块中显式关闭StreamWriter
。您的代码中还有一些缺陷(例如一些逻辑问题)。我已经重构了您的版本以消除一些问题,例如通过使用异步
StreamWriter
API和async/await。因为很难理解你的代码(由于缺少上下文),所以不可能进一步改进它。例如,创建一个连接字符串(例如由25个值组成)将导致一个文件写入(和资源分配),这将显著提高整体性能。
文件IO.cs
主窗口.xaml.cs
kyks70gy2#
计时器。计时器异步工作,如果未设置SynchronizingObject,它将在池线程上引发Elapsed事件。使用WPF UI元素只能在其Dispatcher的线程上完成(几乎总是应用程序的主UI线程)。
从众多可能的解决方案中选择两个:
第二个选项是不使用计时器: