198 lines
6.6 KiB
C#
198 lines
6.6 KiB
C#
using System;
|
||
using System.IO;
|
||
using System.Security.Cryptography;
|
||
using System.Text;
|
||
using System.Threading.Tasks;
|
||
|
||
namespace Luban.Common.Utils
|
||
{
|
||
public static class FileUtil
|
||
{
|
||
private static readonly NLog.Logger s_logger = NLog.LogManager.GetCurrentClassLogger();
|
||
|
||
public static string GetApplicationDirectory()
|
||
{
|
||
return Path.GetDirectoryName(System.Reflection.Assembly.GetCallingAssembly().Location);
|
||
}
|
||
|
||
public static string GetPathRelateApplicationDirectory(string relatePath)
|
||
{
|
||
return Path.Combine(GetApplicationDirectory(), relatePath);
|
||
}
|
||
|
||
public static string GetFileName(string path)
|
||
{
|
||
int index = path.Replace('\\', '/').LastIndexOf('/');
|
||
return index >= 0 ? path[(index + 1)..] : path;
|
||
}
|
||
|
||
public static string GetParent(string path)
|
||
{
|
||
int index = path.Replace('\\', '/').LastIndexOf('/');
|
||
return index >= 0 ? path[..index] : ".";
|
||
}
|
||
|
||
public static string GetFileNameWithoutExt(string file)
|
||
{
|
||
int index = file.LastIndexOf('.');
|
||
return index >= 0 ? file.Substring(0, index) : file;
|
||
}
|
||
|
||
public static string GetFileExtension(string file)
|
||
{
|
||
int index = file.LastIndexOf('.');
|
||
return index >= 0 ? file.Substring(index + 1) : "";
|
||
}
|
||
|
||
public static string GetPathRelateRootFile(string rootFile, string file)
|
||
{
|
||
return Combine(GetParent(rootFile), file);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 忽略以 文件名以 '.' '_' '~' 开头的文件
|
||
/// </summary>
|
||
/// <param name="file"></param>
|
||
/// <returns></returns>
|
||
public static bool IsValidInputFile(string file)
|
||
{
|
||
if (!File.Exists(file))
|
||
{
|
||
return false;
|
||
}
|
||
var f = new FileInfo(file);
|
||
string fname = f.Name;
|
||
return !fname.StartsWith('.') && !fname.StartsWith('_') && !fname.StartsWith('~');
|
||
}
|
||
|
||
public static string CalcMD5(byte[] srcBytes)
|
||
{
|
||
using MD5 md5 = MD5.Create();
|
||
var md5Bytes = md5.ComputeHash(srcBytes);
|
||
var s = new StringBuilder(md5Bytes.Length * 2);
|
||
foreach (var b in md5Bytes)
|
||
{
|
||
s.Append(b.ToString("X"));
|
||
}
|
||
return s.ToString();
|
||
}
|
||
|
||
public static string Standardize(string path)
|
||
{
|
||
return path.Replace('\\', '/');
|
||
}
|
||
|
||
public static string Combine(string parent, string sub)
|
||
{
|
||
return Standardize(Path.Combine(parent, sub));
|
||
}
|
||
|
||
public static bool IsExcelFile(string fullName)
|
||
{
|
||
return fullName.EndsWith(".csv", StringComparison.Ordinal)
|
||
|| fullName.EndsWith(".xls", StringComparison.Ordinal)
|
||
|| fullName.EndsWith(".xlsx", StringComparison.Ordinal);
|
||
}
|
||
|
||
public static (string, string) SplitFileAndSheetName(string url)
|
||
{
|
||
int sheetSepIndex = url.IndexOf('@');
|
||
if (sheetSepIndex < 0)
|
||
{
|
||
return (url, null);
|
||
}
|
||
else
|
||
{
|
||
int lastPathSep = url.LastIndexOf('/', sheetSepIndex);
|
||
if (lastPathSep >= 0)
|
||
{
|
||
return (url[0..(lastPathSep + 1)] + url[(sheetSepIndex + 1)..], url[(lastPathSep + 1)..sheetSepIndex]);
|
||
}
|
||
else
|
||
{
|
||
return (url[(sheetSepIndex + 1)..], url[(lastPathSep + 1)..sheetSepIndex]);
|
||
}
|
||
}
|
||
}
|
||
|
||
public static async Task SaveFileAsync(string relateDir, string filePath, byte[] content)
|
||
{
|
||
// 调用此接口时,已保证 文件必然是改变的,不用再检查对比文件
|
||
var outputPath = Standardize(relateDir != null ? System.IO.Path.Combine(relateDir, filePath) : filePath);
|
||
Directory.GetParent(outputPath).Create();
|
||
if (File.Exists(outputPath))
|
||
{
|
||
s_logger.Info("[override] {file}", outputPath);
|
||
if (File.GetAttributes(outputPath).HasFlag(FileAttributes.ReadOnly))
|
||
{
|
||
File.SetAttributes(outputPath, FileAttributes.Normal);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
s_logger.Info("[new] {file}", outputPath);
|
||
}
|
||
|
||
await WriteAllBytesAsync(outputPath, content);
|
||
}
|
||
|
||
public static async Task<byte[]> ReadAllBytesAsync(string file)
|
||
{
|
||
// File.ReadAllBytesAsync 无法读取被打开的excel文件,只好重新实现了一个
|
||
using var fs = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||
long count = fs.Length;
|
||
var bytes = new byte[count];
|
||
int writeIndex = 0;
|
||
while (writeIndex < count)
|
||
{
|
||
int n = await fs.ReadAsync(bytes, writeIndex, (int)count - writeIndex, default);
|
||
writeIndex += n;
|
||
}
|
||
return bytes;
|
||
}
|
||
|
||
public static byte[] ReadAllBytes(string file)
|
||
{
|
||
// File.ReadAllBytesAsync 无法读取被打开的excel文件,只好重新实现了一个
|
||
using var fs = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||
long count = fs.Length;
|
||
var bytes = new byte[count];
|
||
int writeIndex = 0;
|
||
while (writeIndex < count)
|
||
{
|
||
int n = fs.Read(bytes, writeIndex, (int)count - writeIndex);
|
||
writeIndex += n;
|
||
}
|
||
return bytes;
|
||
}
|
||
|
||
public static async Task WriteAllBytesAsync(string file, byte[] bytes)
|
||
{
|
||
using var fs = new FileStream(file, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite);
|
||
long count = bytes.LongLength;
|
||
fs.SetLength(count);
|
||
fs.Seek(0, SeekOrigin.Begin);
|
||
await fs.WriteAsync(bytes);
|
||
}
|
||
|
||
public static void DeleteDirectoryRecursive(string rootDir)
|
||
{
|
||
string[] files = Directory.GetFiles(rootDir);
|
||
string[] dirs = Directory.GetDirectories(rootDir);
|
||
|
||
foreach (string file in files)
|
||
{
|
||
File.SetAttributes(file, FileAttributes.Normal);
|
||
File.Delete(file);
|
||
}
|
||
|
||
foreach (string dir in dirs)
|
||
{
|
||
DeleteDirectoryRecursive(dir);
|
||
}
|
||
|
||
Directory.Delete(rootDir, false);
|
||
}
|
||
}
|
||
}
|