Song的学习笔记

首页 新随笔 联系 管理

CodingTookit

CodingTookit\src\Md2code\Program.cs


using System.Collections.Concurrent;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
internal class Program
{
    private static async Task Main(string[] args)
    {
        var now = DateTime.Now;
        string srcPath = args.Length > 0 ? args[0] : Directory.GetCurrentDirectory();
        var config = new Config(srcPath);
        bool hasConfig = config.CheckMd2CodeConfig();
        if (!hasConfig)
        {
            System.Console.WriteLine("初次使用,使用默认配置文件");
        }
        config.LoadConfig();
        var result = await FindLatestCode2mdFileAsync(srcPath, config);
        if (result == null)
        {
            Console.WriteLine("\nNo .md files found.");
            return;
        }
        Console.WriteLine($"  Path: {result.Path}");
        string mdPath = result.Path;
        using var fs = new FileStream(mdPath, FileMode.Open, FileAccess.Read, FileShare.Read, 4096);
        using var sr = new StreamReader(fs, Encoding.UTF8);
        bool articleStart = false;
        bool articleEnd = false;
        bool articleRealStart = false;
        bool mdStart = false;
        string? codeFilePath = null;
        string? title = null;
        string? line;
        while ((line = sr.ReadLine()?.Trim()) != null)
        {
            if (string.IsNullOrEmpty(line))
            {
                if (!string.IsNullOrEmpty(codeFilePath))
                {
                    File.AppendAllText(codeFilePath, Environment.NewLine, Encoding.UTF8);
                }
                continue;
            }
            if (string.IsNullOrEmpty(title))
            {
                if (line.StartsWith("# ") && !mdStart)
                {
                    title = line.TrimStart('#').Trim();
                    continue;
                }
            }
            if (!articleEnd && line.StartsWith($"## `{title}") && line.EndsWith('`') && !mdStart)
            {
                string latestCodeFilePath = Path.Combine(srcPath, $"{title}_{now:yyyyMMdd_HHmmss}", line.Split(title + '\\').Last().TrimEnd('`'));
                if (latestCodeFilePath != codeFilePath)
                {
                    codeFilePath = latestCodeFilePath;
                    Console.WriteLine(codeFilePath);
                    string? codeDirPath = Path.GetDirectoryName(codeFilePath);
                    if (!string.IsNullOrEmpty(codeDirPath))
                    {
                        if (!Directory.Exists(codeDirPath))
                        {
                            Directory.CreateDirectory(codeDirPath);
                        }
                        articleStart = true;
                        continue;
                    }
                }
            }
            if (articleStart && !string.IsNullOrEmpty(codeFilePath) && !mdStart)
            {
                if (line.StartsWith("```"))
                {
                    articleRealStart = true;
                    continue;
                }
            }
            if (articleRealStart && !string.IsNullOrEmpty(codeFilePath) && !mdStart)
            {
                if (line.StartsWith($"## `{title}") && line.EndsWith('`'))
                {
                    articleEnd = true;
                    continue;
                }
                File.AppendAllText(codeFilePath, line + Environment.NewLine, Encoding.UTF8);
            }
            if (line.StartsWith($"# `{title}\\") && line.EndsWith('`') && line.Count(c => c.Equals('`')).Equals(4) && line.Contains("`\\_`"))
            {
                string mdTitle = line.Split(title + '\\').Last().Split("`\\_`").First();
                string latestCodeFilePath = Path.Combine(srcPath, $"{title}_{now:yyyyMMdd_HHmmss}", mdTitle);
                if (codeFilePath != latestCodeFilePath)
                {
                    codeFilePath = latestCodeFilePath;
                    Console.WriteLine(codeFilePath);
                }
                string? latestCodeDirPath = Path.GetDirectoryName(latestCodeFilePath);
                if (!string.IsNullOrEmpty(latestCodeDirPath))
                {
                    if (!Directory.Exists(latestCodeDirPath))
                    {
                        Directory.CreateDirectory(latestCodeDirPath);
                    }
                    string firstLine = line.Split(title + '\\').Last().Split("`\\_`").Last().TrimEnd('`') + Environment.NewLine;
                    File.AppendAllText(codeFilePath, firstLine, Encoding.UTF8);
                    mdStart = true;
                    continue;
                }
            }
            if (mdStart)
            {
                if (!string.IsNullOrEmpty(codeFilePath))
                {
                    File.AppendAllText(codeFilePath, line + Environment.NewLine, Encoding.UTF8);
                }
            }
        }
    }
    private static async Task<MdFileInfo?> FindLatestCode2mdFileAsync(string rootPath, Config config)
    {
        var latestFile = new ConcurrentBag<MdFileInfo>();
        var directories = new ConcurrentStack<string>();
        directories.Push(rootPath);
        var filesProcessed = new ConcurrentCounter();
        var directoriesScanned = new ConcurrentCounter();
        await Task.Run(() =>
        {
            Parallel.ForEach(
                Partitioner.Create(1, int.MaxValue),
                range =>
                {
                    var localLatest = (DateTimeOffset?)null;
                    MdFileInfo? localLatestFile = null;
                    while (directories.TryPop(out string? dir))
                    {
                        try
                        {
                            string[] subDirs = Array.Empty<string>();
                            string[] files = Array.Empty<string>();
                            try
                            {
                                subDirs = Directory.GetDirectories(dir);
                                files = Directory.GetFiles(dir, "zz_project_*.md");
                            }
                            catch (UnauthorizedAccessException)
                            {
                                continue;
                            }
                            catch (PathTooLongException)
                            {
                                continue;
                            }
                            foreach (var file in files)
                            {
                                try
                                {
                                    var fileInfo = new FileInfo(file);
                                    if (localLatest == null || fileInfo.LastWriteTimeUtc > localLatest.Value)
                                    {
                                        localLatest = fileInfo.LastWriteTimeUtc;
                                        localLatestFile = new MdFileInfo(file, fileInfo.LastWriteTimeUtc);
                                    }
                                }
                                catch { }
                            }
                            foreach (var subDir in subDirs)
                            {
                                if (!config.ShouldExcludeDirectory(subDir))
                                {
                                    directories.Push(subDir);
                                }
                            }
                            directoriesScanned.Increment(1);
                            filesProcessed.Increment(files.Length);
                        }
                        catch { }
                    }
                    if (localLatestFile != null)
                    {
                        latestFile.Add(localLatestFile);
                    }
                }
            );
        });
        return latestFile.OrderByDescending(f => f.LastModifiedTime).FirstOrDefault();
    }
}

CodingTookit\CodingTookit.sln



Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.2.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{827E0CD3-B72D-47B6-A68D-7590B98EB39B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Code2md", "src\Code2md\Code2md.csproj", "{CF860317-708A-4964-AB32-042D023F2315}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CopyFileV2", "src\CopyFileV2\CopyFileV2.csproj", "{6FA435BC-E305-4790-8175-F463ED91B92A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SqlServerRunner", "src\SqlServerRunner\SqlServerRunner.csproj", "{F7E3C168-FD4B-42AA-80FD-5656D472E6DB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LatestSqlFinder", "src\LatestSqlFinder\LatestSqlFinder.csproj", "{F5013E74-5805-4C2E-8E60-EC697D06AD93}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Md2code", "src\Md2code\Md2code.csproj", "{FD3EC2B3-EA2E-4D1B-A3BA-AFBD2ABAAC63}"
EndProject
Global
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
		Debug|Any CPU = Debug|Any CPU
		Debug|x64 = Debug|x64
		Debug|x86 = Debug|x86
		Release|Any CPU = Release|Any CPU
		Release|x64 = Release|x64
		Release|x86 = Release|x86
	EndGlobalSection
	GlobalSection(ProjectConfigurationPlatforms) = postSolution
		{CF860317-708A-4964-AB32-042D023F2315}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{CF860317-708A-4964-AB32-042D023F2315}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{CF860317-708A-4964-AB32-042D023F2315}.Debug|x64.ActiveCfg = Debug|Any CPU
		{CF860317-708A-4964-AB32-042D023F2315}.Debug|x64.Build.0 = Debug|Any CPU
		{CF860317-708A-4964-AB32-042D023F2315}.Debug|x86.ActiveCfg = Debug|Any CPU
		{CF860317-708A-4964-AB32-042D023F2315}.Debug|x86.Build.0 = Debug|Any CPU
		{CF860317-708A-4964-AB32-042D023F2315}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{CF860317-708A-4964-AB32-042D023F2315}.Release|Any CPU.Build.0 = Release|Any CPU
		{CF860317-708A-4964-AB32-042D023F2315}.Release|x64.ActiveCfg = Release|Any CPU
		{CF860317-708A-4964-AB32-042D023F2315}.Release|x64.Build.0 = Release|Any CPU
		{CF860317-708A-4964-AB32-042D023F2315}.Release|x86.ActiveCfg = Release|Any CPU
		{CF860317-708A-4964-AB32-042D023F2315}.Release|x86.Build.0 = Release|Any CPU
		{6FA435BC-E305-4790-8175-F463ED91B92A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{6FA435BC-E305-4790-8175-F463ED91B92A}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{6FA435BC-E305-4790-8175-F463ED91B92A}.Debug|x64.ActiveCfg = Debug|Any CPU
		{6FA435BC-E305-4790-8175-F463ED91B92A}.Debug|x64.Build.0 = Debug|Any CPU
		{6FA435BC-E305-4790-8175-F463ED91B92A}.Debug|x86.ActiveCfg = Debug|Any CPU
		{6FA435BC-E305-4790-8175-F463ED91B92A}.Debug|x86.Build.0 = Debug|Any CPU
		{6FA435BC-E305-4790-8175-F463ED91B92A}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{6FA435BC-E305-4790-8175-F463ED91B92A}.Release|Any CPU.Build.0 = Release|Any CPU
		{6FA435BC-E305-4790-8175-F463ED91B92A}.Release|x64.ActiveCfg = Release|Any CPU
		{6FA435BC-E305-4790-8175-F463ED91B92A}.Release|x64.Build.0 = Release|Any CPU
		{6FA435BC-E305-4790-8175-F463ED91B92A}.Release|x86.ActiveCfg = Release|Any CPU
		{6FA435BC-E305-4790-8175-F463ED91B92A}.Release|x86.Build.0 = Release|Any CPU
		{F7E3C168-FD4B-42AA-80FD-5656D472E6DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{F7E3C168-FD4B-42AA-80FD-5656D472E6DB}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{F7E3C168-FD4B-42AA-80FD-5656D472E6DB}.Debug|x64.ActiveCfg = Debug|Any CPU
		{F7E3C168-FD4B-42AA-80FD-5656D472E6DB}.Debug|x64.Build.0 = Debug|Any CPU
		{F7E3C168-FD4B-42AA-80FD-5656D472E6DB}.Debug|x86.ActiveCfg = Debug|Any CPU
		{F7E3C168-FD4B-42AA-80FD-5656D472E6DB}.Debug|x86.Build.0 = Debug|Any CPU
		{F7E3C168-FD4B-42AA-80FD-5656D472E6DB}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{F7E3C168-FD4B-42AA-80FD-5656D472E6DB}.Release|Any CPU.Build.0 = Release|Any CPU
		{F7E3C168-FD4B-42AA-80FD-5656D472E6DB}.Release|x64.ActiveCfg = Release|Any CPU
		{F7E3C168-FD4B-42AA-80FD-5656D472E6DB}.Release|x64.Build.0 = Release|Any CPU
		{F7E3C168-FD4B-42AA-80FD-5656D472E6DB}.Release|x86.ActiveCfg = Release|Any CPU
		{F7E3C168-FD4B-42AA-80FD-5656D472E6DB}.Release|x86.Build.0 = Release|Any CPU
		{F5013E74-5805-4C2E-8E60-EC697D06AD93}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{F5013E74-5805-4C2E-8E60-EC697D06AD93}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{F5013E74-5805-4C2E-8E60-EC697D06AD93}.Debug|x64.ActiveCfg = Debug|Any CPU
		{F5013E74-5805-4C2E-8E60-EC697D06AD93}.Debug|x64.Build.0 = Debug|Any CPU
		{F5013E74-5805-4C2E-8E60-EC697D06AD93}.Debug|x86.ActiveCfg = Debug|Any CPU
		{F5013E74-5805-4C2E-8E60-EC697D06AD93}.Debug|x86.Build.0 = Debug|Any CPU
		{F5013E74-5805-4C2E-8E60-EC697D06AD93}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{F5013E74-5805-4C2E-8E60-EC697D06AD93}.Release|Any CPU.Build.0 = Release|Any CPU
		{F5013E74-5805-4C2E-8E60-EC697D06AD93}.Release|x64.ActiveCfg = Release|Any CPU
		{F5013E74-5805-4C2E-8E60-EC697D06AD93}.Release|x64.Build.0 = Release|Any CPU
		{F5013E74-5805-4C2E-8E60-EC697D06AD93}.Release|x86.ActiveCfg = Release|Any CPU
		{F5013E74-5805-4C2E-8E60-EC697D06AD93}.Release|x86.Build.0 = Release|Any CPU
		{FD3EC2B3-EA2E-4D1B-A3BA-AFBD2ABAAC63}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{FD3EC2B3-EA2E-4D1B-A3BA-AFBD2ABAAC63}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{FD3EC2B3-EA2E-4D1B-A3BA-AFBD2ABAAC63}.Debug|x64.ActiveCfg = Debug|Any CPU
		{FD3EC2B3-EA2E-4D1B-A3BA-AFBD2ABAAC63}.Debug|x64.Build.0 = Debug|Any CPU
		{FD3EC2B3-EA2E-4D1B-A3BA-AFBD2ABAAC63}.Debug|x86.ActiveCfg = Debug|Any CPU
		{FD3EC2B3-EA2E-4D1B-A3BA-AFBD2ABAAC63}.Debug|x86.Build.0 = Debug|Any CPU
		{FD3EC2B3-EA2E-4D1B-A3BA-AFBD2ABAAC63}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{FD3EC2B3-EA2E-4D1B-A3BA-AFBD2ABAAC63}.Release|Any CPU.Build.0 = Release|Any CPU
		{FD3EC2B3-EA2E-4D1B-A3BA-AFBD2ABAAC63}.Release|x64.ActiveCfg = Release|Any CPU
		{FD3EC2B3-EA2E-4D1B-A3BA-AFBD2ABAAC63}.Release|x64.Build.0 = Release|Any CPU
		{FD3EC2B3-EA2E-4D1B-A3BA-AFBD2ABAAC63}.Release|x86.ActiveCfg = Release|Any CPU
		{FD3EC2B3-EA2E-4D1B-A3BA-AFBD2ABAAC63}.Release|x86.Build.0 = Release|Any CPU
	EndGlobalSection
	GlobalSection(SolutionProperties) = preSolution
		HideSolutionNode = FALSE
	EndGlobalSection
	GlobalSection(NestedProjects) = preSolution
		{CF860317-708A-4964-AB32-042D023F2315} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
		{6FA435BC-E305-4790-8175-F463ED91B92A} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
		{F7E3C168-FD4B-42AA-80FD-5656D472E6DB} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
		{F5013E74-5805-4C2E-8E60-EC697D06AD93} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
		{FD3EC2B3-EA2E-4D1B-A3BA-AFBD2ABAAC63} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
	EndGlobalSection
	GlobalSection(ExtensibilityGlobals) = postSolution
		SolutionGuid = {952E0F08-889A-4D42-8C09-9A6CE65269E2}
	EndGlobalSection
EndGlobal

CodingTookit\src\Md2code\Config.cs


using Microsoft.Extensions.Configuration;
public class Config
{
    private readonly string _srcPath;
    private readonly string _configPath;
    private IConfigurationRoot _configurationRoot = null!;
    public List<string> ExcludeEqualDirs { get; set; } = new();
    public List<string> ExcludeStartDirs { get; set; } = new();
    public List<string> ExcludeEndDirs { get; set; } = new();
    public Config(string srcPath)
    {
        _srcPath = srcPath;
        _configPath = Path.Combine(srcPath, ".vscode", "md2code.yaml");
    }
    public bool CheckMd2CodeConfig()
    {
        string configDir = Path.GetDirectoryName(_configPath) ?? ".vscode";
        if (!Directory.Exists(configDir))
        {
            Directory.CreateDirectory(configDir);
        }
        if (!File.Exists(_configPath))
        {
            File.WriteAllText(_configPath, GenerateCmdSqlConfigYaml(), System.Text.Encoding.UTF8);
            return false;
        }
        return true;
    }
    public void LoadConfig()
    {
        if (!File.Exists(_configPath))
            return;
        try
        {
            _configurationRoot = new ConfigurationBuilder().SetBasePath(_srcPath).AddYamlFile(_configPath, optional: true, reloadOnChange: true).Build();
            ExcludeEqualDirs = GetConfigList("ExcludeEqualDirs");
            ExcludeStartDirs = GetConfigList("ExcludeStartDirs");
            ExcludeEndDirs = GetConfigList("ExcludeEndDirs");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Warning: Could not load config file: {ex.Message}");
            ExcludeEqualDirs.Clear();
            ExcludeStartDirs.Clear();
            ExcludeEndDirs.Clear();
        }
    }
    public bool ShouldExcludeDirectory(string dirPath)
    {
        string dirName = Path.GetFileName(dirPath);
        if (ExcludeEqualDirs.Contains(dirName))
            return true;
        if (ExcludeStartDirs.Any(prefix => dirName.StartsWith(prefix)))
            return true;
        if (ExcludeEndDirs.Any(suffix => dirName.EndsWith(suffix)))
            return true;
        return false;
    }
    private List<string> GetConfigList(string sectionName)
    {
        return _configurationRoot.GetSection(sectionName).GetChildren().Select(child => child.Value ?? string.Empty).Where(v => !string.IsNullOrEmpty(v)).ToList();
    }
    public static string GenerateCmdSqlConfigYaml()
    {
        return @"ExcludeEqualDirs:
  - ""res""
  - ""docs""
  - ""note""
  - ""config""
  - ""Publish""
  - "".idea""
  - "".vs""
  - "".vscode""
  - "".git""
  - ""zz_pro""
  - ""zz_res""
  - ""zz_zz""
  - ""bin""
  - ""zz_config""
  - ""zz_note""
  - ""zz_cache""
  - ""node_modules""
  - ""obj""
  - ""zz_zz_publish""
  - ""zz_zz_pro""
  - ""Migrations""
  - ""log""
  - ""logs""
ExcludeStartDirs: []
ExcludeEndDirs: []";
    }
}

CodingTookit\src\Md2code\Md2code.csproj


<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net9.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.Configuration" Version="9.0.0" />
    <PackageReference Include="NetEscapades.Configuration.Yaml" Version="3.1.0" />
    <PackageReference Include="YamlDotNet" Version="15.1.2" />
  </ItemGroup>

</Project>

CodingTookit\src\Md2code\MdFileInfo.cs


public class MdFileInfo
{
    public string Path { get; }
    public DateTimeOffset LastModifiedTime { get; }
    public MdFileInfo(string path, DateTimeOffset lastModifiedTime)
    {
        Path = path;
        LastModifiedTime = lastModifiedTime;
    }
}

CodingTookit\src\Md2code\ConcurrentCounter.cs


public class ConcurrentCounter
{
    private long _count = 0;
    public void Increment(long value = 1)
    {
        Interlocked.Add(ref _count, value);
    }
    public long Value => Interlocked.Read(ref _count);
}

CodingTookit\src\Code2md\Project.cs


using System.Text;
public class Project
{
    private readonly string _srcPath;
    private readonly Config _config;
    private readonly DateTime _now = DateTime.Now;
    private string _suffix = string.Empty;
    public Project(string srcPath)
    {
        _srcPath = srcPath;
        _config = new Config(srcPath);
    }
    public async Task Run()
    {
        Console.WriteLine("============== Run Code2md START==============");
        bool hasConfig = _config.CheckCode2mdConfig();
        if (!hasConfig)
        {
            return;
        }
        Console.WriteLine("请输入文件名后缀:");
        Console.InputEncoding = Encoding.Unicode;
        Console.OutputEncoding = Encoding.Unicode;
        _suffix = Console.ReadLine()?.Trim() ?? string.Empty;
        _config.LoadConfig();
        List<string> rootDirPaths = this.GetRootDirPaths();
        List<string> deepDirs = await GetDeepDirPaths(rootDirPaths);
        List<string> allDirPaths = rootDirPaths.Concat(deepDirs).ToList();
        allDirPaths.Add(_srcPath);
        List<string> allFilePaths = await GetAllFiles(allDirPaths);
        List<string> sortedFilePaths = allFilePaths.Select(path => new { Path = path, LastWriteTime = File.GetLastWriteTime(path) }).OrderByDescending(file => file.LastWriteTime).Select(file => file.Path).ToList();
        this.CodeToOneMarkdown(sortedFilePaths);
        Console.WriteLine("============== Run Code2md  END ==============");
    }
    private void CodeToOneMarkdown(List<string> filePaths)
    {
        var mdFileName = $"zz_project_{_now:yyyyMMdd_HHmmss}_{_suffix}.md";
        var mdFolderPath = Path.Combine(_srcPath, "zz_zz");
        if (!Directory.Exists(mdFolderPath))
        {
            Directory.CreateDirectory(mdFolderPath);
        }
        string mdFilePath = Path.Combine(mdFolderPath, mdFileName);
        using StreamWriter sw = new StreamWriter(mdFilePath, false, Encoding.UTF8);
        string basePath = Path.GetDirectoryName(_srcPath) ?? string.Empty;
        string projectName = Path.GetFileName(_srcPath);
        sw.WriteLine($"\n# {projectName}\n");
        List<string> codeFiles = filePaths.Where(file => !file.EndsWith(".md")).ToList();
        foreach (var file in codeFiles)
        {
            string fileExtension = Path.GetExtension(file).ToLowerInvariant().Trim();
            if (!_config.CodeToMarkDownExtension.Contains(fileExtension))
            {
                Console.WriteLine($"skip code2md no suffix: {file}");
                continue;
            }
            string relativePath = Path.GetRelativePath(basePath, file);
            sw.WriteLine($"\n## `{relativePath}`\n");
            string? markdownCodeBlockName = _config.CodeSuffixMap.GetValueOrDefault(fileExtension);
            if (string.IsNullOrEmpty(markdownCodeBlockName))
            {
                markdownCodeBlockName = fileExtension.Replace(".", "").Trim();
            }
            sw.WriteLine($"\n```{markdownCodeBlockName}\n");
            try
            {
                using var fs = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 4096, useAsync: false);
                using var reader = new StreamReader(fs, Encoding.UTF8, detectEncodingFromByteOrderMarks: true, bufferSize: 8192);
                string? line;
                while ((line = reader.ReadLine()) != null)
                {
                    if (fileExtension.Equals(".cs"))
                    {
                        if (line.Trim().StartsWith("//"))
                        {
                            continue;
                        }
                        if (string.IsNullOrEmpty(line.Trim()))
                        {
                            continue;
                        }
                    }
                    sw.WriteLine(line);
                }
            }
            catch (UnauthorizedAccessException)
            {
                Console.WriteLine($"Unauthorized access to file: {file}");
                sw.WriteLine($"<!-- Unauthorized access to file: {file} -->\n```");
                continue;
            }
            catch (IOException ex)
            {
                Console.WriteLine($"IO error reading file {file}: {ex.Message}");
                sw.WriteLine($"<!-- IO error reading file: {file} - {ex.Message} -->\n```");
                continue;
            }
            catch (System.Exception ex)
            {
                Console.WriteLine($"Error reading file {file}: {ex.Message}");
                sw.WriteLine($"<!-- Error reading file: {file} - {ex.Message} -->\n```");
                continue;
            }
            sw.WriteLine("\n```");
        }
        List<string> mdFiles = filePaths.Where(file => file.EndsWith(".md")).ToList();
        foreach (var file in mdFiles)
        {
            string relativePath = Path.GetRelativePath(basePath, file);
            var firstInFlag = true;
            sw.Write($"\n# `{relativePath}`");
            try
            {
                using var fs = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 4096, useAsync: false);
                using var reader = new StreamReader(fs, Encoding.UTF8, detectEncodingFromByteOrderMarks: true, bufferSize: 8192);
                string? line;
                while ((line = reader.ReadLine()) != null)
                {
                    if (string.IsNullOrEmpty(line.Trim()))
                    {
                        continue;
                    }
                    if (line.Trim().StartsWith("# "))
                    {
                        sw.Write($"_`{line}`\n\n");
                        continue;
                    }
                    if (firstInFlag)
                    {
                        sw.WriteLine("\n");
                        firstInFlag = false;
                    }
                    sw.WriteLine(line);
                }
            }
            catch (UnauthorizedAccessException)
            {
                Console.WriteLine($"Unauthorized access to file: {file}");
                sw.WriteLine($"<!-- Unauthorized access to file: {file} -->\n```");
                continue;
            }
            catch (IOException ex)
            {
                Console.WriteLine($"IO error reading file {file}: {ex.Message}");
                sw.WriteLine($"<!-- IO error reading file: {file} - {ex.Message} -->\n```");
                continue;
            }
            catch (System.Exception ex)
            {
                Console.WriteLine($"Error reading file {file}: {ex.Message}");
                sw.WriteLine($"<!-- Error reading file: {file} - {ex.Message} -->\n```");
                continue;
            }
        }
        Console.WriteLine($"=========代码转成一个Markdown文件成功!!!=========");
    }
    private async Task<List<string>> GetAllFiles(List<string> allDirPaths)
    {
        List<Task<List<string>>> tasks = new List<Task<List<string>>>();
        foreach (var allDirPath in allDirPaths)
        {
            tasks.Add(Task.Run(() => GetFilteringTopDirFiles(allDirPath)));
        }
        await Task.WhenAll(tasks);
        var files = new List<string>();
        foreach (var task in tasks)
        {
            files.AddRange(task.Result);
        }
        return files;
    }
    public List<string> GetFilteringTopDirFiles(string folderPath)
    {
        return Directory.GetFiles(folderPath, "*", SearchOption.TopDirectoryOnly).Where(file => ShouldIncludeFile(Path.GetFileName(file))).ToList();
    }
    public bool ShouldIncludeFile(string fileName)
    {
        return !_config.GetExcludeFileFlag(fileName) || _config.GetIncludeFileFlag(fileName);
    }
    private List<string> GetRootDirPaths()
    {
        return Directory
            .GetDirectories(_srcPath, "*", SearchOption.TopDirectoryOnly)
            .Where(dirPath =>
            {
                string folderName = Path.GetFileName(dirPath);
                return !_config.GetExcludeDirFlag(folderName) || _config.GetIncludeDirFlag(folderName);
            })
            .ToList();
    }
    private async Task<List<string>> GetDeepDirPaths(List<string> rootDirPaths)
    {
        var tasks = rootDirPaths.Select(rootDirPath => Task.Run(() => GetFilteringAllDirTask(rootDirPath))).ToArray();
        await Task.WhenAll(tasks);
        return tasks.SelectMany(task => task.Result).ToList();
    }
    private List<string> GetFilteringAllDirTask(string rootDirPath)
    {
        var deepDirs = new List<string>();
        GetFilteringAllDirs(rootDirPath, deepDirs);
        return deepDirs;
    }
    public void GetFilteringAllDirs(string folderPath, List<string> allFolders)
    {
        try
        {
            var validSubdirs = GetFilteringTopDirFolders(folderPath);
            foreach (var dir in validSubdirs)
            {
                allFolders.Add(dir);
                GetFilteringAllDirs(dir, allFolders);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error while traversing folder: {ex.Message}");
        }
    }
    public List<string> GetFilteringTopDirFolders(string folderPath)
    {
        return Directory.GetDirectories(folderPath, "*", SearchOption.TopDirectoryOnly).Where(dir => ShouldIncludeDir(Path.GetFileName(dir))).ToList();
    }
    public bool ShouldIncludeDir(string folderName)
    {
        return !GetExcludeDirFlag(folderName) || GetIncludeDirFlag(folderName);
    }
    private bool GetExcludeDirFlag(string folderName)
    {
        return _config.ExcludeEqualDirs.Any(folder => folderName.Equals(folder)) || _config.ExcludeStartDirs.Any(folder => folderName.StartsWith(folder)) || _config.ExcludeEndDirs.Any(folder => folderName.EndsWith(folder));
    }
    private bool GetIncludeDirFlag(string folderName)
    {
        return _config.IncludeEqualDirs.Any(folder => folderName.Equals(folder)) || _config.IncludeStartDirs.Any(folder => folderName.StartsWith(folder)) || _config.IncludeEndDirs.Any(folder => folderName.EndsWith(folder));
    }
}

CodingTookit\src\Code2md\Program.cs


if (args.Length == 0)
{
    Console.WriteLine("请传入文件夹路径");
    return;
}
if (!Directory.Exists(args[0]))
{
    Console.WriteLine($"传入的文件夹不存在 : {args[0]}");
    return;
}
Project project = new Project(args[0].Trim());
await project.Run();

CodingTookit\run.bat


set "scriptPath=%cd%"
@REM dotnet run --project ./src/Code2md/Code2md.csproj -- "%scriptPath%"
@REM dotnet run --project ./src/Code2mdV2/Code2mdV2.csproj -- "%scriptPath%"
@REM dotnet run --project ./src/LastestSqlFinder/LastestSqlFinder.csproj -- "%scriptPath%"
@REM dotnet run --project ./src/SqlServerRunner/SqlServerRunner.csproj -- "%scriptPath%"

@REM dotnet run --project ./src/Md2code/Md2code.csproj -- "%scriptPath%"
@REM dotnet run --project D:\CodingTookit\consoletests\MarkdownLineTest\MarkdownLineTest.csproj

dotnet run --project ./src/LatestCode2mdFinder/LatestCode2mdFinder.csproj  -- "%scriptPath%"


























CodingTookit\src\LatestSqlFinder\Program.cs


using System.Collections.Concurrent;
using System.Diagnostics;
using System.Text;
class Program
{
    static async Task Main(string[] args)
    {
        string path = args.Length > 0 ? args[0] : Directory.GetCurrentDirectory();
        var config = new Config(path);
        bool hasConfig = config.CheckCmdSqlConfig();
        if (!hasConfig)
        {
            System.Console.WriteLine("初次使用,使用默认配置文件");
        }
        config.LoadConfig();
        var stopwatch = Stopwatch.StartNew();
        var result = await FindLatestSqlFileAsync(path, config);
        var tempPath = Path.Combine(@"C:\Users", Environment.UserName, @"AppData\Local\Temp");
        var dstPath = FindLatestDstSqlFileAsync(tempPath);
        stopwatch.Stop();
        if (result == null || dstPath == null)
        {
            Console.WriteLine("\nNo .sql files found.");
            Console.WriteLine($"\nScanned in {stopwatch.ElapsedMilliseconds}ms");
            return;
        }
        Console.WriteLine($"\nFound latest SQL file:");
        string latestSrcSqlFilePath = result.Path;
        Console.WriteLine(latestSrcSqlFilePath);
        string latestDstSqlFilePath = dstPath;
        List<string> bottoms = ReverseReadLines(latestSrcSqlFilePath);
        File.WriteAllText(latestDstSqlFilePath, string.Join(Environment.NewLine, bottoms), System.Text.Encoding.UTF8);
        Console.WriteLine($"\nScanned in {stopwatch.ElapsedMilliseconds}ms");
    }
    public static List<string> ReverseReadLines(string filePath)
    {
        List<string> resultLines = new List<string>();
        List<byte> currentLineBuffer = new List<byte>();
        int consecutiveEmptyLines = 0;
        bool foundFirstContent = false;
        using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
        {
            long position = fs.Length;
            while (position > 0)
            {
                position--;
                fs.Position = position;
                int byteValue = fs.ReadByte();
                if (byteValue == -1)
                    continue;
                char c = (char)byteValue;
                if (c == '\n')
                {
                    currentLineBuffer.Reverse();
                    string line = Encoding.UTF8.GetString(currentLineBuffer.ToArray()).TrimEnd('\r');
                    currentLineBuffer.Clear();
                    if (!foundFirstContent)
                    {
                        if (!string.IsNullOrWhiteSpace(line))
                        {
                            foundFirstContent = true;
                            resultLines.Add(line);
                        }
                    }
                    else
                    {
                        if (string.IsNullOrWhiteSpace(line))
                        {
                            consecutiveEmptyLines++;
                            if (consecutiveEmptyLines >= 3)
                            {
                                break;
                            }
                        }
                        else
                        {
                            resultLines.Add(line);
                            consecutiveEmptyLines = 0;
                        }
                    }
                }
                else
                {
                    currentLineBuffer.Add((byte)byteValue);
                }
            }
            if (currentLineBuffer.Count > 0 && (foundFirstContent && consecutiveEmptyLines < 3))
            {
                currentLineBuffer.Reverse();
                string firstLine = Encoding.UTF8.GetString(currentLineBuffer.ToArray()).TrimEnd('\r');
                if (!string.IsNullOrWhiteSpace(firstLine))
                {
                    resultLines.Add(firstLine);
                }
            }
            else if (currentLineBuffer.Count > 0 && !foundFirstContent)
            {
                currentLineBuffer.Reverse();
                string onlyLine = Encoding.UTF8.GetString(currentLineBuffer.ToArray()).TrimEnd('\r');
                if (!string.IsNullOrWhiteSpace(onlyLine))
                {
                    resultLines.Add(onlyLine);
                }
            }
        }
        resultLines.Reverse();
        return resultLines;
    }
    private static string? FindLatestDstSqlFileAsync(string v)
    {
        string[] sqlFiles = Directory.GetFiles(v, "*.sql", SearchOption.TopDirectoryOnly);
        if (sqlFiles.Length == 0)
            return null;
        string? latestFile = null;
        DateTimeOffset latestTime = DateTimeOffset.MinValue;
        foreach (var file in sqlFiles)
        {
            try
            {
                var fileInfo = new FileInfo(file);
                if (fileInfo.LastWriteTimeUtc > latestTime)
                {
                    latestTime = fileInfo.LastWriteTimeUtc;
                    latestFile = file;
                }
            }
            catch { }
        }
        return latestFile;
    }
    private static async Task<SqlFileInfo?> FindLatestSqlFileAsync(string rootPath, Config config)
    {
        var latestFile = new ConcurrentBag<SqlFileInfo>();
        var directories = new ConcurrentStack<string>();
        directories.Push(rootPath);
        var filesProcessed = new ConcurrentCounter();
        var directoriesScanned = new ConcurrentCounter();
        await Task.Run(() =>
        {
            Parallel.ForEach(
                Partitioner.Create(1, int.MaxValue),
                range =>
                {
                    var localLatest = (DateTimeOffset?)null;
                    SqlFileInfo? localLatestFile = null;
                    while (directories.TryPop(out string? dir))
                    {
                        try
                        {
                            string[] subDirs = Array.Empty<string>();
                            string[] files = Array.Empty<string>();
                            try
                            {
                                subDirs = Directory.GetDirectories(dir);
                                files = Directory.GetFiles(dir, "*.sql");
                            }
                            catch (UnauthorizedAccessException)
                            {
                                continue;
                            }
                            catch (PathTooLongException)
                            {
                                continue;
                            }
                            foreach (var file in files)
                            {
                                try
                                {
                                    var fileInfo = new FileInfo(file);
                                    if (localLatest == null || fileInfo.LastWriteTimeUtc > localLatest.Value)
                                    {
                                        localLatest = fileInfo.LastWriteTimeUtc;
                                        localLatestFile = new SqlFileInfo(file, fileInfo.LastWriteTimeUtc);
                                    }
                                }
                                catch { }
                            }
                            foreach (var subDir in subDirs)
                            {
                                if (!config.ShouldExcludeDirectory(subDir))
                                {
                                    directories.Push(subDir);
                                }
                            }
                            directoriesScanned.Increment(1);
                            filesProcessed.Increment(files.Length);
                        }
                        catch { }
                    }
                    if (localLatestFile != null)
                    {
                        latestFile.Add(localLatestFile);
                    }
                }
            );
        });
        return latestFile.OrderByDescending(f => f.LastModifiedTime).FirstOrDefault();
    }
}
public class SqlFileInfo
{
    public string Path { get; }
    public DateTimeOffset LastModifiedTime { get; }
    public SqlFileInfo(string path, DateTimeOffset lastModifiedTime)
    {
        Path = path;
        LastModifiedTime = lastModifiedTime;
    }
}
public class ConcurrentCounter
{
    private long _count = 0;
    public void Increment(long value = 1)
    {
        Interlocked.Add(ref _count, value);
    }
    public long Value => Interlocked.Read(ref _count);
}

CodingTookit\src\SqlServerRunner\Program.cs


using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
class Program
{
    [DllImport("user32.dll")]
    private static extern bool SetForegroundWindow(IntPtr hWnd);
    [DllImport("user32.dll")]
    private static extern IntPtr FindWindow(string? lpClassName, string lpWindowName);
    [DllImport("user32.dll")]
    private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
    [DllImport("user32.dll")]
    private static extern bool IsIconic(IntPtr hWnd);
    [DllImport("user32.dll")]
    private static extern IntPtr GetForegroundWindow();
    private const int SW_RESTORE = 9;
    static void Main(string[] args)
    {
        const string windowTitle = "Microsoft SQL Server Management Studio";
        const string processName = "ssms";
        IntPtr previousActiveWindow = GetForegroundWindow();
        IntPtr hWnd = FindWindow(null, windowTitle);
        if (hWnd == IntPtr.Zero)
        {
            Process[] processes = Process.GetProcessesByName(processName);
            if (processes.Length > 0)
            {
                hWnd = processes[0].MainWindowHandle;
                processes[0].Dispose();
            }
        }
        if (hWnd == IntPtr.Zero)
        {
            Console.WriteLine("Error: Microsoft SQL Server Management Studio is not running.");
            return;
        }
        if (IsIconic(hWnd))
        {
            ShowWindow(hWnd, SW_RESTORE);
        }
        if (!SetForegroundWindow(hWnd))
        {
            Console.WriteLine("Error: Failed to activate the window.");
            return;
        }
        Thread.Sleep(500);
        SendF5Key();
        Thread.Sleep(500);
        if (previousActiveWindow != IntPtr.Zero)
        {
            SetForegroundWindow(previousActiveWindow);
        }
        Console.WriteLine("F5 key sent to SQL Server Management Studio successfully.");
    }
    private static void SendF5Key()
    {
        const byte VK_F5 = 0x74;
        const uint KEYEVENTF_KEYUP = 0x2;
        keybd_event(VK_F5, 0, 0, IntPtr.Zero);
        keybd_event(VK_F5, 0, KEYEVENTF_KEYUP, IntPtr.Zero);
    }
    [DllImport("user32.dll")]
    private static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, IntPtr dwExtraInfo);
}

CodingTookit\src\LatestSqlFinder\Config.cs


using Microsoft.Extensions.Configuration;
public class Config
{
    private readonly string _srcPath;
    private readonly string _configPath;
    private IConfigurationRoot _configurationRoot = null!;
    public List<string> ExcludeEqualDirs { get; set; } = new();
    public List<string> ExcludeStartDirs { get; set; } = new();
    public List<string> ExcludeEndDirs { get; set; } = new();
    public Config(string srcPath)
    {
        _srcPath = srcPath;
        _configPath = Path.Combine(srcPath, ".vscode", "cmdSql.yaml");
    }
    public bool CheckCmdSqlConfig()
    {
        string configDir = Path.GetDirectoryName(_configPath) ?? ".vscode";
        if (!Directory.Exists(configDir))
        {
            Directory.CreateDirectory(configDir);
        }
        if (!File.Exists(_configPath))
        {
            File.WriteAllText(_configPath, GenerateCmdSqlConfigYaml(), System.Text.Encoding.UTF8);
            return false;
        }
        return true;
    }
    public void LoadConfig()
    {
        if (!File.Exists(_configPath))
            return;
        try
        {
            _configurationRoot = new ConfigurationBuilder().SetBasePath(_srcPath).AddYamlFile(_configPath, optional: true, reloadOnChange: true).Build();
            ExcludeEqualDirs = GetConfigList("ExcludeEqualDirs");
            ExcludeStartDirs = GetConfigList("ExcludeStartDirs");
            ExcludeEndDirs = GetConfigList("ExcludeEndDirs");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Warning: Could not load config file: {ex.Message}");
            ExcludeEqualDirs.Clear();
            ExcludeStartDirs.Clear();
            ExcludeEndDirs.Clear();
        }
    }
    public bool ShouldExcludeDirectory(string dirPath)
    {
        string dirName = Path.GetFileName(dirPath);
        if (ExcludeEqualDirs.Contains(dirName))
            return true;
        if (ExcludeStartDirs.Any(prefix => dirName.StartsWith(prefix)))
            return true;
        if (ExcludeEndDirs.Any(suffix => dirName.EndsWith(suffix)))
            return true;
        return false;
    }
    private List<string> GetConfigList(string sectionName)
    {
        return _configurationRoot.GetSection(sectionName).GetChildren().Select(child => child.Value ?? string.Empty).Where(v => !string.IsNullOrEmpty(v)).ToList();
    }
    public static string GenerateCmdSqlConfigYaml()
    {
        return @"ExcludeEqualDirs:
  - ""res""
  - ""docs""
  - ""note""
  - ""config""
  - ""Publish""
  - "".idea""
  - "".vs""
  - "".vscode""
  - "".git""
  - ""zz_pro""
  - ""zz_res""
  - ""zz_zz""
  - ""bin""
  - ""zz_config""
  - ""zz_note""
  - ""zz_cache""
  - ""node_modules""
  - ""obj""
  - ""zz_zz_publish""
  - ""zz_zz_pro""
  - ""Migrations""
  - ""log""
  - ""logs""
ExcludeStartDirs: []
ExcludeEndDirs: []";
    }
}

CodingTookit\src\Code2md\Config.cs


using Microsoft.Extensions.Configuration;
public class Config
{
    private readonly string _srcPath;
    private readonly string _code2mdConfigFolder;
    private readonly string _code2mdConfigPath;
    private IConfigurationRoot _configurationRoot = null!;
    public List<string> ExcludeEqualDirs { get; set; } = null!;
    public List<string> ExcludeStartDirs { get; set; } = null!;
    public List<string> ExcludeEndDirs { get; set; } = null!;
    public List<string> IncludeEqualDirs { get; set; } = null!;
    public List<string> IncludeStartDirs { get; set; } = null!;
    public List<string> IncludeEndDirs { get; set; } = null!;
    public List<string> ExcludeEqualFiles { get; set; } = null!;
    public List<string> ExcludeStartFiles { get; set; } = null!;
    public List<string> ExcludeEndFiles { get; set; } = null!;
    public List<string> IncludeEqualFiles { get; set; } = null!;
    public List<string> IncludeStartFiles { get; set; } = null!;
    public List<string> IncludeEndFiles { get; set; } = null!;
    public List<string> CodeToMarkDownExtension { get; set; } = null!;
    public Dictionary<string, string> CodeSuffixMap { get; set; } = null!;
    public Config(string srcPath)
    {
        _srcPath = srcPath;
        _code2mdConfigFolder = Path.Combine(_srcPath, ".vscode");
        _code2mdConfigPath = Path.Combine(_srcPath, ".vscode", "code2md.yaml");
    }
    public bool CheckCode2mdConfig()
    {
        if (!Directory.Exists(_code2mdConfigFolder))
        {
            Directory.CreateDirectory(_code2mdConfigFolder);
        }
        if (!Path.Exists(_code2mdConfigPath))
        {
            Console.WriteLine($"无配置文件 : {_code2mdConfigPath} , 已生成配置文件,然后返回");
            File.WriteAllText(_code2mdConfigPath, GenerateCode2mdConfigYaml(), System.Text.Encoding.UTF8);
            return false;
        }
        return true;
    }
    public void LoadConfig()
    {
        _configurationRoot = new ConfigurationBuilder().SetBasePath(_srcPath).AddYamlFile(_code2mdConfigPath, optional: true, reloadOnChange: true).Build();
        ExcludeEqualDirs = GetConfigList("ExcludeEqualDirs");
        ExcludeStartDirs = GetConfigList("ExcludeStartDirs");
        ExcludeEndDirs = GetConfigList("ExcludeEndDirs");
        IncludeEqualDirs = GetConfigList("IncludeEqualDirs");
        IncludeStartDirs = GetConfigList("IncludeStartDirs");
        IncludeEndDirs = GetConfigList("IncludeEndDirs");
        ExcludeEqualFiles = GetConfigList("ExcludeEqualFiles");
        ExcludeStartFiles = GetConfigList("ExcludeStartFiles");
        ExcludeEndFiles = GetConfigList("ExcludeEndFiles");
        IncludeEqualFiles = GetConfigList("IncludeEqualFiles");
        IncludeStartFiles = GetConfigList("IncludeStartFiles");
        IncludeEndFiles = GetConfigList("IncludeEndFiles");
        CodeToMarkDownExtension = GetConfigList("CodeToMarkDownExtension");
        CodeSuffixMap = GetConfigMap("CodeSuffixDic");
    }
    public bool GetExcludeDirFlag(string folderName)
    {
        return ExcludeEqualDirs.Any(folder => folderName.Equals(folder)) || ExcludeStartDirs.Any(folder => folderName.StartsWith(folder)) || ExcludeEndDirs.Any(folder => folderName.EndsWith(folder));
    }
    public bool GetIncludeDirFlag(string folderName)
    {
        return IncludeEqualDirs.Any(folder => folderName.Equals(folder)) || IncludeStartDirs.Any(folder => folderName.StartsWith(folder)) || IncludeEndDirs.Any(folder => folderName.EndsWith(folder));
    }
    public bool GetExcludeFileFlag(string fileName)
    {
        return ExcludeEqualFiles.Any(folder => fileName.Equals(folder)) || ExcludeStartFiles.Any(folder => fileName.StartsWith(folder)) || ExcludeEndFiles.Any(folder => fileName.EndsWith(folder));
    }
    public bool GetIncludeFileFlag(string fileName)
    {
        return IncludeEqualFiles.Any(folder => fileName.Equals(folder)) || IncludeStartFiles.Any(folder => fileName.StartsWith(folder)) || IncludeEndFiles.Any(folder => fileName.EndsWith(folder));
    }
    private List<string> GetConfigList(string sectionName)
    {
        return _configurationRoot.GetSection(sectionName).GetChildren().Select(child => child.Value ?? string.Empty).ToList();
    }
    private Dictionary<string, string> GetConfigMap(string sectionName)
    {
        return _configurationRoot.GetSection(sectionName).GetChildren().ToDictionary(e => e.Key, e => e.Value ?? string.Empty);
    }
    public static string GenerateCode2mdConfigYaml()
    {
        return @"DstBackFolder: """"
ExcludeEqualDirs:
  - ""res""
  - ""docs""
  - ""note""
  - ""config""
  - ""Publish""
  - "".idea""
  - "".vs""
  - "".vscode""
  - "".git""
  - ""zz_pro""
  - ""zz_res""
  - ""zz_zz""
  - ""bin""
  - ""zz_config""
  - ""zz_note""
  - ""zz_cache""
  - ""node_modules""
  - ""obj""
  - ""zz_zz_publish""
  - ""zz_zz_pro""
  - ""Migrations""
  - ""log""
  - ""logs""
ExcludeStartDirs: []
ExcludeEndDirs: []
IncludeEqualDirs: []
IncludeStartDirs: []
IncludeEndDirs: []
ExcludeEqualFiles:
  - ""zz.bat""
  - ""AssemblyInfo.cs""
  - ""out.txt""
ExcludeStartFiles:
  - ""temp""
ExcludeEndFiles:
  - "".xlsx""
  - "".doc""
  - "".docx""
  - "".ppt""
  - "".pptx""
  - "".pdf""
  - "".png""
  - "".jpg""
  - "".jpeg""
  - "".gif""
  - "".mp4""
  - "".mp3""
IncludeEqualFiles: []
IncludeStartFiles: []
IncludeEndFiles: []
CodeSuffixDic:
  "".cs"": ""cs""
  "".csproj"": ""csproj""
  "".http"": ""http""
  "".bat"": ""sh""
  "".ps1"": ""sh""
  "".py"": ""py""
  "".js"": ""js""
  "".ts"": ""ts""
  "".cpp"": ""cpp""
  "".c"": ""c""
  "".json"": ""json""
  "".sln"": ""xml""
  "".config"": ""config""
  "".xaml"": ""xml""
CodeToMarkDownExtension:
  - "".txt""
  - "".log""
  - "".ini""
  - "".conf""
  - "".cfg""
  - "".toml""
  - "".yml""
  - "".yaml""
  - "".json""
  - "".xml""
  - "".properties""
  - "".c""
  - "".cpp""
  - "".h""
  - "".hpp""
  - "".cs""
  - "".java""
  - "".js""
  - "".ts""
  - "".py""
  - "".rb""
  - "".php""
  - "".go""
  - "".rs""
  - "".swift""
  - "".m""
  - "".mm""
  - "".scala""
  - "".groovy""
  - "".pl""
  - "".pm""
  - "".sh""
  - "".bat""
  - "".cmd""
  - "".ps1""
  - "".html""
  - "".htm""
  - "".css""
  - "".markdown""
  - "".rst""
  - "".sql""
  - "".graphql""
  - "".sln""
  - "".csproj""
  - "".vbproj""
  - "".fsproj""
  - "".gradle""
  - "".pom.xml""
  - "".gemspec""
  - "".npmrc""
  - "".yarnrc""
  - "".package.json""
  - "".cabal""
  - "".opam""
  - "".pubspec.yaml""
  - "".rst""
  - "".tex""
  - "".gitignore""
  - "".editorconfig""
  - "".dockerfile""
  - "".env""
  - "".class""
  - "".asm""
  - "".ada""
  - "".pas""
  - "".bas""
  - "".xaml""
  - "".axaml""
  - "".manifest""
  - "".config""
  - "".qwenignore""";
    }
}

CodingTookit\src\CopyFileV2\Config.cs


using Microsoft.Extensions.Configuration;
public class Config
{
    private readonly string _srcPath;
    private readonly string _code2mdConfigFolder;
    private readonly string _code2mdConfigPath;
    private IConfigurationRoot _configurationRoot = null!;
    public List<string> ExcludeEqualDirs { get; set; } = null!;
    public List<string> ExcludeStartDirs { get; set; } = null!;
    public List<string> ExcludeEndDirs { get; set; } = null!;
    public List<string> IncludeEqualDirs { get; set; } = null!;
    public List<string> IncludeStartDirs { get; set; } = null!;
    public List<string> IncludeEndDirs { get; set; } = null!;
    public List<string> ExcludeEqualFiles { get; set; } = null!;
    public List<string> ExcludeStartFiles { get; set; } = null!;
    public List<string> ExcludeEndFiles { get; set; } = null!;
    public List<string> IncludeEqualFiles { get; set; } = null!;
    public List<string> IncludeStartFiles { get; set; } = null!;
    public List<string> IncludeEndFiles { get; set; } = null!;
    public List<string> CodeToMarkDownExtension { get; set; } = null!;
    public Dictionary<string, string> CodeSuffixMap { get; set; } = null!;
    public string DstBackFolder { get; set; } = null!;
    public Config(string srcPath)
    {
        _srcPath = srcPath;
        _code2mdConfigFolder = Path.Combine(_srcPath, ".vscode");
        _code2mdConfigPath = Path.Combine(_srcPath, ".vscode", "code2md.yaml");
    }
    public bool CheckCode2mdConfig()
    {
        if (!Directory.Exists(_code2mdConfigFolder))
        {
            Directory.CreateDirectory(_code2mdConfigFolder);
        }
        if (!Path.Exists(_code2mdConfigPath))
        {
            Console.WriteLine($"无配置文件 : {_code2mdConfigPath} , 已生成配置文件,然后返回");
            File.WriteAllText(_code2mdConfigPath, GenerateCode2mdConfigYaml(), System.Text.Encoding.UTF8);
            return false;
        }
        return true;
    }
    public void LoadConfig()
    {
        _configurationRoot = new ConfigurationBuilder().SetBasePath(_srcPath).AddYamlFile(_code2mdConfigPath, optional: true, reloadOnChange: true).Build();
        ExcludeEqualDirs = GetConfigList("ExcludeEqualDirs");
        ExcludeStartDirs = GetConfigList("ExcludeStartDirs");
        ExcludeEndDirs = GetConfigList("ExcludeEndDirs");
        IncludeEqualDirs = GetConfigList("IncludeEqualDirs");
        IncludeStartDirs = GetConfigList("IncludeStartDirs");
        IncludeEndDirs = GetConfigList("IncludeEndDirs");
        ExcludeEqualFiles = GetConfigList("ExcludeEqualFiles");
        ExcludeStartFiles = GetConfigList("ExcludeStartFiles");
        ExcludeEndFiles = GetConfigList("ExcludeEndFiles");
        IncludeEqualFiles = GetConfigList("IncludeEqualFiles");
        IncludeStartFiles = GetConfigList("IncludeStartFiles");
        IncludeEndFiles = GetConfigList("IncludeEndFiles");
        CodeToMarkDownExtension = GetConfigList("CodeToMarkDownExtension");
        CodeSuffixMap = GetConfigMap("CodeSuffixDic");
        var dstBackFolder = GetConfigValue("DstBackFolder");
        if (string.IsNullOrEmpty(dstBackFolder))
        {
            string? v = Path.GetDirectoryName(_srcPath);
            if (string.IsNullOrEmpty(v))
            {
                throw new Exception($"无法获取当前项目的父文件夹 : {_srcPath}");
            }
            Console.WriteLine($"使用默认的备份文件夹 : {v}");
            DstBackFolder = v;
        }
        else
        {
            DstBackFolder = dstBackFolder;
        }
        Directory.CreateDirectory(DstBackFolder);
    }
    private string? GetConfigValue(string sectionName)
    {
        return _configurationRoot.GetSection(sectionName).Value;
    }
    public bool GetExcludeDirFlag(string folderName)
    {
        return ExcludeEqualDirs.Any(folder => folderName.Equals(folder)) || ExcludeStartDirs.Any(folder => folderName.StartsWith(folder)) || ExcludeEndDirs.Any(folder => folderName.EndsWith(folder));
    }
    public bool GetIncludeDirFlag(string folderName)
    {
        return IncludeEqualDirs.Any(folder => folderName.Equals(folder)) || IncludeStartDirs.Any(folder => folderName.StartsWith(folder)) || IncludeEndDirs.Any(folder => folderName.EndsWith(folder));
    }
    public bool GetExcludeFileFlag(string fileName)
    {
        return ExcludeEqualFiles.Any(folder => fileName.Equals(folder)) || ExcludeStartFiles.Any(folder => fileName.StartsWith(folder)) || ExcludeEndFiles.Any(folder => fileName.EndsWith(folder));
    }
    public bool GetIncludeFileFlag(string fileName)
    {
        return IncludeEqualFiles.Any(folder => fileName.Equals(folder)) || IncludeStartFiles.Any(folder => fileName.StartsWith(folder)) || IncludeEndFiles.Any(folder => fileName.EndsWith(folder));
    }
    private List<string> GetConfigList(string sectionName)
    {
        return _configurationRoot.GetSection(sectionName).GetChildren().Select(child => child.Value ?? string.Empty).ToList();
    }
    private Dictionary<string, string> GetConfigMap(string sectionName)
    {
        return _configurationRoot.GetSection(sectionName).GetChildren().ToDictionary(e => e.Key, e => e.Value ?? string.Empty);
    }
    public static string GenerateCode2mdConfigYaml()
    {
        return @"DstBackFolder: """"
ExcludeEqualDirs:
  - ""res""
  - ""docs""
  - ""note""
  - ""config""
  - ""Publish""
  - "".idea""
  - "".vs""
  - "".vscode""
  - "".git""
  - ""zz_pro""
  - ""zz_res""
  - ""zz_zz""
  - ""bin""
  - ""zz_config""
  - ""zz_note""
  - ""zz_cache""
  - ""node_modules""
  - ""obj""
  - ""zz_zz_publish""
  - ""zz_zz_pro""
  - ""Migrations""
  - ""log""
  - ""logs""
ExcludeStartDirs: []
ExcludeEndDirs: []
IncludeEqualDirs: []
IncludeStartDirs: []
IncludeEndDirs: []
ExcludeEqualFiles:
  - ""zz.bat""
  - ""AssemblyInfo.cs""
  - ""out.txt""
ExcludeStartFiles:
  - ""temp""
ExcludeEndFiles:
  - "".xlsx""
  - "".doc""
  - "".docx""
  - "".ppt""
  - "".pptx""
  - "".pdf""
  - "".png""
  - "".jpg""
  - "".jpeg""
  - "".gif""
  - "".mp4""
  - "".mp3""
IncludeEqualFiles: []
IncludeStartFiles: []
IncludeEndFiles: []
CodeSuffixDic:
  "".cs"": ""cs""
  "".csproj"": ""csproj""
  "".http"": ""http""
  "".bat"": ""sh""
  "".ps1"": ""sh""
  "".py"": ""py""
  "".js"": ""js""
  "".ts"": ""ts""
  "".cpp"": ""cpp""
  "".c"": ""c""
  "".json"": ""json""
  "".sln"": ""xml""
  "".config"": ""config""
  "".xaml"": ""xml""
CodeToMarkDownExtension:
  - "".txt""
  - "".log""
  - "".ini""
  - "".conf""
  - "".cfg""
  - "".toml""
  - "".yml""
  - "".yaml""
  - "".json""
  - "".xml""
  - "".properties""
  - "".c""
  - "".cpp""
  - "".h""
  - "".hpp""
  - "".cs""
  - "".java""
  - "".js""
  - "".ts""
  - "".py""
  - "".rb""
  - "".php""
  - "".go""
  - "".rs""
  - "".swift""
  - "".m""
  - "".mm""
  - "".scala""
  - "".groovy""
  - "".pl""
  - "".pm""
  - "".sh""
  - "".bat""
  - "".cmd""
  - "".ps1""
  - "".html""
  - "".htm""
  - "".css""
  - "".markdown""
  - "".rst""
  - "".sql""
  - "".graphql""
  - "".sln""
  - "".csproj""
  - "".vbproj""
  - "".fsproj""
  - "".gradle""
  - "".pom.xml""
  - "".gemspec""
  - "".npmrc""
  - "".yarnrc""
  - "".package.json""
  - "".cabal""
  - "".opam""
  - "".pubspec.yaml""
  - "".rst""
  - "".tex""
  - "".gitignore""
  - "".editorconfig""
  - "".dockerfile""
  - "".env""
  - "".class""
  - "".asm""
  - "".ada""
  - "".pas""
  - "".bas""
  - "".xaml""
  - "".axaml""
  - "".manifest""
  - "".config""
  - "".qwenignore""";
    }
}

CodingTookit\.claude\settings.local.json


{
  "permissions": {
    "allow": [
      "Bash(cat:*)",
      "Bash(dotnet build:*)"
    ]
  }
}

CodingTookit\src\SqlServerRunner\SqlServerRunner.csproj


<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net9.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

</Project>

CodingTookit\scripts\sql.bat


@echo off
set "scriptPath=%cd%"
D: && cd D:\CodingTookit\src\LatestSqlFinder\bin\Release\net9.0\win-x64\publish\ && D:\CodingTookit\src\LatestSqlFinder\bin\Release\net9.0\win-x64\publish\LatestSqlFinder.exe  "%scriptPath%"
D: && cd D:\CodingTookit\src\SqlServerRunner\bin\Release\net9.0\win-x64\publish\ && D:\CodingTookit\src\SqlServerRunner\bin\Release\net9.0\win-x64\publish\SqlServerRunner.exe  "%scriptPath%"

CodingTookit\src\LatestSqlFinder\LatestSqlFinder.csproj


<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net9.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.Configuration" Version="9.0.0" />
    <PackageReference Include="NetEscapades.Configuration.Yaml" Version="3.1.0" />
    <PackageReference Include="YamlDotNet" Version="15.1.2" />
  </ItemGroup>
</Project>

CodingTookit\publish.bat



dotnet publish .\src\Code2md\Code2md.csproj -c Release -r win-x64 --self-contained true /p:PublishSingleFile=true /p:IncludeNativeLibrariesForSelfExtract=true


dotnet publish .\src\CopyFileV2\CopyFileV2.csproj -c Release -r win-x64 --self-contained true /p:PublishSingleFile=true /p:IncludeNativeLibrariesForSelfExtract=true

CodingTookit\scripts\code2md.bat


@echo off
set "scriptPath=%cd%"
D: && cd D:\CodingTookit\src\Code2md\bin\Release\net9.0\win-x64\publish\ && D:\CodingTookit\src\Code2md\bin\Release\net9.0\win-x64\publish\Code2md.exe  "%scriptPath%"

  






CodingTookit\scripts\backup.bat


@echo off
set "scriptPath=%cd%"
D: && cd D:\CodingTookit\src\CopyFileV2\bin\Release\net9.0\win-x64\publish\ && D:\CodingTookit\src\CopyFileV2\bin\Release\net9.0\win-x64\publish\Code2mdV2.exe  "%scriptPath%"


  











CodingTookit\src\CopyFileV2\Program.cs


using System.Text;
if (args.Length == 0)
{
    Console.WriteLine("请传入文件夹路径");
    return;
}
if (!Directory.Exists(args[0]))
{
    Console.WriteLine($"传入的文件夹不存在 : {args[0]}");
    return;
}
string srcPath = args[0];
Console.WriteLine($"============== CopyFile START ==================");
Config config = new Config(srcPath);
bool hasConfig = config.CheckCode2mdConfig();
if (!hasConfig)
{
    Console.WriteLine("已生成被配置文件,配置后重新运行");
    return;
}
config.LoadConfig();
Console.WriteLine("请输入文件名后缀:");
Console.InputEncoding = Encoding.Unicode;
Console.OutputEncoding = Encoding.Unicode;
string suffix = Console.ReadLine()?.Trim() ?? string.Empty;
var collector = new Collector(srcPath, config, suffix);
await collector.BackupProject();
Console.WriteLine($"============== CopyFile  END ==============");

CodingTookit\src\CopyFileV2\Collector.cs


using System.Collections.Concurrent;
using System.Runtime.CompilerServices;
public class Collector
{
    private ConcurrentQueue<string> _directoryQueue = new ConcurrentQueue<string>();
    private ConcurrentQueue<string> _fileQueue = new ConcurrentQueue<string>();
    private ManualResetEvent _directoryTraversalFinished = new ManualResetEvent(false);
    private ManualResetEvent _allFileProducersFinished = new ManualResetEvent(false);
    private int _numDirectoryConsumers;
    private int _numFileConsumers;
    private int[] _completedDirectoryConsumers = new int[1];
    private DateTime _startTime;
    private DateTime _endTime;
    private TimeSpan _totalTime;
    private readonly string _srcPath;
    private readonly Config _config;
    private readonly string _suffix = string.Empty;
    public Collector(string srcPath, Config config, string suffix)
    {
        _srcPath = srcPath;
        _config = config;
        _suffix = suffix;
    }
    public DateTime StartTime => _startTime;
    public DateTime EndTime => _endTime;
    public TimeSpan TotalTime => _totalTime;
    private string _backupFolderName = null!;
    public async Task BackupProject()
    {
        _startTime = DateTime.Now;
        _backupFolderName = Path.GetFileName(_srcPath) + $"_{_startTime:yyyyMMdd_HHmmss}_{_suffix}";
        InitializeProcessing();
        var directoryProducerTask = Task.Run(() => DirectoryProducer(_directoryQueue, _directoryTraversalFinished));
        var directoryConsumerTasks = new Task[_numDirectoryConsumers];
        for (int i = 0; i < _numDirectoryConsumers; i++)
        {
            directoryConsumerTasks[i] = Task.Run(() => DirectoryConsumer(_directoryQueue, _fileQueue, _directoryTraversalFinished, _completedDirectoryConsumers, _numDirectoryConsumers, _allFileProducersFinished));
        }
        var fileConsumerTasks = new Task[_numFileConsumers];
        for (int i = 0; i < _numFileConsumers; i++)
        {
            fileConsumerTasks[i] = Task.Run(() => FileConsumer(_fileQueue, _allFileProducersFinished));
        }
        await directoryProducerTask;
        _directoryTraversalFinished.Set(); // 通知目录遍历已完成
        await Task.WhenAll(directoryConsumerTasks);
        await Task.WhenAll(fileConsumerTasks);
        _endTime = DateTime.Now;
        _totalTime = _endTime - _startTime;
    }
    private void InitializeProcessing()
    {
        _directoryQueue = new ConcurrentQueue<string>();
        _fileQueue = new ConcurrentQueue<string>();
        _directoryTraversalFinished.Reset();
        _allFileProducersFinished.Reset();
        _completedDirectoryConsumers[0] = 0;
        _numDirectoryConsumers = Math.Max(1, Environment.ProcessorCount / 4); // 1/4用于目录消费者
        _numFileConsumers = Math.Max(1, (3 * Environment.ProcessorCount) / 4); // 3/4用于文件消费者
    }
    private void DirectoryProducer(ConcurrentQueue<string> directoryQueue, ManualResetEvent directoryTraversalFinished)
    {
        try
        {
            var stack = new Stack<string>();
            stack.Push(_srcPath);
            directoryQueue.Enqueue(_srcPath);
            while (stack.Count > 0)
            {
                string currentDir = stack.Pop();
                string[] subDirs;
                try
                {
                    subDirs = Directory.GetDirectories(currentDir, "*.*", SearchOption.TopDirectoryOnly);
                }
                catch (UnauthorizedAccessException)
                {
                    continue;
                }
                foreach (string dir in subDirs)
                {
                    string dirName = Path.GetFileName(dir);
                    if (_config.GetExcludeDirFlag(dirName) && !_config.GetIncludeDirFlag(dirName))
                    {
                        continue;
                    }
                    stack.Push(dir);
                    directoryQueue.Enqueue(dir);
                }
            }
        }
        finally
        {
            directoryTraversalFinished.Set();
        }
    }
    public List<string> GetAllLevelDirectories()
    {
        var result = new List<string>();
        var stack = new Stack<string>();
        stack.Push(_srcPath);
        while (stack.Count > 0)
        {
            string currentDir = stack.Pop();
            string[] subDirs;
            try
            {
                subDirs = Directory.GetDirectories(currentDir, "*.*", SearchOption.TopDirectoryOnly);
            }
            catch (UnauthorizedAccessException)
            {
                continue;
            }
            foreach (string dir in subDirs)
            {
                string dirName = Path.GetFileName(dir);
                if (_config.GetExcludeDirFlag(dirName) && !_config.GetIncludeDirFlag(dirName))
                {
                    continue;
                }
                result.Add(dir);
                stack.Push(dir);
            }
        }
        return result;
    }
    public static List<string> GetAllDirectories(string rootPath, HashSet<string> excludeFolders)
    {
        ArgumentNullException.ThrowIfNull(rootPath);
        ArgumentNullException.ThrowIfNull(excludeFolders);
        var result = new List<string>();
        var stack = new Stack<string>();
        stack.Push(rootPath);
        while (stack.Count > 0)
        {
            string currentDir = stack.Pop();
            string[] subDirs;
            try
            {
                subDirs = Directory.GetDirectories(currentDir, "*", SearchOption.TopDirectoryOnly);
            }
            catch (UnauthorizedAccessException)
            {
                continue;
            }
            catch (DirectoryNotFoundException)
            {
                continue;
            }
            foreach (string dir in subDirs)
            {
                string dirName = GetDirectoryName(dir);
                if (!excludeFolders.Contains(dirName))
                {
                    result.Add(dir);
                    stack.Push(dir);
                }
            }
        }
        return result;
    }
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    private static string GetDirectoryName(string path)
    {
        int separatorIndex = path.LastIndexOf(Path.DirectorySeparatorChar);
        return separatorIndex >= 0 ? path[(separatorIndex + 1)..] : path;
    }
    private void DirectoryConsumer(ConcurrentQueue<string> directoryQueue, ConcurrentQueue<string> fileQueue, ManualResetEvent directoryTraversalFinished, int[] completedDirectoryConsumers, int totalDirectoryConsumers, ManualResetEvent allFileProducersFinished)
    {
        bool keepProcessing = true;
        while (keepProcessing)
        {
            if (directoryQueue.TryDequeue(out string? dirPath))
            {
                try
                {
                    var files = Directory.GetFiles(dirPath, "*", SearchOption.TopDirectoryOnly);
                    foreach (var file in files)
                    {
                        string fileName = Path.GetFileName(file);
                        if (_config.GetExcludeFileFlag(fileName) && !_config.GetIncludeFileFlag(fileName))
                        {
                            continue;
                        }
                        fileQueue.Enqueue(file);
                    }
                }
                catch (UnauthorizedAccessException)
                {
                    continue;
                }
            }
            else
            {
                if (directoryTraversalFinished.WaitOne(0) && directoryQueue.IsEmpty)
                {
                    keepProcessing = false;
                }
                else
                {
                    Thread.Sleep(10);
                }
            }
        }
        if (Interlocked.Increment(ref completedDirectoryConsumers[0]) == totalDirectoryConsumers)
        {
            allFileProducersFinished.Set();
        }
    }
    private void FileConsumer(ConcurrentQueue<string> fileQueue, ManualResetEvent allFileProducersFinished)
    {
        bool keepProcessing = true;
        while (keepProcessing)
        {
            if (fileQueue.TryDequeue(out string? filePath))
            {
                string relativePath = Path.GetRelativePath(_srcPath, filePath);
                string dstCodePath = Path.Combine(_config.DstBackFolder, _backupFolderName, relativePath);
                string? dirPath = Path.GetDirectoryName(dstCodePath);
                if (!string.IsNullOrEmpty(dirPath))
                {
                    Directory.CreateDirectory(dirPath);
                }
                CopyFile(filePath, dstCodePath);
            }
            else
            {
                if (allFileProducersFinished.WaitOne(0) && fileQueue.IsEmpty)
                {
                    keepProcessing = false;
                }
                else
                {
                    Thread.Sleep(10);
                }
            }
        }
    }
    private static void CopyFile(string srcPath, string dstPath, int maxRetries = 3)
    {
        int retries = 0;
        while (true)
        {
            try
            {
                File.Copy(srcPath, dstPath, false);
                System.Console.WriteLine(srcPath + "=>" + dstPath);
                if (!File.Exists(dstPath))
                {
                    throw new IOException("文件复制后不存在于目标位置");
                }
                break;
            }
            catch (Exception ex)
            {
                retries++;
                if (retries > maxRetries)
                {
                    Console.WriteLine($"文件移动失败 ({srcPath} : {ex.Message}");
                    throw;
                }
                Thread.Sleep(500 * retries);
            }
        }
    }
}

CodingTookit\old\CopyFile\Program.cs


using System.Collections.Concurrent;
using System.Diagnostics;
public class Program
{
    private static string SourceDirectory = string.Empty;
    private static string DstFolderPath = string.Empty;
    private static string SourceDirectoryBakPath = string.Empty;
    private static string DirectorySuffix = string.Empty;
    private static readonly DateTime Now = DateTime.Now;
    private static readonly List<string> ExcludedEqualDirectories = new List<string> { "bin", "obj", "npm_modules", ".git", "Publish" };
    private static readonly BlockingCollection<CopyFileTask> BackupCollection = new BlockingCollection<CopyFileTask>();
    private static readonly ConcurrentDictionary<string, object> DirectoryLocks = new ConcurrentDictionary<string, object>();
    private static readonly CancellationTokenSource CancellationTokenSource = new CancellationTokenSource();
    static void Main(string[] args)
    {
        try
        {
            Console.WriteLine("正在扫描文件...");
            System.Console.WriteLine("输入文件夹后缀:");
            DirectorySuffix = System.Console.ReadLine() ?? string.Empty;
            if (args.Length == 0)
            {
                System.Console.WriteLine("请传入文件夹路径");
                return;
            }
            SourceDirectory = args[0];
            if (!Directory.Exists(SourceDirectory))
            {
                Console.WriteLine($"错误: 源目录 {SourceDirectory} 不存在。");
                return;
            }
            System.Console.WriteLine("请输入目标文件夹:");
            DstFolderPath = System.Console.ReadLine() ?? string.Empty;
            if (DstFolderPath == string.Empty)
                return;
            SourceDirectoryBakPath = Path.GetFileName(SourceDirectory) + $"_{Now:yyyyMMdd_HHmmss}_{DirectorySuffix}";
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            var producerTask = Task.Run(() =>
            {
                try
                {
                    var options = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount * 2 };
                    Parallel.ForEach(
                        Directory.EnumerateDirectories(SourceDirectory),
                        options,
                        (dirPath) =>
                        {
                            ScanDirectory(dirPath);
                        }
                    );
                    GetFiles(SourceDirectory);
                }
                finally
                {
                    BackupCollection.CompleteAdding();
                }
            });
            Console.WriteLine("扫描已启动,开始并行处理文件...");
            const int maxThreads = 8;
            var backupTasks = new Task[maxThreads];
            for (int i = 0; i < maxThreads; i++)
            {
                backupTasks[i] = Task.Run(() => CodeBackup(CancellationTokenSource.Token));
            }
            Task.WaitAll(backupTasks);
            stopwatch.Stop();
            Console.WriteLine($"处理完成,共耗时 {stopwatch.Elapsed.TotalSeconds} s");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"\n发生致命错误: {ex.Message}");
        }
        finally
        {
            CancellationTokenSource.Cancel();
        }
        Console.WriteLine("============备份完成============");
    }
    private static bool FilterFolder(string dirPath)
    {
        var dirName = Path.GetFileName(dirPath);
        var excludedSet = new HashSet<string>(ExcludedEqualDirectories, StringComparer.OrdinalIgnoreCase);
        return !excludedSet.Contains(dirName);
    }
    private static void ScanDirectory(string currentPath)
    {
        if (!FilterFolder(currentPath))
            return;
        try
        {
            GetFiles(currentPath);
            var options = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount * 2 };
            Parallel.ForEach(
                Directory.EnumerateDirectories(currentPath),
                options,
                (subDirectory) =>
                {
                    ScanDirectory(subDirectory); // 递归调用
                }
            );
        }
        catch (IOException ex)
        {
            Console.WriteLine($"IOException ex: {ex.Message}");
        }
        catch (UnauthorizedAccessException ex)
        { /* 忽略无权限目录 */
            System.Console.WriteLine($"UnauthorizedAccessException ex: {ex.Message} ");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"\n扫描目录时出错 ({currentPath}): {ex.Message}");
        }
    }
    private static void GetFiles(string sourcePath)
    {
        var files = Directory.GetFiles(sourcePath, "*", SearchOption.TopDirectoryOnly);
        foreach (string filePath in files)
        {
            string relativePath = Path.GetRelativePath(SourceDirectory, filePath);
            string dstCodePath = Path.Combine(DstFolderPath, SourceDirectoryBakPath, relativePath);
            EnsureDirectoryExists(Path.GetDirectoryName(dstCodePath)!);
            var task = new CopyFileTask { CodePath = filePath, DstCodePath = dstCodePath };
            BackupCollection.Add(task);
        }
    }
    private static void CodeBackup(CancellationToken cancellationToken)
    {
        try
        {
            foreach (var copyFileTask in BackupCollection.GetConsumingEnumerable(cancellationToken))
            {
                try
                {
                    CopyFile(copyFileTask);
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"\n处理文件时出错 ({copyFileTask.CodePath}): {ex.Message}");
                }
            }
        }
        catch (OperationCanceledException)
        {
            System.Console.WriteLine("\n文件处理已取消。");
        }
    }
    private static void CopyFile(CopyFileTask code2mdTask, int maxRetries = 3)
    {
        int retries = 0;
        while (true)
        {
            try
            {
                string codePath = code2mdTask.CodePath;
                string dstCodePath = code2mdTask.DstCodePath;
                File.Copy(codePath, dstCodePath, false);
                System.Console.WriteLine(codePath + "=>" + dstCodePath);
                if (!File.Exists(dstCodePath))
                {
                    throw new IOException("文件复制后不存在于目标位置");
                }
                break;
            }
            catch (Exception ex)
            {
                retries++;
                if (retries > maxRetries)
                {
                    Console.WriteLine($"文件移动失败 ({code2mdTask.CodePath} : {ex.Message}");
                    throw;
                }
                Thread.Sleep(500 * retries);
            }
        }
    }
    private static void EnsureDirectoryExists(string directoryPath)
    {
        if (Directory.Exists(directoryPath))
            return;
        object dirLock = DirectoryLocks.GetOrAdd(directoryPath, _ => new object());
        if (!Directory.Exists(directoryPath))
        {
            if (Directory.Exists(directoryPath))
                return;
            lock (dirLock)
            {
                Directory.CreateDirectory(directoryPath);
            }
        }
    }
}
public class CopyFileTask
{
    public required string CodePath { get; set; }
    public required string DstCodePath { get; set; }
}

CodingTookit\src\CopyFileV2\CopyFileV2.csproj


<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net9.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.Configuration" Version="9.0.0" />
    <PackageReference Include="NetEscapades.Configuration.Yaml" Version="3.1.0" />
    <PackageReference Include="YamlDotNet" Version="15.1.2" />
  </ItemGroup>



</Project>

CodingTookit\src\Code2md\Code2md.csproj


<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net9.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.Configuration" Version="9.0.0" />
    <PackageReference Include="NetEscapades.Configuration.Yaml" Version="3.1.0" />
    <PackageReference Include="YamlDotNet" Version="15.1.2" />
  </ItemGroup>

</Project>

CodingTookit\.csharpierrc.json


{
  "printWidth": 300,
  "useTabs": false,
  "tabWidth": 4,
  "endOfLine": "auto"
}

CodingTookit\old\CopyFile\CopyFile.csproj


<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net9.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

</Project>

CodingTookit\README.md_# CodingTookit

Code2md

说明

convert code project to one markdown file.

发布

dotnet publish .\src\Code2md\Code2md.csproj -c Release -r win-x64 --self-contained true /p:PublishSingleFile=true /p:IncludeNativeLibrariesForSelfExtract=true
dotnet publish .\src\Code2md\Code2md.csproj -c Release -r linux-x64 --self-contained true /p:PublishSingleFile=true /p:IncludeNativeLibrariesForSelfExtract=true

部署脚本

Windows

@echo off
set "scriptPath=%cd%"
D: && cd D:\CodingTookit\src\Code2md\bin\Release\net9.0\win-x64\publish\ && D:\CodingTookit\src\Code2md\bin\Release\net9.0\win-x64\publish\Code2md.exe  "%scriptPath%"
@echo off
set "scriptPath=%cd%"
D: && cd D:\Code2Md\Code2md\bin\Debug\net9.0\ && D:\Code2Md\Code2md\bin\Debug\net9.0\Code2md.exe  "%scriptPath%"

Linux

#!/bin/bash
_`# 1. 获取当前工作目录(对应bat的%cd%)`

scriptPath=$PWD
_`# 2. 替换为你Linux下Code2md程序的实际路径(关键!需修改)`

_`# 原bat路径:D:\Code2Md\Publish\Code2md\V2.0.0\Code2md.exe`

_`# 示例Linux路径(请替换为你实际的发布路径):`

program_path="D:\CodingTookit\src\Code2md\bin\Release\net9.0\linux-x64\publish\Code2md"
_`# 3. 执行程序,传递当前目录作为参数`

if [ -f "$program_path" ]; then
_`    # 执行程序并传递参数`

    "$program_path" "$scriptPath"
else
_`    # 程序文件不存在时提示`

    echo "错误:未找到Code2md程序,请检查路径是否正确!"
    echo "当前配置的程序路径:$program_path"
    exit 1
fi

CopyFileV2

说明

copy code project to dst folder.

发布

dotnet publish .\src\CopyFileV2\CopyFileV2.csproj -c Release -r win-x64 --self-contained true /p:PublishSingleFile=true /p:IncludeNativeLibrariesForSelfExtract=true

部署脚本

Windows

@echo off
set "scriptPath=%cd%"
D: && cd D:\CodingTookit\src\CopyFileV2\bin\Release\net9.0\win-x64\publish\ && D:\CodingTookit\src\CopyFileV2\bin\Release\net9.0\win-x64\publish\Code2mdV2.exe  "%scriptPath%"

Linux

LatestSqlFinder

说明

find latest sql file.

发布

dotnet publish .\src\LatestSqlFinder\LatestSqlFinder.csproj -c Release -r win-x64 --self-contained true /p:PublishSingleFile=true /p:IncludeNativeLibrariesForSelfExtract=true

部署脚本

Windows

@echo off
set "scriptPath=%cd%"
D: && cd D:\CodingTookit\src\LatestSqlFinder\bin\Release\net9.0\win-x64\publish\ && D:\CodingTookit\src\LatestSqlFinder\bin\Release\net9.0\win-x64\publish\LatestSqlFinder.exe  "%scriptPath%"

SqlServerRunner

说明

active sql server management studio

发布

dotnet publish .\src\SqlServerRunner\SqlServerRunner.csproj -c Release -r win-x64 --self-contained true /p:PublishSingleFile=true /p:IncludeNativeLibrariesForSelfExtract=true

部署脚本

Windows

@echo off
set "scriptPath=%cd%"
D: && cd D:\CodingTookit\src\SqlServerRunner\bin\Release\net9.0\win-x64\publish\ && D:\CodingTookit\src\SqlServerRunner\bin\Release\net9.0\win-x64\publish\SqlServerRunner.exe  "%scriptPath%"

Md2code

说明

convert markdown to code project.

发布

dotnet publish .\src\Md2code\Md2code.csproj -c Release -r win-x64 --self-contained true /p:PublishSingleFile=true /p:IncludeNativeLibrariesForSelfExtract=true
dotnet publish .\src\Md2code\Md2code.csproj -c Release -r linux-x64 --self-contained true /p:PublishSingleFile=true /p:IncludeNativeLibrariesForSelfExtract=true

部署脚本

Windows

@echo off
set "scriptPath=%cd%"
D: && cd D:\CodingTookit\src\Code2md\bin\Release\net9.0\win-x64\publish\ && D:\CodingTookit\src\Code2md\bin\Release\net9.0\win-x64\publish\Code2md.exe  "%scriptPath%"
@echo off
set "scriptPath=%cd%"
D: && cd D:\Code2Md\Code2md\bin\Debug\net9.0\ && D:\Code2Md\Code2md\bin\Debug\net9.0\Code2md.exe  "%scriptPath%"

Linux

#!/bin/bash
_`# 1. 获取当前工作目录(对应bat的%cd%)`

scriptPath=$PWD
_`# 2. 替换为你Linux下Code2md程序的实际路径(关键!需修改)`

_`# 原bat路径:D:\Code2Md\Publish\Code2md\V2.0.0\Code2md.exe`

_`# 示例Linux路径(请替换为你实际的发布路径):`

program_path="D:\CodingTookit\src\Code2md\bin\Release\net9.0\linux-x64\publish\Code2md"
_`# 3. 执行程序,传递当前目录作为参数`

if [ -f "$program_path" ]; then
_`    # 执行程序并传递参数`

    "$program_path" "$scriptPath"
else
_`    # 程序文件不存在时提示`

    echo "错误:未找到Code2md程序,请检查路径是否正确!"
    echo "当前配置的程序路径:$program_path"
    exit 1
fi

CodingTookit\CLAUDE.md_# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

CodingTookit is a .NET developer utility toolkit with two main components:

  1. Code2md (src/Code2md/): Converts code projects into a single consolidated Markdown document with syntax highlighting
  2. CopyFileV2 (src/CopyFileV2/): Parallel file backup tool for duplicating projects
    Both tools share the same configuration system (.vscode/code2md.yaml) for filtering files/directories.

Build Commands

_`# Build projects`

dotnet build ./src/Code2md/Code2md.csproj -c Debug
dotnet build ./src/CopyFileV2/CopyFileV2.csproj -c Debug
_`# Publish self-contained executables`

dotnet publish ./src/Code2md/Code2md.csproj -c Release -r win-x64 --self-contained true /p:PublishSingleFile=true
dotnet publish ./src/Code2md/Code2md.csproj -c Release -r linux-x64 --self-contained true /p:PublishSingleFile=true
dotnet publish ./src/CopyFileV2/CopyFileV2.csproj -c Release -r win-x64 --self-contained true /p:PublishSingleFile=true
_`# Run directly`

dotnet run --project ./src/Code2md/Code2md.csproj -- "/path/to/project"
dotnet run --project ./src/CopyFileV2/CopyFileV2.csproj -- "/path/to/project"

Configuration System

Both tools use .vscode/code2md.yaml for filtering:

  • DstBackFolder: Backup destination for CopyFileV2
  • ExcludeEqualDirs / ExcludeStartDirs / ExcludeEndDirs: Directory exclusion rules
  • ExcludeEqualFiles / ExcludeStartFiles / ExcludeEndFiles: File exclusion rules
  • CodeSuffixDic: Maps file extensions to markdown code block languages
  • CodeToMarkDownExtension: File types to include as code blocks
    Key default exclusions: bin, obj, .git, .vs, .vscode, node_modules, zz_zz

Architecture

  • Code2md: Entry point (Program.cs) → Project scanner (Project.cs) → Markdown generation
  • CopyFileV2: Uses concurrent queues with parallel consumer threads for fast file copying
    Both use Microsoft.Extensions.Configuration with YAML provider for config management.
posted on 2026-01-26 15:17  Song的学习笔记  阅读(5)  评论(0)    收藏  举报