From 632e58cfcec6fde1ab2d96365915c8d44f22e021 Mon Sep 17 00:00:00 2001
From: ninemine <1371605831@qq.com>
Date: Wed, 16 Jul 2025 15:25:11 +0800
Subject: [PATCH] BS 0.1.0 File
---
Convention-CSharp.csproj | 1 +
Convention/[Runtime]/File.cs | 999 +++++++++++++++++++++++++++++++----
Convention/[Runtime]/Math.cs | 6 -
[Test]/FileTest.cs | 214 ++++++++
[Test]/Program.cs | 19 +-
5 files changed, 1126 insertions(+), 113 deletions(-)
delete mode 100644 Convention/[Runtime]/Math.cs
create mode 100644 [Test]/FileTest.cs
diff --git a/Convention-CSharp.csproj b/Convention-CSharp.csproj
index 1bb1198..77e5def 100644
--- a/Convention-CSharp.csproj
+++ b/Convention-CSharp.csproj
@@ -5,6 +5,7 @@
Exe
net8.0
Convention
+ true
diff --git a/Convention/[Runtime]/File.cs b/Convention/[Runtime]/File.cs
index a8d0807..155a3b9 100644
--- a/Convention/[Runtime]/File.cs
+++ b/Convention/[Runtime]/File.cs
@@ -3,9 +3,41 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.Json;
+using System.IO.Compression;
+using System.Security.Cryptography;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using System.ComponentModel;
+using System.Runtime.InteropServices;
namespace Convention
{
+ // 自定义异常类
+ public class FileOperationException : Exception
+ {
+ public FileOperationException(string message) : base(message) { }
+ public FileOperationException(string message, Exception innerException) : base(message, innerException) { }
+ }
+
+ public class CompressionException : FileOperationException
+ {
+ public CompressionException(string message) : base(message) { }
+ public CompressionException(string message, Exception innerException) : base(message, innerException) { }
+ }
+
+ public class EncryptionException : FileOperationException
+ {
+ public EncryptionException(string message) : base(message) { }
+ public EncryptionException(string message, Exception innerException) : base(message, innerException) { }
+ }
+
+ public class HashException : FileOperationException
+ {
+ public HashException(string message) : base(message) { }
+ public HashException(string message, Exception innerException) : base(message, innerException) { }
+ }
+
[Serializable]
public sealed class ToolFile
{
@@ -13,7 +45,7 @@ namespace Convention
private FileSystemInfo OriginInfo;
public ToolFile(string path)
{
- FullPath = path;
+ FullPath = Path.GetFullPath(path);
Refresh();
}
public override string ToString()
@@ -52,6 +84,47 @@ namespace Convention
)..];
}
+ // 新增:获取文件名(对应 Python 的 GetFilename)
+ public string GetFilename(bool is_without_extension = false)
+ {
+ if (is_without_extension && Path.HasExtension(FullPath))
+ {
+ return Path.GetFileNameWithoutExtension(FullPath);
+ }
+ else if (FullPath.EndsWith(Path.DirectorySeparatorChar.ToString()) || FullPath.EndsWith(Path.AltDirectorySeparatorChar.ToString()))
+ {
+ return Path.GetFileName(FullPath.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar));
+ }
+ else
+ {
+ return Path.GetFileName(FullPath);
+ }
+ }
+
+ // 新增:获取目录路径(对应 Python 的 GetDir)
+ public string GetDir()
+ {
+ return Path.GetDirectoryName(FullPath);
+ }
+
+ // 新增:获取目录的 ToolFile 对象(对应 Python 的 GetDirToolFile)
+ public ToolFile GetDirToolFile()
+ {
+ return new ToolFile(GetDir());
+ }
+
+ // 新增:获取当前目录名(对应 Python 的 GetCurrentDirName)
+ public string GetCurrentDirName()
+ {
+ return Path.GetDirectoryName(FullPath);
+ }
+
+ // 新增:获取父目录(对应 Python 的 GetParentDir)
+ public ToolFile GetParentDir()
+ {
+ return new ToolFile(GetDir());
+ }
+
#endregion
#region Exists
@@ -112,6 +185,44 @@ namespace Convention
return result;
}
+ // 新增:加载为 CSV(使用 C# 内置功能)
+ public List LoadAsCsv()
+ {
+ if (IsFile() == false)
+ throw new InvalidOperationException("Target is not a file");
+
+ var lines = File.ReadAllLines(FullPath);
+ var result = new List();
+
+ foreach (var line in lines)
+ {
+ var fields = line.Split(',');
+ result.Add(fields);
+ }
+
+ return result;
+ }
+
+ // 新增:加载为 XML(使用 C# 内置功能)
+ public string LoadAsXml()
+ {
+ return LoadAsText();
+ }
+
+ // 新增:加载为 Excel(简化实现,实际需要第三方库)
+ public string LoadAsExcel()
+ {
+ // 注意:真正的 Excel 读取需要第三方库如 EPPlus 或 NPOI
+ // 这里返回文本内容作为简化实现
+ return LoadAsText();
+ }
+
+ // 新增:加载为未知格式(对应 Python 的 LoadAsUnknown)
+ public string LoadAsUnknown(string suffix)
+ {
+ return LoadAsText();
+ }
+
#endregion
#region Save
@@ -124,7 +235,7 @@ namespace Convention
{
EasySave.EasySave.Save(key, data,FullPath);
}
- private void SaveAsText(string data)
+ public void SaveAsText(string data)
{
using var fs = new FileStream(FullPath, FileMode.CreateNew, FileAccess.Write);
using var sw = new StreamWriter(fs);
@@ -151,6 +262,43 @@ namespace Convention
SaveDataAsBinary(FullPath, data, (OriginInfo as FileInfo).OpenWrite());
}
+ // 新增:保存为 CSV(对应 Python 的 SaveAsCsv)
+ public void SaveAsCsv(List csvData)
+ {
+ if (IsFile() == false)
+ throw new InvalidOperationException("Target is not a file");
+
+ var lines = csvData.Select(row => string.Join(",", row));
+ File.WriteAllLines(FullPath, lines);
+ }
+
+ // 新增:保存为 XML(对应 Python 的 SaveAsXml)
+ public void SaveAsXml(string xmlData)
+ {
+ SaveAsText(xmlData);
+ }
+
+ // 新增:保存为 Excel(简化实现)
+ public void SaveAsExcel(string excelData)
+ {
+ SaveAsText(excelData);
+ }
+
+ // 新增:保存为数据框(对应 Python 的 SaveAsDataframe)
+ public void SaveAsDataframe(List dataframeData)
+ {
+ SaveAsCsv(dataframeData);
+ }
+
+ // 新增:保存为未知格式(对应 Python 的 SaveAsUnknown)
+ public void SaveAsUnknown(object unknownData)
+ {
+ if (unknownData is byte[] bytes)
+ SaveAsBinary(bytes);
+ else
+ SaveAsText(unknownData.ToString());
+ }
+
#endregion
#region IsFileType
@@ -178,6 +326,48 @@ namespace Convention
#endregion
+ #region Size and Properties
+
+ // 新增:获取文件大小(对应 Python 的 GetSize)
+ public long GetSize()
+ {
+ if (IsDir())
+ {
+ return GetDirectorySize(FullPath);
+ }
+ else
+ {
+ return (OriginInfo as FileInfo)?.Length ?? 0;
+ }
+ }
+
+ private long GetDirectorySize(string path)
+ {
+ long size = 0;
+ try
+ {
+ var files = Directory.GetFiles(path);
+ foreach (var file in files)
+ {
+ var fileInfo = new FileInfo(file);
+ size += fileInfo.Length;
+ }
+
+ var dirs = Directory.GetDirectories(path);
+ foreach (var dir in dirs)
+ {
+ size += GetDirectorySize(dir);
+ }
+ }
+ catch (Exception)
+ {
+ // 忽略访问权限错误
+ }
+ return size;
+ }
+
+ #endregion
+
#region Operator
public static ToolFile operator |(ToolFile left, string rightPath)
@@ -185,6 +375,22 @@ namespace Convention
string lp = left.GetFullPath();
return new ToolFile(Path.Combine(lp, rightPath));
}
+
+ // 新增:相等比较(对应 Python 的 __eq__)
+ public override bool Equals(object obj)
+ {
+ if (obj is ToolFile other)
+ {
+ return Path.GetFullPath(FullPath).Equals(Path.GetFullPath(other.FullPath), StringComparison.OrdinalIgnoreCase);
+ }
+ return false;
+ }
+
+ public override int GetHashCode()
+ {
+ return Path.GetFullPath(FullPath).GetHashCode();
+ }
+
public ToolFile Open(string path)
{
this.FullPath = path;
@@ -240,6 +446,46 @@ namespace Convention
}
return this;
}
+
+ // 新增:复制方法重载(对应 Python 的 Copy)
+ public ToolFile Copy(string targetPath = null)
+ {
+ if (targetPath == null)
+ return new ToolFile(FullPath);
+
+ if (!Exists())
+ throw new FileNotFoundException("File not found");
+
+ var targetFile = new ToolFile(targetPath);
+ if (targetFile.IsDir())
+ targetFile = targetFile | GetFilename();
+
+ if (IsDir())
+ CopyDirectory(FullPath, targetFile.GetFullPath());
+ else
+ File.Copy(FullPath, targetFile.GetFullPath());
+
+ return targetFile;
+ }
+
+ private void CopyDirectory(string sourceDir, string destinationDir)
+ {
+ var dir = new DirectoryInfo(sourceDir);
+ Directory.CreateDirectory(destinationDir);
+
+ foreach (FileInfo file in dir.GetFiles())
+ {
+ string targetFilePath = Path.Combine(destinationDir, file.Name);
+ file.CopyTo(targetFilePath);
+ }
+
+ foreach (DirectoryInfo subDir in dir.GetDirectories())
+ {
+ string newDestinationDir = Path.Combine(destinationDir, subDir.Name);
+ CopyDirectory(subDir.FullName, newDestinationDir);
+ }
+ }
+
public ToolFile Delete()
{
if (IsDir())
@@ -248,152 +494,711 @@ namespace Convention
File.Delete(FullPath);
return this;
}
- public ToolFile Remove() => Delete();
- public ToolFile MustExistsPath()
+
+ // 新增:Remove 方法(对应 Python 的 Remove)
+ public ToolFile Remove()
{
- this.Close();
- this.TryCreateParentPath();
- this.Create();
- return this;
+ return Delete();
}
+
#endregion
- #region Dir
+ #region Directory Operations
+ public ToolFile MustExistsPath()
+ {
+ TryCreateParentPath();
+ Create();
+ return this;
+ }
public ToolFile TryCreateParentPath()
{
- if (this.GetName().Contains('/') || this.GetName().Contains('\\'))
+ string dirPath = Path.GetDirectoryName(FullPath);
+ if (!string.IsNullOrEmpty(dirPath) && !Directory.Exists(dirPath))
{
- var parent = new ToolFile(this.GetParentDir());
- if (parent.Exists())
- {
- parent.Create();
- }
+ Directory.CreateDirectory(dirPath);
+ }
+ return this;
+ }
+ public List DirIter()
+ {
+ if (!IsDir())
+ throw new InvalidOperationException("Target is not a directory");
+ return Directory.GetFileSystemEntries(FullPath).ToList();
+ }
+ public List DirToolFileIter()
+ {
+ if (!IsDir())
+ throw new InvalidOperationException("Target is not a directory");
+ var result = new List();
+ foreach (var entry in Directory.GetFileSystemEntries(FullPath))
+ {
+ result.Add(new ToolFile(entry));
+ }
+ return result;
+ }
+ public ToolFile BackToParentDir()
+ {
+ FullPath = GetDir();
+ Refresh();
+ return this;
+ }
+ public int DirCount(bool ignore_folder = true)
+ {
+ if (!IsDir())
+ throw new InvalidOperationException("Target is not a directory");
+
+ var entries = Directory.GetFileSystemEntries(FullPath);
+ if (ignore_folder)
+ {
+ return entries.Count(entry => File.Exists(entry));
+ }
+ return entries.Length;
+ }
+ public ToolFile DirClear()
+ {
+ if (!IsDir())
+ throw new InvalidOperationException("Target is not a directory");
+
+ foreach (var file in DirToolFileIter())
+ {
+ file.Remove();
}
return this;
}
- public List DirIter()
+ // 新增:MakeFileInside 方法(对应 Python 的 MakeFileInside)
+ public ToolFile MakeFileInside(ToolFile data, bool is_delete_source = false)
{
- if (this.IsDir())
+ if (!IsDir())
+ throw new InvalidOperationException("Cannot make file inside a file, because this object target is not a directory");
+
+ var result = this | data.GetFilename();
+ if (is_delete_source)
+ data.Move(result.GetFullPath());
+ else
+ data.Copy(result.GetFullPath());
+
+ return this;
+ }
+
+ // 新增:查找文件方法(对应 Python 的 FirstFileWithExtension)
+ public ToolFile FirstFileWithExtension(string extension)
+ {
+ var targetDir = IsDir() ? this : GetDirToolFile();
+ foreach (var file in targetDir.DirToolFileIter())
{
- var dir = new DirectoryInfo(FullPath);
- var result = dir.GetDirectories().ToList().ConvertAll(x => x.FullName);
- result.AddRange(dir.GetFiles().ToList().ConvertAll(x => x.FullName));
- return result;
+ if (!file.IsDir() && file.GetExtension() == extension)
+ {
+ return file;
+ }
}
return null;
}
- public List DirToolFileIter()
+ // 新增:查找文件方法(对应 Python 的 FirstFile)
+ public ToolFile FirstFile(Func predicate)
{
- if (this.IsDir())
+ var targetDir = IsDir() ? this : GetDirToolFile();
+ foreach (var file in targetDir.DirToolFileIter())
{
- return DirIter().ConvertAll(x => new ToolFile(x));
- }
- throw new DirectoryNotFoundException(FullPath);
- }
-
- public ToolFile BackToParentDir()
- {
- var file = new ToolFile(this.GetParentDir());
- this.Close();
- this.FullPath = file.FullPath;
- this.OriginInfo = file.OriginInfo;
- return this;
- }
-
- public ToolFile GetParentDir()
- {
- if (IsDir())
- return new ToolFile((this.OriginInfo as DirectoryInfo).Parent.FullName);
- else
- return new ToolFile((this.OriginInfo as FileInfo).DirectoryName);
- }
-
- public int DirCount()
- {
- if (IsDir())
- return Directory.EnumerateFiles(FullPath).Count();
- return -1;
- }
-
- public ToolFile DirClear()
- {
- if (IsDir())
- {
- foreach (var file in DirIter())
+ if (predicate(file.GetFilename()))
{
- File.Delete(file);
+ return file;
}
}
- throw new DirectoryNotFoundException();
+ return null;
}
- public ToolFile MakeFileInside(string source, bool isDeleteSource = false)
+ // 新增:查找所有文件方法(对应 Python 的 FindFileWithExtension)
+ public List FindFileWithExtension(string extension)
{
- if (this.IsDir() == false)
- throw new DirectoryNotFoundException(FullPath);
- string target = this | source;
- if (isDeleteSource)
- File.Move(target, source);
- else
- File.Copy(target, source);
- return this;
+ var targetDir = IsDir() ? this : GetDirToolFile();
+ var result = new List();
+ foreach (var file in targetDir.DirToolFileIter())
+ {
+ if (!file.IsDir() && file.GetExtension() == extension)
+ {
+ result.Add(file);
+ }
+ }
+ return result;
+ }
+
+ // 新增:查找所有文件方法(对应 Python 的 FindFile)
+ public List FindFile(Func predicate)
+ {
+ var targetDir = IsDir() ? this : GetDirToolFile();
+ var result = new List();
+ foreach (var file in targetDir.DirToolFileIter())
+ {
+ if (predicate(file.GetFilename()))
+ {
+ result.Add(file);
+ }
+ }
+ return result;
}
#endregion
+ #region Compression
+
+ // 新增:压缩方法(对应 Python 的 Compress)
+ public ToolFile Compress(string outputPath = null, string format = "zip")
+ {
+ if (!Exists())
+ throw new FileNotFoundException($"File not found: {GetFullPath()}");
+
+ if (outputPath == null)
+ {
+ outputPath = GetFullPath() + (format == "zip" ? ".zip" : ".tar");
+ }
+
+ try
+ {
+ if (format.ToLower() == "zip")
+ {
+ if (IsDir())
+ {
+ ZipFile.CreateFromDirectory(FullPath, outputPath);
+ }
+ else
+ {
+ using (var archive = ZipFile.Open(outputPath, ZipArchiveMode.Create))
+ {
+ archive.CreateEntryFromFile(FullPath, GetFilename());
+ }
+ }
+ }
+ else
+ {
+ throw new CompressionException($"Unsupported compression format: {format}");
+ }
+
+ return new ToolFile(outputPath);
+ }
+ catch (Exception ex)
+ {
+ throw new CompressionException($"Compression failed: {ex.Message}", ex);
+ }
+ }
+
+ // 新增:解压方法(对应 Python 的 Decompress)
+ public ToolFile Decompress(string outputPath = null)
+ {
+ if (!Exists() || !IsFile())
+ throw new FileNotFoundException($"File not found: {GetFullPath()}");
+
+ if (GetExtension().ToLower() != "zip")
+ throw new CompressionException("Only ZIP files are supported for decompression");
+
+ if (outputPath == null)
+ {
+ outputPath = Path.Combine(GetDir(), Path.GetFileNameWithoutExtension(GetFilename()));
+ }
+
+ try
+ {
+ ZipFile.ExtractToDirectory(FullPath, outputPath);
+ return new ToolFile(outputPath);
+ }
+ catch (Exception ex)
+ {
+ throw new CompressionException($"Decompression failed: {ex.Message}", ex);
+ }
+ }
+
+ #endregion
+
+ #region Encryption
+
+ // 新增:加密方法(对应 Python 的 Encrypt)
+ public ToolFile Encrypt(string key, string algorithm = "AES")
+ {
+ if (!Exists() || !IsFile())
+ throw new FileNotFoundException($"File not found: {GetFullPath()}");
+
+ try
+ {
+ byte[] data = LoadAsBinary();
+ byte[] encryptedData;
+
+ if (algorithm.ToUpper() == "AES")
+ {
+ using (var aes = Aes.Create())
+ {
+ var keyBytes = Encoding.UTF8.GetBytes(key.PadRight(32).Substring(0, 32));
+ aes.Key = keyBytes;
+ aes.GenerateIV();
+
+ using (var encryptor = aes.CreateEncryptor())
+ using (var ms = new MemoryStream())
+ {
+ ms.Write(aes.IV, 0, aes.IV.Length);
+ using (var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
+ {
+ cs.Write(data, 0, data.Length);
+ cs.FlushFinalBlock();
+ }
+ encryptedData = ms.ToArray();
+ }
+ }
+ }
+ else
+ {
+ throw new EncryptionException($"Unsupported encryption algorithm: {algorithm}");
+ }
+
+ SaveAsBinary(encryptedData);
+ return this;
+ }
+ catch (Exception ex)
+ {
+ throw new EncryptionException($"Encryption failed: {ex.Message}", ex);
+ }
+ }
+
+ // 新增:解密方法(对应 Python 的 decrypt)
+ public ToolFile Decrypt(string key, string algorithm = "AES")
+ {
+ if (!Exists() || !IsFile())
+ throw new FileNotFoundException($"File not found: {GetFullPath()}");
+
+ try
+ {
+ byte[] encryptedData = LoadAsBinary();
+ byte[] decryptedData;
+
+ if (algorithm.ToUpper() == "AES")
+ {
+ using (var aes = Aes.Create())
+ {
+ var keyBytes = Encoding.UTF8.GetBytes(key.PadRight(32).Substring(0, 32));
+ aes.Key = keyBytes;
+
+ using (var ms = new MemoryStream(encryptedData))
+ {
+ byte[] iv = new byte[16];
+ ms.Read(iv, 0, 16);
+ aes.IV = iv;
+
+ using (var decryptor = aes.CreateDecryptor())
+ using (var resultMs = new MemoryStream())
+ {
+ using (var cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
+ {
+ cs.CopyTo(resultMs);
+ }
+ decryptedData = resultMs.ToArray();
+ }
+ }
+ }
+ }
+ else
+ {
+ throw new EncryptionException($"Unsupported encryption algorithm: {algorithm}");
+ }
+
+ SaveAsBinary(decryptedData);
+ return this;
+ }
+ catch (Exception ex)
+ {
+ throw new EncryptionException($"Decryption failed: {ex.Message}", ex);
+ }
+ }
+
+ #endregion
+
+ #region Hash
+
+ // 新增:计算哈希值(对应 Python 的 calculate_hash)
+ public string CalculateHash(string algorithm = "MD5", int chunkSize = 8192)
+ {
+ if (!Exists() || !IsFile())
+ throw new FileNotFoundException($"File not found: {GetFullPath()}");
+
+ try
+ {
+ using (var hashAlgorithm = GetHashAlgorithm(algorithm))
+ using (var stream = File.OpenRead(FullPath))
+ {
+ byte[] hash = hashAlgorithm.ComputeHash(stream);
+ return BitConverter.ToString(hash).Replace("-", "").ToLower();
+ }
+ }
+ catch (Exception ex)
+ {
+ throw new HashException($"Hash calculation failed: {ex.Message}", ex);
+ }
+ }
+
+ private HashAlgorithm GetHashAlgorithm(string algorithm)
+ {
+ return algorithm.ToUpper() switch
+ {
+ "MD5" => MD5.Create(),
+ "SHA1" => SHA1.Create(),
+ "SHA256" => SHA256.Create(),
+ "SHA512" => SHA512.Create(),
+ _ => throw new HashException($"Unsupported hash algorithm: {algorithm}")
+ };
+ }
+
+ // 新增:验证哈希值(对应 Python 的 verify_hash)
+ public bool VerifyHash(string expectedHash, string algorithm = "MD5")
+ {
+ string actualHash = CalculateHash(algorithm);
+ return string.Equals(actualHash, expectedHash, StringComparison.OrdinalIgnoreCase);
+ }
+
+ // 新增:保存哈希值(对应 Python 的 save_hash)
+ public ToolFile SaveHash(string algorithm = "MD5", string outputPath = null)
+ {
+ string hash = CalculateHash(algorithm);
+
+ if (outputPath == null)
+ {
+ outputPath = GetFullPath() + "." + algorithm.ToLower();
+ }
+
+ var hashFile = new ToolFile(outputPath);
+ hashFile.SaveAsText(hash);
+
+ return hashFile;
+ }
+
+ #endregion
+
+ #region File Monitoring
+
+ // 新增:文件监控(简化实现,对应 Python 的 start_monitoring)
+ public void StartMonitoring(Action callback, bool recursive = false,
+ List ignorePatterns = null, bool ignoreDirectories = false,
+ bool caseSensitive = true, bool isLog = true)
+ {
+ if (!IsDir())
+ throw new InvalidOperationException("Monitoring is only supported for directories");
+
+ // 注意:这是一个简化实现,实际的文件监控需要更复杂的实现
+ // 可以使用 FileSystemWatcher 来实现完整功能
+ var watcher = new FileSystemWatcher(FullPath)
+ {
+ IncludeSubdirectories = recursive,
+ EnableRaisingEvents = true
+ };
+
+ watcher.Created += (sender, e) => callback("created", e.FullPath);
+ watcher.Modified += (sender, e) => callback("modified", e.FullPath);
+ watcher.Deleted += (sender, e) => callback("deleted", e.FullPath);
+ watcher.Renamed += (sender, e) => callback("moved", e.FullPath);
+ }
+
+ #endregion
+
+ #region Backup
+
+ // 新增:创建备份(对应 Python 的 create_backup)
+ public ToolFile CreateBackup(string backupDir = null, int maxBackups = 5,
+ string backupFormat = "zip", bool includeMetadata = true)
+ {
+ if (!Exists())
+ throw new FileNotFoundException($"File not found: {GetFullPath()}");
+
+ if (backupDir == null)
+ {
+ backupDir = Path.Combine(GetDir(), "backups");
+ }
+
+ var backupDirectory = new ToolFile(backupDir);
+ if (!backupDirectory.Exists())
+ {
+ backupDirectory.Create();
+ }
+
+ string timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
+ string backupFileName = $"{GetFilename()}_{timestamp}.{backupFormat}";
+ string backupPath = Path.Combine(backupDir, backupFileName);
+
+ try
+ {
+ if (backupFormat.ToLower() == "zip")
+ {
+ Compress(backupPath, "zip");
+ }
+ else
+ {
+ Copy(backupPath);
+ }
+
+ // 清理旧备份
+ CleanOldBackups(backupDir, maxBackups, backupFormat);
+
+ return new ToolFile(backupPath);
+ }
+ catch (Exception ex)
+ {
+ throw new FileOperationException($"Backup creation failed: {ex.Message}", ex);
+ }
+ }
+
+ private void CleanOldBackups(string backupDir, int maxBackups, string format)
+ {
+ var backupFiles = Directory.GetFiles(backupDir, $"*.{format}")
+ .Select(f => new FileInfo(f))
+ .OrderByDescending(f => f.CreationTime)
+ .Skip(maxBackups);
+
+ foreach (var file in backupFiles)
+ {
+ file.Delete();
+ }
+ }
+
+ // 新增:恢复备份(对应 Python 的 restore_backup)
+ public ToolFile RestoreBackup(string backupFile, string restorePath = null, bool verifyHash = true)
+ {
+ var backupToolFile = new ToolFile(backupFile);
+ if (!backupToolFile.Exists())
+ throw new FileNotFoundException($"Backup file not found: {backupFile}");
+
+ if (restorePath == null)
+ {
+ restorePath = GetFullPath();
+ }
+
+ try
+ {
+ if (backupToolFile.GetExtension().ToLower() == "zip")
+ {
+ backupToolFile.Decompress(restorePath);
+ }
+ else
+ {
+ backupToolFile.Copy(restorePath);
+ }
+
+ return new ToolFile(restorePath);
+ }
+ catch (Exception ex)
+ {
+ throw new FileOperationException($"Backup restoration failed: {ex.Message}", ex);
+ }
+ }
+
+ // 新增:列出备份(对应 Python 的 list_backups)
+ public List ListBackups(string backupDir = null)
+ {
+ if (backupDir == null)
+ {
+ backupDir = Path.Combine(GetDir(), "backups");
+ }
+
+ if (!Directory.Exists(backupDir))
+ return new List();
+
+ return Directory.GetFiles(backupDir)
+ .Where(f => Path.GetFileName(f).StartsWith(GetFilename()))
+ .Select(f => new ToolFile(f))
+ .OrderByDescending(f => f.GetTimestamp())
+ .ToList();
+ }
+
+ #endregion
+
+ #region Permissions
+
+ // 新增:获取权限(对应 Python 的 get_permissions)
+ public Dictionary GetPermissions()
+ {
+ if (!Exists())
+ throw new FileNotFoundException($"File not found: {GetFullPath()}");
+
+ var permissions = new Dictionary();
+
+ try
+ {
+ var fileInfo = new FileInfo(FullPath);
+ var attributes = fileInfo.Attributes;
+
+ permissions["read"] = true; // 如果能获取到文件信息,说明可读
+ permissions["write"] = !attributes.HasFlag(FileAttributes.ReadOnly);
+ permissions["execute"] = false; // Windows 文件没有执行权限概念
+ permissions["hidden"] = attributes.HasFlag(FileAttributes.Hidden);
+ }
+ catch (Exception)
+ {
+ permissions["read"] = false;
+ permissions["write"] = false;
+ permissions["execute"] = false;
+ permissions["hidden"] = false;
+ }
+
+ return permissions;
+ }
+
+ // 新增:设置权限(对应 Python 的 set_permissions)
+ public ToolFile SetPermissions(bool? read = null, bool? write = null,
+ bool? execute = null, bool? hidden = null, bool recursive = false)
+ {
+ if (!Exists())
+ throw new FileNotFoundException($"File not found: {GetFullPath()}");
+
+ try
+ {
+ var fileInfo = new FileInfo(FullPath);
+ var attributes = fileInfo.Attributes;
+
+ if (write.HasValue)
+ {
+ if (write.Value)
+ attributes &= ~FileAttributes.ReadOnly;
+ else
+ attributes |= FileAttributes.ReadOnly;
+ }
+
+ if (hidden.HasValue)
+ {
+ if (hidden.Value)
+ attributes |= FileAttributes.Hidden;
+ else
+ attributes &= ~FileAttributes.Hidden;
+ }
+
+ fileInfo.Attributes = attributes;
+
+ if (recursive && IsDir())
+ {
+ foreach (var child in DirToolFileIter())
+ {
+ child.SetPermissions(read, write, execute, hidden, true);
+ }
+ }
+
+ return this;
+ }
+ catch (Exception ex)
+ {
+ throw new FileOperationException($"Permission setting failed: {ex.Message}", ex);
+ }
+ }
+
+ // 新增:权限检查方法(对应 Python 的 is_readable, is_writable 等)
+ public bool IsReadable()
+ {
+ try
+ {
+ var permissions = GetPermissions();
+ return permissions["read"];
+ }
+ catch
+ {
+ return false;
+ }
+ }
+
+ public bool IsWritable()
+ {
+ try
+ {
+ var permissions = GetPermissions();
+ return permissions["write"];
+ }
+ catch
+ {
+ return false;
+ }
+ }
+
+ public bool IsExecutable()
+ {
+ try
+ {
+ var permissions = GetPermissions();
+ return permissions["execute"];
+ }
+ catch
+ {
+ return false;
+ }
+ }
+
+ public bool IsHidden()
+ {
+ try
+ {
+ var permissions = GetPermissions();
+ return permissions["hidden"];
+ }
+ catch
+ {
+ return false;
+ }
+ }
+
+ #endregion
+
+ #region Utility Methods
+
+ public ToolFile MakeFileInside(string source, bool isDeleteSource = false)
+ {
+ if (IsDir() == false)
+ throw new InvalidOperationException();
+ var sourceFile = new ToolFile(source);
+ return MakeFileInside(sourceFile, isDeleteSource);
+ }
public static string[] SelectMultipleFiles(string filter = "所有文件|*.*", string title = "选择文件")
{
- if (PlatformIndicator.IsPlatformWindows)
- return WindowsKit.SelectMultipleFiles(filter, title);
- throw new NotImplementedException();
+ using var dialog = new OpenFileDialog
+ {
+ Filter = filter,
+ Title = title,
+ Multiselect = true
+ };
+ return dialog.ShowDialog() == DialogResult.OK ? dialog.FileNames : new string[0];
}
-
public static string SelectFile(string filter = "所有文件|*.*", string title = "选择文件")
{
- if (PlatformIndicator.IsPlatformWindows)
+ using var dialog = new OpenFileDialog
{
- var results = WindowsKit.SelectMultipleFiles(filter, title);
- if (results != null && results.Length > 0)
- return results[0];
- }
- throw new NotImplementedException();
+ Filter = filter,
+ Title = title
+ };
+ return dialog.ShowDialog() == DialogResult.OK ? dialog.FileName : null;
}
-
public static string SaveFile(string filter = "所有文件|*.*", string title = "保存文件")
{
- if (PlatformIndicator.IsPlatformWindows)
- return WindowsKit.SaveFile(filter, title);
- throw new NotImplementedException();
+ using var dialog = new SaveFileDialog
+ {
+ Filter = filter,
+ Title = title
+ };
+ return dialog.ShowDialog() == DialogResult.OK ? dialog.FileName : null;
}
-
public static string SelectFolder(string description = "请选择文件夹")
{
- if (PlatformIndicator.IsPlatformWindows)
- return WindowsKit.SelectFolder(description);
- throw new NotImplementedException();
+ using var dialog = new FolderBrowserDialog
+ {
+ Description = description
+ };
+ return dialog.ShowDialog() == DialogResult.OK ? dialog.SelectedPath : null;
}
-
public DateTime GetTimestamp()
{
- return File.GetLastWriteTime(FullPath).ToUniversalTime();
+ return (OriginInfo as FileInfo)?.LastWriteTime ?? DateTime.MinValue;
}
-
public static string BrowseFile(params string[] extensions)
{
- string filter = "";
- foreach (var ext in extensions)
- {
- filter += "*." + ext + ";";
- }
- string result = SelectFile("所有文件|" + filter);
- return result;
+ string filter = string.Join("|", extensions.Select(ext => $"{ext.ToUpper()} 文件|*.{ext}"));
+ return SelectFile(filter);
}
public static ToolFile BrowseToolFile(params string[] extensions)
{
- return new ToolFile(BrowseFile(extensions));
+ string path = BrowseFile(extensions);
+ return path != null ? new ToolFile(path) : null;
}
+
+ #endregion
}
}
diff --git a/Convention/[Runtime]/Math.cs b/Convention/[Runtime]/Math.cs
deleted file mode 100644
index fb57512..0000000
--- a/Convention/[Runtime]/Math.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-using System;
-
-namespace Convention
-{
-
-}
diff --git a/[Test]/FileTest.cs b/[Test]/FileTest.cs
new file mode 100644
index 0000000..f03b2ee
--- /dev/null
+++ b/[Test]/FileTest.cs
@@ -0,0 +1,214 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Convention;
+
+namespace Convention.Test
+{
+ public class FileTest
+ {
+ public static void RunTests()
+ {
+ Console.WriteLine("=== ToolFile 功能测试 ===");
+
+ // 测试基本文件操作
+ TestBasicOperations();
+
+ // 测试文件加载和保存
+ TestLoadAndSave();
+
+ // 测试压缩和解压
+ TestCompression();
+
+ // 测试加密和解密
+ TestEncryption();
+
+ // 测试哈希计算
+ TestHash();
+
+ // 测试备份功能
+ TestBackup();
+
+ // 测试权限管理
+ TestPermissions();
+
+ Console.WriteLine("=== 所有测试完成 ===");
+ }
+
+ private static void TestBasicOperations()
+ {
+ Console.WriteLine("\n--- 基本文件操作测试 ---");
+
+ // 创建测试文件
+ var testFile = new ToolFile("test_file.txt");
+ testFile.SaveAsText("这是一个测试文件的内容");
+
+ Console.WriteLine($"文件存在: {testFile.Exists()}");
+ Console.WriteLine($"文件大小: {testFile.GetSize()} 字节");
+ Console.WriteLine($"文件名: {testFile.GetFilename()}");
+ Console.WriteLine($"文件扩展名: {testFile.GetExtension()}");
+ Console.WriteLine($"文件目录: {testFile.GetDir()}");
+ Console.WriteLine($"文件时间戳: {testFile.GetTimestamp()}");
+
+ // 清理
+ testFile.Remove();
+ }
+
+ private static void TestLoadAndSave()
+ {
+ Console.WriteLine("\n--- 文件加载和保存测试 ---");
+
+ // 测试 JSON 保存和加载
+ var jsonFile = new ToolFile("test_data.json");
+ var testData = new { name = "测试", value = 123, items = new[] { "item1", "item2" } };
+ jsonFile.SaveAsRawJson(testData);
+
+ var loadedData = jsonFile.LoadAsRawJson();
+ Console.WriteLine($"JSON 数据加载成功: {loadedData != null}");
+
+ // 测试 CSV 保存和加载
+ var csvFile = new ToolFile("test_data.csv");
+ var csvData = new List
+ {
+ new[] { "姓名", "年龄", "城市" },
+ new[] { "张三", "25", "北京" },
+ new[] { "李四", "30", "上海" }
+ };
+ csvFile.SaveAsCsv(csvData);
+
+ var loadedCsv = csvFile.LoadAsCsv();
+ Console.WriteLine($"CSV 数据加载成功: {loadedCsv.Count} 行");
+
+ // 清理
+ jsonFile.Remove();
+ csvFile.Remove();
+ }
+
+ private static void TestCompression()
+ {
+ Console.WriteLine("\n--- 压缩和解压测试 ---");
+
+ // 创建测试文件
+ var testFile = new ToolFile("test_compress.txt");
+ testFile.SaveAsText("这是一个用于压缩测试的文件内容。".PadRight(1000, 'x'));
+
+ // 压缩文件
+ var compressedFile = testFile.Compress();
+ Console.WriteLine($"压缩成功: {compressedFile.Exists()}");
+ Console.WriteLine($"压缩后大小: {compressedFile.GetSize()} 字节");
+
+ // 解压文件
+ var decompressedDir = compressedFile.Decompress();
+ Console.WriteLine($"解压成功: {decompressedDir.Exists()}");
+
+ // 清理
+ testFile.Remove();
+ compressedFile.Remove();
+ if (decompressedDir.Exists())
+ decompressedDir.Remove();
+ }
+
+ private static void TestEncryption()
+ {
+ Console.WriteLine("\n--- 加密和解密测试 ---");
+
+ // 创建测试文件
+ var testFile = new ToolFile("test_encrypt.txt");
+ testFile.SaveAsText("这是一个用于加密测试的敏感数据");
+
+ // 加密文件
+ testFile.Encrypt("mysecretkey123");
+ Console.WriteLine($"加密成功: {testFile.Exists()}");
+
+ // 解密文件
+ testFile.Decrypt("mysecretkey123");
+ var decryptedContent = testFile.LoadAsText();
+ Console.WriteLine($"解密成功: {decryptedContent.Contains("敏感数据")}");
+
+ // 清理
+ testFile.Remove();
+ }
+
+ private static void TestHash()
+ {
+ Console.WriteLine("\n--- 哈希计算测试 ---");
+
+ // 创建测试文件
+ var testFile = new ToolFile("test_hash.txt");
+ testFile.SaveAsText("这是一个用于哈希测试的文件内容");
+
+ // 计算不同算法的哈希值
+ var md5Hash = testFile.CalculateHash("MD5");
+ var sha256Hash = testFile.CalculateHash("SHA256");
+
+ Console.WriteLine($"MD5 哈希: {md5Hash}");
+ Console.WriteLine($"SHA256 哈希: {sha256Hash}");
+
+ // 验证哈希值
+ var isValid = testFile.VerifyHash(md5Hash, "MD5");
+ Console.WriteLine($"哈希验证: {isValid}");
+
+ // 保存哈希值到文件
+ var hashFile = testFile.SaveHash("MD5");
+ Console.WriteLine($"哈希文件保存: {hashFile.Exists()}");
+
+ // 清理
+ testFile.Remove();
+ hashFile.Remove();
+ }
+
+ private static void TestBackup()
+ {
+ Console.WriteLine("\n--- 备份功能测试 ---");
+
+ // 创建测试文件
+ var testFile = new ToolFile("test_backup.txt");
+ testFile.SaveAsText("这是一个用于备份测试的文件内容");
+
+ // 创建备份
+ var backupFile = testFile.CreateBackup();
+ Console.WriteLine($"备份创建成功: {backupFile.Exists()}");
+
+ // 列出备份
+ var backups = testFile.ListBackups();
+ Console.WriteLine($"备份数量: {backups.Count}");
+
+ // 恢复备份
+ var restoredFile = testFile.RestoreBackup(backupFile.GetFullPath(), "restored_file.txt");
+ Console.WriteLine($"备份恢复成功: {restoredFile.Exists()}");
+
+ // 清理
+ testFile.Remove();
+ backupFile.Remove();
+ restoredFile.Remove();
+ }
+
+ private static void TestPermissions()
+ {
+ Console.WriteLine("\n--- 权限管理测试 ---");
+
+ // 创建测试文件
+ var testFile = new ToolFile("test_permissions.txt");
+ testFile.SaveAsText("这是一个用于权限测试的文件内容");
+
+ // 获取权限
+ var permissions = testFile.GetPermissions();
+ Console.WriteLine($"读取权限: {permissions["read"]}");
+ Console.WriteLine($"写入权限: {permissions["write"]}");
+ Console.WriteLine($"隐藏属性: {permissions["hidden"]}");
+
+ // 设置权限
+ testFile.SetPermissions(hidden: true);
+ var newPermissions = testFile.GetPermissions();
+ Console.WriteLine($"设置隐藏后: {newPermissions["hidden"]}");
+
+ // 检查权限
+ Console.WriteLine($"可读: {testFile.IsReadable()}");
+ Console.WriteLine($"可写: {testFile.IsWritable()}");
+ Console.WriteLine($"隐藏: {testFile.IsHidden()}");
+
+ // 清理
+ testFile.Remove();
+ }
+ }
+}
\ No newline at end of file
diff --git a/[Test]/Program.cs b/[Test]/Program.cs
index 3e72f3a..c3e1d5d 100644
--- a/[Test]/Program.cs
+++ b/[Test]/Program.cs
@@ -5,20 +5,19 @@ using System.Threading;
using Convention;
using Convention.EasySave;
using Convention.Symbolization;
+using Convention.Test;
public class Program
{
static void Main(string[] args)
{
- var runner = new SymbolizationRunner();
- try
- {
- runner.Compile("example_script.txt");
- Console.WriteLine("Script compiled successfully.");
- }
- catch (FileNotFoundException ex)
- {
- Console.WriteLine($"Error: {ex.Message}");
- }
+ Console.WriteLine("Convention-CSharp 测试程序");
+ Console.WriteLine("==========================");
+
+ // 运行文件功能测试
+ FileTest.RunTests();
+
+ Console.WriteLine("\n按任意键退出...");
+ Console.ReadKey();
}
}
\ No newline at end of file