知识创造技术 技术改变世界

------ Oracle中文开发者社区 ------

二维码 二维码 二维码 二维码 二维码 二维码
如果你想要学习编程,关注本博客,持续获得技术支持,持续获得技术咨询

java开发·企业官方账号 Oracle中国官方账号 Java中国管理部 全网粉丝30万+ 华为云享专家 阿里专家博主 CSDN内容合伙人 CSDN原力计划作者 51CTO专家博主 CSDN博客V账号 毕业于四川大学新闻与文学学院 精通java,Python,HTML,掌握了PHP,C语言,C++,C#,JavaScript,Visual Basic等二十余种编程语言的技巧,会分享一些编程心得、面试技巧和编程方法。


其他链接

主页 官网 社区 论坛

文章目录


最近遇到了一个 .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);

执行结果如下:

开始删除 E:\Work\ReactProject\hi-ice\node_ _modules 
System.I0.IOException:参数错误:'Lodash.debounce' 
  at System.I0.FileSystem.RemoveDirectoryRecursive(String fullPath, WIN32_FIND_DATA& findData, Boolean topLevel) 
  at system.I0.Filesystem.RemoveDirectory(string fullPath,Boolean'recursive) 
  at System.I0.Directory.Delete(string path, Boolean recursive) 
  at RmDirDemo.Program.MyFun() 删除结束,耗时 17608.6092

(卧槽,执行了这么长时间,还敢报错?微软自己的编程语言和标准库都不能完美处理微软自己的系统?后来大概看了下源码,代码倒是挺多,但就是删不成功。。)

又搜了一个普通的递归删除文件的代码(因为系统只能删除空文件夹,所以必须先删文件,再删文件夹)。

执行结果如下:
(果然比标准库的Directory.Delete 还垃圾。甚至基本的处理软链接得自己写。)

开始删除 E:\Work\ReactProject\hi-ice\node_modules
System.10.DirectoryNotFoundException: Could not find a part of the path 'E:\Work\ReactProject\hi-ice\node_inodules\.pnpin\@antdesign+icons@4.7.0_sfoxds7t5ydpegc3knd667wn6m\node_modules\@antdesign\colors.
  at System.10.Enumeration.FileSystemEnumerator'1.CreateDirectoryHandle(String path, Boolean ignoreNotFound)
  at System.10. Enumeration.FileSystemEnumerator'1.InitC)
  at System.10.Enumeration.FileSystemEnumerator'1..ctor(String directory, Boolean isNormalized,Enumerationoptions options)
  at System.10.Enumeration.FileSystemEnumerable'1..ctor(String directory,FindTransformtransform,Enumerationoptionsoptions, Boolean isNormalized)
  at System.10.Enumeration.FileSystemEnumerableFactory.UserEntries(String directory, String expression,EnumerationOptions options)
  at System.10.Directory.InternalEnumeratePaths(String path, String searchPattern, SearchTargetsearchTarget,Enumeration Options options)
  at System.10. Directory.EnumerateFileSystemEntriesCstring path)
  at RmDirDemo. Program.DeleteDirectory(String path) in                     E:\Work\CSharpProject\RmDirDemo\RmDirDemo\Program.cs:line 24
  at RmDirDemo. Program.DeleteDirectory(String path) in                     E:\Work\CSharpProject\RmDirDemo\RmDirDemo\Program.cs:line 29
  at RmDirDemo. Program.DeleteDirectory(String path) in                     E:\Work\CSharpProject\RmDirDemo\RmDirDemo\Program.cs:line 29
  at RmDirDemo. Program.DeleteDirectory(String path) in                     E:\Work\CSharpProject\RmDirDemo\RmDirDemo\Program.cs:line 29
  at RmDirDemo. Program.DeleteDirectory(String path) in                     E:\Work\CSharpProject\RmDirDemo\RmDirDemo\Program.cs:line 29
  at RmDirDemo. Program.DeleteDirectory(String path)               in E:\Work\CSharpProject\RmDirDemo\RmDirDemo\Program.cs:line        29
  at RmDirDemo.Program.MyFunC) in E:\Work\CSharpProject\RmDirDemo\RmDirDemo\Prograin.cs:line 49
删除结束,耗时3246.7662 ms                                                                                                                  



搞到这里我已经对 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.jna</groupId>
    <artifactId>jna</artifactId>
    <version>5.12.1</version>
</dependency>

------- THE END -------
Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐