头图

写个 .NET 程序解决 Windows 版微信 3.9 收到文件“只读”的问题

Windows 版微信升级到 3.9 之后,接收到的文件都变成了只读属性,对需要经常修改微信接收文件进行交流的人来说极为不便。虽然从业务功能上来说,需要频繁交流的文档还是用在线协同(比如腾讯文档)比较好一些,但从技术的角度来看,应该如何解决这个问题呢?

其实很多技术栈都提供了监听系统文件变化的 API,比如 .NET 就在其 System.IO 命名空间下提供了 FileSystemWatcher 类用于监听文件的变化,包括创建文件、删除文件、文件改名/移动、文件属性变化等。所以可以使用 C# 和 .NET 快速的写一个程序用来监听指定文件夹下的新建文件,如果新创建的文件属性是只读,则去掉其只读属性。

第一步,找到微信接收文件的目录。

在微信的「设置→文件管理」中就可以找到,比如 C:\Users\James\Documents\WeChat Files。然后需要识别这个目录下的用户目录,一般是微信号。点击微信窗口上自己的头像就可以看到。用户目录下的 FileStorage\File 目录就是我们的目标目录了。

为了帮助用户快速定位到这个目录,在假设用户没有手工改变微信文件目录的情况下,可以这样来查找

  • 通过 Environment.GetFolderPath() 获取到当前用户的“文档”目录;
  • 拼接得到 WeChat Files 目录的路径;
  • 遍历 WeChat Files 目录下的子目录,去掉特殊命名的 All UsersApplet 等,在剩下的子目录中进一步猜测
  • 一般最近访问过的就是自己的微信账号目录

那么整个猜测目录的过程代码示例如下:

string? GuessReceivePath() {
    var docDir = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
    var wxDir = Path.Combine(docDir, "WeChat Files");
    if (!Directory.Exists(wxDir)) { return null; }

    HashSet<string> excludes = new(StringComparer.InvariantCulture) {
        "All Users",
        "Applet"
    };

    var userDir = Directory.EnumerateDirectories(wxDir)
        .Select(it => new FileInfo(it))         // 对每个目录产生 FileInfo 对象(小性能损耗可以忽略)
        .ExceptBy(excludes, fi => fi.Name)      // 去掉特定名称的目录
        .OrderByDescending(it => it.LastAccessTime)    // 按最近访问时间排序
        .FirstOrDefault()                       // 取最最后访问的那一个,注意有可能是 null
        ?.FullName;                             // 取得完整路径

    if (userDir == null) { return null; }
    return Path.Combine(userDir, "FileStorage", "File");
}

当然,猜测的目录不一定准确,所以写程序的时候最好能提供给用户一个可以手工修改/设置目录的手段,当然别忘了目录的有效性检查(检查目录存在)。

第二步,监听文件创建

监听文件变化只需要新建一个 FileSystemWatcher 对象,设置一些属性即可。

  • 设置 Path 到要监听的目录
  • 设置 .IncludeSubdirectories = true 表示需要监听其子目录
  • 添加 Created 事件在监听到有文件创建时进行处理

示例代码:

var watcher = new FileSystemWatcher() {
    IncludeSubdirectories = true,
};

watcher.Created += (_, e) => { ... };

第三步,对监听到的新建文件进行处理

如果目录下有新创建的文件,上面 Created 事件的 e 参数(FileSystemEventArgs 类型)会携带文件的信息,通过 e.FullPath 可以拿文件的完整路径。然后使用 FileInfo 判断其是否只读,并解除其只读属性即可:

(_, e) => {
    var info = new FileInfo(e.FullPath);
    if (info.IsReadOnly) {
        info.IsReadOnly = false;
        Log($"[去掉只读] {e.Name}");
    }
};

第四步,监听文件属性变更

实际使用中发现,只有在发送文件的时候,会在微信文件目录创建只读文件。接收文件的时候多数是收到的非只读文件,然后再改成只读属性的。所以还需要监听文件属性的变化。

这样就需要设置 FileSystemWatcher 对象的 NotifyFilter 属性,把 NotifyFilters.Attributes 标记加上。NotifyFilter 的默认值是 LastWriteFileNameDirectoryName,所以修改之后(不需要处理目录)是:

var watcher = new FileSystemWatcher() {
    IncludeSubdirectories = true,
    NotifyFilter = NotifyFilters.LastWrite
        | NotifyFilters.Attributes
        | NotifyFilters.FileName,
};

此外还需要为 wathcer 添加 Changed 事件的处理函数,在这里检查并修改文件属性:

watcher.Changed += (_, e) => {
    new FileInfo(e.FullPath).Also(info => {
        if (info.IsReadOnly) {
            info.IsReadOnly = false;
            Log($"[改为可写] {e.Name}");
        }
    });
};
注:AlsoViyi.Util 提供的扩展。

第五步,界面和用户体验

麻雀虽小,但也应该是五脏俱全。核心功能完成之后就需要考虑用户操作界面和使用体验上的一些问题。不用考虑得太复杂,但至少也应该考虑:

  • 这是一个常驻类应用,虽然不用注册成系统服务,但也应该考虑使用系统任务栏图标方式常驻;
  • 允许用户修改路径,开始/停止监听操作;
  • 提供简单的日志功能,让用户知道它处理了哪些文件。

image.png


相关资源


边城客栈
全栈技术专栏,公众号「边城客栈」,[链接]

一路从后端走来,终于走在了前端!

58.1k 声望
28.5k 粉丝
0 条评论
推荐阅读
羡慕 C# 的 switch 表达式不,JS 也可以有
对于 C/Java 语系的语言,都有 switch 语法。switch 语法用于多分支是一个标准的用法,但这个分支语法的各分支之间存在穿透性,所以需要 break 来切断逻辑,这也成为 switch 语法中最重要的一个替在缺陷来源。此...

边城2阅读 1.3k

封面图
async/await 在 C# 语言中是如何工作的?(中)
迭代器允许你编写一个方法,然后由编译器用来实现 IEnumerable&lt;T&gt; 和/或 IEnumerator&lt;T&gt;。例如,如果我想创建一个产生斐波那契数列的枚举数,我可以这样写:

微软技术栈1阅读 414

封面图
【紧急】微信存在图片闪退漏洞
已经很久没在社区发帖了,考虑到今晚很多普通用户,当然也有程序员朋友中招,因此简单聊聊。因为是技术社区,没有正式安全报告那么严谨,因此排版简单,字数不多,希望你能看懂。

瞿小凯阅读 802

封面图
使用nssm将.net core的woker service 注册为windows服务
使用 NSSM (Non-Sucking Service Manager) 可以将 .NET Core Worker Service 注册成 Windows 服务。请按照以下步骤操作:

Chobits阅读 602

C#开发租房管理系统
访问【WRITE-BUG数字空间】_[内附完整源码和文档]房屋租赁管理系统是管理房屋出租、出售信息资料而设计的信息管理系统,包含有后台数据库和前台应用程序系统两大部分,后台数据库要求数据的一.致性和完整性、安全...

老大小跟班阅读 562

封面图
比特熊故事汇2.0 | 机会从不是偶遇的,就趁现在做这个决定
最近天气渐暖,比特熊直播间热闹起来,迎来久违的纯线下直播!本期嘉宾相信很多人都不会陌生,他可是开发圈的“大红人”!这位到访嘉宾除了技术过硬且涉猎广泛,他的个人故事也相当有趣,比特熊不能一“熊”听得津津...

微软技术栈阅读 519

封面图
.NET 8 预览版 1 发布!
.NET 8 是一个长期支持(LTS) 版本。这篇文章涵盖了推动增强功能优先级排序和选择开发的主要主题和目标。.NET 8 预览版和发布候选版本将每月交付一次。像往常一样,最终版本将在 11 月的某个时候在 .NET Conf 上发...

微软技术栈阅读 505

封面图

一路从后端走来,终于走在了前端!

58.1k 声望
28.5k 粉丝
宣传栏