1

我正在使用用 C# 为 Windows 8 编写的桌面应用程序来提供剪贴板上不同设备传感器的读数。现在,有一个外部应用程序(我对其结构没有任何控制权),我的应用程序将与之交互。这两个应用程序都使用相互文本文件作为开关。当外部应用程序需要我的读数时,它会将文本文件重命名为“SensorsTurn.txt”并在剪贴板上放置一个触发词,例如(“sensors”)当我的应用程序看到文件已被这样命名时,它会读取触发器的剪贴板,相应地收集数据,将其放在剪贴板上并将文本文件重命名为“RBsTurn.txt”。问题是,我需要我的程序在运行时不断检查该文件的名称。我想到的一种非常基本的方法是将程序放入无限的while循环中。但这显然是一个非常糟糕的方法。当我在任务管理器中看到我的应用程序时,它占用了大量不应该的 CPU 处理。我发现的另一个建议是让我的循环成为后台线程,这样效率更高一些。但是两次连续读数之间的时间变慢了。我为之工作的人报告说:“我第一次尝试写入剪贴板时,它写入速度非常快,但在随后的写入中大约需要 3 秒(我经常有两个程序与剪贴板通信)。我怀疑你的程序没有以某种方式释放剪贴板。一旦我能够写入剪贴板,我就会更改文件名并立即取回你的数据。

namespace sampleApplication
{
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }
    //Initialize sensor variables
    LightSensorReading _newLightSensorReading;
    LightSensor _LightSensor = LightSensor.GetDefault();

    string _pathString = System.IO.Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "dummy");
    private void Form1_Load(object sender, EventArgs e)
    {
        //InitializeDevices();
        System.IO.Directory.CreateDirectory(_pathString);
        string _filePathSensors = System.IO.Path.Combine(_pathString, "SensorsTurn.txt");
        string _filePathRBsTurn = System.IO.Path.Combine(_pathString, "RBsTurn.txt");
        string _triggerString = "";
        int x = 1;
        Thread th = new Thread(() =>
            {
                while (x == 1)
                {
                    if (System.IO.File.Exists(_filePathSensors))
                    {
                        _triggerString = Clipboard.GetText();
                        switch (_triggerString)
                        {
                            case "sensors":
                                if (_LightSensor != null)
                                {
                                    _newLightSensorReading = _LightSensor.GetCurrentReading();

                                    string _deviceReading = "LightSensor" + "," + _newLightSensorReading.IlluminanceInLux.ToString();
                                    Clipboard.SetText(_deviceReading);
                                    System.IO.File.Move(_filePathSensors, _filePathRBsTurn);
                                }
                                break;
                            case "stop":
                                Clipboard.Clear();
                                System.IO.File.Move(_filePathSensors, _filePathRBsTurn);
                                Application.Exit();
                                break;
                        }
                    }
                }
            });
        th.IsBackground = true;
        th.SetApartmentState(ApartmentState.STA);
        th.Start();
    }
}
}

长话短说,有两个问题:1)如何在不使用低效无限循环的情况下连续检查文件名?我可以以某种方式定义一个事件吗?2)我的程序在使用后没有足够快地释放剪贴板。可能是什么原因?

4

5 回答 5

9

您可以使用File System Watcher对象来响应Renamed事件,而不是不断寻找更改的名称。这可能会完全避免这个问题。

更新:

这是关于该主题的博客文章(之前在评论中提到过)

于 2013-05-06T14:37:44.240 回答
2

正确的做法是创建一个FileSystemWatcher,它会在文件名更改(或创建新文件 - 在文档中解释)时引发事件。

创建/重命名文件时,将触发一个事件,您可以在处理程序的主体中处理并执行您的操作。

于 2013-05-06T14:43:13.583 回答
0

我会使用Timer。这样,您以指定的时间间隔运行,否则不会占用 CPU。从本质上讲,它完成了使用 Thread.Sleep 的 Thread 解决方案所做的事情,但是以一种更清晰、更易读的方式,恕我直言。

using System;
using System.Timers;

public class Timer1
{
    private static System.Timers.Timer aTimer;

    public static void Main()
    {
        // Normally, the timer is declared at the class level, 
        // so that it stays in scope as long as it is needed. 
        // If the timer is declared in a long-running method,   
        // KeepAlive must be used to prevent the JIT compiler  
        // from allowing aggressive garbage collection to occur  
        // before the method ends. You can experiment with this 
        // by commenting out the class-level declaration and  
        // uncommenting the declaration below; then uncomment 
        // the GC.KeepAlive(aTimer) at the end of the method. 
        //System.Timers.Timer aTimer; 

        // Create a timer with a ten second interval.
        aTimer = new System.Timers.Timer(10000);

        // Hook up the Elapsed event for the timer.
        aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);

        // Set the Interval to 2 seconds (2000 milliseconds).
        aTimer.Interval = 2000;
        aTimer.Enabled = true;

        Console.WriteLine("Press the Enter key to exit the program.");
        Console.ReadLine();

        // If the timer is declared in a long-running method, use 
        // KeepAlive to prevent garbage collection from occurring 
        // before the method ends. 
        //GC.KeepAlive(aTimer);
    }

    // Specify what you want to happen when the Elapsed event is  
    // raised. 
    private static void OnTimedEvent(object source, ElapsedEventArgs e)
    {
        Console.WriteLine("The Elapsed event was raised at {0}", e.SignalTime);
    }
}

/* This code example produces output similar to the following:

Press the Enter key to exit the program.
The Elapsed event was raised at 5/20/2007 8:42:27 PM
The Elapsed event was raised at 5/20/2007 8:42:29 PM
The Elapsed event was raised at 5/20/2007 8:42:31 PM
...
 */
于 2013-05-06T14:38:44.763 回答
-1

只需使用无限循环,但在循环结束时,添加一个Thread.Sleep(1000)或类似的东西。然后它不会使用你所有的 CPU 时间。将数字调整为所需的检查频率。

于 2013-05-06T14:36:08.763 回答
-2

让您的线程调用包含 while 循环的方法。

于 2013-05-06T14:37:34.753 回答