最近遇到了一个 .Net 6 的大问题 (我感觉是一个 Bug)。
Directory.Delete(path, recursive: true)
竟然删不掉 pnpm
安装的 node_modules
(有大量的软链接 和 无效软链接)
var path = "E:\\Work\\ReactProject\\hi-ice\\node_modules";
// 第二个参数是 递归删除
Directory.Delete(path, recursive: true);
执行结果如下:
(卧槽,执行了这么长时间,还敢报错?微软自己的编程语言和标准库都不能完美处理微软自己的系统?后来大概看了下源码,代码倒是挺多,但就是删不成功。。)
又搜了一个普通的递归删除文件的代码(因为系统只能删除空文件夹,所以必须先删文件,再删文件夹)。
执行结果如下:
(果然比标准库的Directory.Delete
还垃圾。甚至基本的处理软链接得自己写。)
搞到这里我已经对 C# 绝望了。
反正是自己的小工具,那我换个语言写吧。
又去试了试 Java
,更气人了,标准库连递归删除都没有,只能用第三方的库,
试了试 commons-lang3
和 hutool
也都报错了,看来这两个库内部实现也没有做到非常的完美。
易语言
也报错了.
NodeJs
的第三方库 rimraf
,终于完美删除,然后我就用 NodeJs
写完了这个小工具。(后来大概看了一下源码,发现处理了很多情况,也算是一个久经沙场的库了。)
接下来又试了几个语言
Python
的 shutil.rmtree(path)
,也完美删除。(不过只能删除文件夹,文件只能自己 if 判断下用 os.remove
)
Golang
的 os.RemoveAll
也完美删除。
C++
搜了下也是一堆写普通递归的代码,直接放弃,连新建项目都懒得搞了。
Rust
的 std::fs::remove_dir_all
,也完美删除。
搞到这里,脑子里突然灵光一闪,
既然 Rust 可以删除,那我直接编译成 DLL,让 C# 调用不就解决了 C# 的大问题。
于是有了下面的 Rust 代码
Cargo.toml
[package]
name = "rm_dir_lib"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib"]
[dependencies]
Rust 代码
use std::{ffi::CStr, fs, os::raw::c_char, path::Path};
#[no_mangle]
pub extern "C" fn rs_rm_dir(path: *const c_char) -> bool {
let c_str = unsafe {
assert!(!path.is_null());
CStr::from_ptr(path)
};
// c 字符串 转为 rust 字符串
let path_str = c_str.to_str().unwrap().to_string();
println!("地址:");
println!("{}", path_str);
let ret = {
if Path::new(&path_str).exists() {
match fs::remove_dir_all(&path_str) {
Ok(_) => true,
Err(err) => {
println!("{}", err);
return false;
}
}
} else {
true
}
};
if ret {
// 检查一下是否真的删掉了
return !Path::new(&path_str).exists();
}
return false;
}
// 测试
#[cfg(test)]
mod tests {
use std::{ffi::CString, fs::create_dir};
use super::*;
#[test]
fn test_rs_rm_dir() {
let path = "E:\\Work\\ReactProject\\hi-ice\\node_modules";
if !Path::new(&path).exists() {
create_dir(&path).unwrap();
}
// 转为 CString
let data = CString::new(path).unwrap();
let res = rs_rm_dir(data.as_ptr());
println!("返回值: {}", res);
assert_eq!(res, true);
}
}
C# 调用一下
// 定义一下
[
DllImport("rm_dir_lib.dll",
EntryPoint = "rs_rm_dir",
CallingConvention = CallingConvention.Cdecl)
]
public static extern bool RsRmDir([MarshalAs(UnmanagedType.LPUTF8Str)] string path);
// 调用
var path = "E:\\Work\\ReactProject\\hi-ice\\node_modules";
var res = RsRmDir(path);
Console.WriteLine(res);
编译 Release,测试两遍,完美删除 ,速度也很稳定和 Rust 几乎相同,
Rust 编译出的 DLL 也只有 150 KB
, 非常的不错啊,
这个 DLL 可以在任何语言中用了.
再来个 Java 调用例子:
DLL 放到 resources 目录下
import com.sun.jna.Library;
import com.sun.jna.Native;
public interface JNATestDll extends Library {
JNATestDll dll = Native.load("rm_dir_lib", JNATestDll.class);
public boolean rs_rm_dir(String path);
}
public class Main {
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
JNATestDll.dll.rs_rm_dir("E:\\Work\\ReactProject\\hi-ice\\node_modules");
long endTime = System.currentTimeMillis();
System.out.printf("执行时长:%d 秒.", (endTime - startTime) / 1000);
}
}
<dependency>
<groupId>net.java.dev.jnagroupId>
<artifactId>jnaartifactId>
<version>5.12.1version>
dependency>