【问题标题】:FileSystem Watcher- Checking if copied file is an ImageFileSystem Watcher - 检查复制的文件是否为图像
【发布时间】:2016-07-21 04:23:49
【问题描述】:

我正在使用 FileSystem Watcher 监视文件夹的文件创建(复制)事件。我只希望程序处理图像文件。

FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Filter = "*.*";
watcher.Created += new FileSystemEventHandler(watcher_FileCreated);
watcher.Path = path;

所以我尝试创建一个位图并在抛出异常时避免该文件

private static void watcher_FileCreated(object sender, FileSystemEventArgs e)
{
    try
    {
        using (Bitmap test = new Bitmap(Bitmap.FromFile(e.FullPath)))
        {
            mytoprocesslist.add(e.FullPath);
        }

        //do my processing with image 
        Console.WriteLine(e.FullPath);
    }
    catch (Exception error)
    {
       Console.WriteLine("File Error");
    }
 }

即使复制了有效的图像文件,这也会引发Out of Memory exception,我认为这是因为在完全复制文件之前引发了事件。我怎样才能克服这个?我只想将有效的图像文件添加到待办事项列表中,稍后我将一一处理这些图像。

【问题讨论】:

  • 上面的代码似乎没有任何可能导致内存不足的行。很可能您的“//对图像进行处理”正在引发此错误。如果您觉得文件尚未完全复制,您可以添加等待 1 秒。
  • @puneet using (Bitmap test = new Bitmap(Bitmap.FromFile(e.FullPath)))
  • 我设置了watcher.NotifyFilter = NotifyFilters.FileName; 并加载图像,我使用的是Image.FromFile(e.FullPath);,它可以正常工作,没有任何异常。
  • 对于对此投反对票的人,最好发表评论。
  • @x...设置watcher.NotifyFilter = NotifyFilters.FileName;有什么作用?

标签: c# .net filesystemwatcher


【解决方案1】:

比 Try-Catch 更清洁的解决方案可能是这个。 我正在使用此代码,没有引发任何异常。

private static bool IsImage(string path) {
      try {
        var result = false;

        using (var stream = new FileStream(path, FileMode.Open)) {
          stream.Seek(0, SeekOrigin.Begin);

          var jpg = new List<string> { "FF", "D8" };
          var bmp = new List<string> { "42", "4D" };
          var gif = new List<string> { "47", "49", "46" };
          var png = new List<string> { "89", "50", "4E", "47", "0D", "0A", "1A", "0A" };
          var imgTypes = new List<List<string>> { jpg, bmp, gif, png };

          var bytesIterated = new List<string>();

          for (var i = 0; i < 8; i++) {
            var bit = stream.ReadByte().ToString("X2");
            bytesIterated.Add(bit);

            var isImage = imgTypes.Any(img => !img.Except(bytesIterated).Any());
            if (isImage) {
              result = true;
              break;
            }
          }
        }
        return result;
      } catch (UnauthorizedAccessException) {
        return false;
      }
    }

代码的使用

foreach (var file in Directory.EnumerateFiles(@"pathToFlowersFolder"))
            {
                Console.WriteLine($"File: {file} Result:{IsImage(file)}");
            }

编辑

玩了之后,我得到了一个 IO 异常(文件已在使用中)
阅读this 后,我会为您提供以下解决方案:

private void button1_Click(object sender, EventArgs e)
        {
            var watcher = new FileSystemWatcher();
            watcher.Created += new FileSystemEventHandler(fileSystemWatcher1_Changed);
            watcher.Path = @"c:\temp";
            watcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.Size;
            watcher.EnableRaisingEvents = true;
        }

        private void fileSystemWatcher1_Changed(object sender, System.IO.FileSystemEventArgs e)
        {
            Thread.Sleep(100); // <- give the Creator some time. Increase value for greate pause
            if (IsImage(e.FullPath))
            {
                Console.WriteLine("success----------->" + e.FullPath);
            }
        }

注意

这段代码可以在我的机器上正常运行。我的 HDD 是 SSD,因此您可能需要增加线程休眠时间。它适用于大小不超过 7 Mb 的所有图像(jpg、bmp、gif、png)(我非常确定并且更大)。

如果此代码不适合您,请发布异常而不是上传您的代码。

【讨论】:

  • 谢谢...我会尝试回来...顺便说一句我没有投反对票:)
  • 这无法正确检测到一些 jpg 图像。
  • 你能举个例子吗? jpg 的幻数应该以FFd8 开头。多次声明here
  • 请看这个压缩包里的图片wikisend.com/download/868908/Flowers.zip
  • 无法重现您的陈述。您的 zip 中的每张图片都被视为带有已发布代码的有效图片。
【解决方案2】:

对于第一个要求:“我只希望程序处理图像文件”

private static void fileSystemWatcher1_Changed(object sender, FileSystemEventArgs e)
{
  string strFileExt = getFileExt(e.FullPath); 

  // filter file types 
  if (Regex.IsMatch(strFileExt, @"\.png|\.jpg", RegexOptions.IgnoreCase)) 
  { 
      //here Process the image file 
  }
} 

对于第二个要求:“Out of Memory Exception”

这里发生的情况是,当文件被创建(只有文件名和一些属性)时,系统正在调用 created 事件。然后文件更改事件也被调用

所以你必须在 changed 事件中进行处理。此外,为了防止重复呼叫,您必须向观察者添加过滤器。

以下是完整代码。

private void fileSystemWatcher1_Changed(object sender, System.IO.FileSystemEventArgs e)
        {

            FileInfo fileInfo = new FileInfo(e.FullPath);
            string strFileExt = fileInfo.Extension;

            // filter file types 
            if (Regex.IsMatch(strFileExt, @"\.png|\.jpg", RegexOptions.IgnoreCase))
            {
                //here Process the image file 
                try
                {
                    using (Bitmap test = new Bitmap(Bitmap.FromFile(e.FullPath)))
                    {
                        //Do your code here.
                    }
                }
                catch (Exception error)
                {
                    Console.WriteLine("File Error");
                }
            }


        }

        private void Form1_Load(object sender, EventArgs e)
        {
            fileSystemWatcher1.Path = @"C:\Users\Christlin\Desktop\res";

            //To Prevent duplicated calling of changed event
            fileSystemWatcher1.NotifyFilter = NotifyFilters.FileName | NotifyFilters.Size;
        }

【讨论】:

  • 谢谢...你已经挂钩了更改事件和创建事件...我应该挂钩这两个事件吗?
  • 根据 OP 要求,这可能还不够。例如,我可以通过给它另一个扩展名(例如.txt)来轻松伪装图像。
  • @techno 仅更改和 Form1_Load 事件就够了
  • @Christian.K 感谢您的注意,在这种情况下,我们甚至可以在不检查文件扩展名的情况下处理文件,并通过创建代码的位图部分来处理它。
  • @ChristlinJoseph 在复制 10 张大小超过 1 MB 的图像时,我仍然收到 A first chance exception of type 'System.OutOfMemoryException' occurred in System.Drawing.dll。看来旧问题仍然存在。这是因为图像没有完全复制。
猜你喜欢
  • 2012-11-25
  • 2011-01-12
  • 2013-08-15
  • 2013-03-02
  • 2014-11-25
  • 1970-01-01
  • 1970-01-01
  • 2014-03-11
  • 2013-01-13
相关资源
最近更新 更多