chore: initial commit

This commit is contained in:
XingCheng3
2026-05-29 09:34:04 +08:00
commit 78ae9dcd2e
683 changed files with 68110 additions and 0 deletions

View File

@@ -0,0 +1,277 @@
using System.Net.Http;
using System.Net;
using System.Web.Http;
using Newtonsoft.Json.Linq;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System;
/////http://127.0.0.1:9981/api/file/browse
/// <summary>
///
/// </summary>
namespace WebApi
{
/// <summary>
///
/// </summary>
[RoutePrefix("api/file")]
public class IFileController : ApiController
{
// 基础路径配置
private readonly string _basePath = @"D:\CameraImg";
/// <summary>
/// 请求DTO
/// </summary>
public class FileRequestDto
{
public string RelativePath { get; set; } = "";
}
/// <summary>
/// 浏览文件或文件夹,前端传相对路径,返回文件夹内容或文件流(图片等可预览)
/// </summary>
[HttpPost]
[Route("browse")]
public IHttpActionResult BrowsePath([FromBody] FileRequestDto request)
{
try
{
if (request == null)
request = new FileRequestDto();
if (string.IsNullOrEmpty(request.RelativePath) || request.RelativePath == "/")
{
request.RelativePath = "";
}
string fullPath = Path.Combine(_basePath, request.RelativePath.Replace('/', Path.DirectorySeparatorChar));
if (!IsPathSafe(fullPath))
{
return Ok(new { success = false, message = "无效的路径" });
}
if (!Directory.Exists(fullPath) && !System.IO.File.Exists(fullPath))
{
return Ok(new { success = false, message = "路径不存在" });
}
if (System.IO.File.Exists(fullPath))
{
return GetFilePreview(fullPath, request.RelativePath);
}
if (Directory.Exists(fullPath))
{
return GetDirectoryContents(fullPath, request.RelativePath);
}
return Ok(new { success = false, message = "路径不存在" });
}
catch (Exception ex)
{
return Ok(new { success = false, message = $"服务器错误: {ex.Message}" });
}
}
/// <summary>
/// 获取文件预览数据(图片/文本base64前端可直接预览
/// </summary>
private IHttpActionResult GetFilePreview(string fullPath, string relativePath)
{
try
{
var fileInfo = new FileInfo(fullPath);
var extension = fileInfo.Extension.ToLowerInvariant();
var previewable = IsPreviewableFile(extension);
var contentType = GetContentType(fileInfo.Name);
bool tooLarge = fileInfo.Length > 10 * 1024 * 1024; // 10MB限制
string base64String = null;
string dataUrl = null;
bool canPreview = previewable && !tooLarge;
if (canPreview)
{
var fileBytes = System.IO.File.ReadAllBytes(fullPath);
base64String = Convert.ToBase64String(fileBytes);
dataUrl = $"data:{contentType};base64,{base64String}";
}
var result = new
{
success = true,
type = "file",
path = relativePath,
name = fileInfo.Name,
size = fileInfo.Length,
extension = fileInfo.Extension,
contentType = contentType,
isPreviewable = canPreview,
base64Data = base64String,
dataUrl = dataUrl,
created = fileInfo.CreationTime,
modified = fileInfo.LastWriteTime,
message = tooLarge ? "文件过大,无法预览,可下载" : null
};
return Ok(result);
}
catch (Exception ex)
{
return Ok(new { success = false, message = $"获取文件预览失败: {ex.Message}" });
}
}
/// <summary>
/// 判断文件是否可预览
/// </summary>
private bool IsPreviewableFile(string extension)
{
var previewableExtensions = new[]
{
".bmp", ".jpg", ".jpeg", ".png", ".gif", ".tiff", ".tif", ".webp",
".txt", ".json", ".xml", ".csv", ".log", ".md"
};
return previewableExtensions.Contains(extension);
}
/// <summary>
/// 安全检查:确保路径在基础目录内,防止路径遍历攻击
/// </summary>
private bool IsPathSafe(string fullPath)
{
try
{
var basePath = Path.GetFullPath(_basePath);
var requestedPath = Path.GetFullPath(fullPath);
return requestedPath.StartsWith(basePath, StringComparison.OrdinalIgnoreCase);
}
catch
{
return false;
}
}
/// <summary>
/// 根据文件扩展名获取MIME类型兼容C# 7.3
/// </summary>
private string GetContentType(string fileName)
{
var extension = Path.GetExtension(fileName).ToLowerInvariant();
if (extension == ".bmp") return "image/bmp";
if (extension == ".jpg" || extension == ".jpeg") return "image/jpeg";
if (extension == ".png") return "image/png";
if (extension == ".gif") return "image/gif";
if (extension == ".tiff" || extension == ".tif") return "image/tiff";
if (extension == ".webp") return "image/webp";
if (extension == ".pdf") return "application/pdf";
if (extension == ".txt") return "text/plain";
if (extension == ".json") return "application/json";
if (extension == ".xml") return "application/xml";
if (extension == ".csv") return "text/csv";
if (extension == ".md") return "text/markdown";
if (extension == ".log") return "text/plain";
if (extension == ".zip") return "application/zip";
if (extension == ".rar") return "application/x-rar-compressed";
return "application/octet-stream";
}
private IHttpActionResult GetDirectoryContents(string fullPath, string relativePath)
{
try
{
var items = new List<object>();
var directories = Directory.GetDirectories(fullPath);
foreach (var dir in directories)
{
var dirInfo = new DirectoryInfo(dir);
var subPath = string.IsNullOrEmpty(relativePath)
? dirInfo.Name
: $"{relativePath}/{dirInfo.Name}";
items.Add(new
{
name = dirInfo.Name,
type = "directory",
path = subPath,
created = dirInfo.CreationTime,
modified = dirInfo.LastWriteTime,
isPreviewable = false
});
}
var files = Directory.GetFiles(fullPath);
foreach (var file in files)
{
var fileInfo = new FileInfo(file);
var filePath = string.IsNullOrEmpty(relativePath)
? fileInfo.Name
: $"{relativePath}/{fileInfo.Name}";
var extension = fileInfo.Extension.ToLowerInvariant();
items.Add(new
{
name = fileInfo.Name,
type = "file",
path = filePath,
size = fileInfo.Length,
extension = fileInfo.Extension,
created = fileInfo.CreationTime,
modified = fileInfo.LastWriteTime,
isPreviewable = IsPreviewableFile(extension),
contentType = GetContentType(fileInfo.Name)
});
}
var result = new
{
success = true,
type = "directory",
path = relativePath,
items = items.OrderBy(x => ((dynamic)x).type == "directory" ? 0 : 1)
.ThenBy(x => ((dynamic)x).name)
.ToList()
};
return Ok(result);
}
catch (Exception ex)
{
return Ok(new { success = false, message = $"读取目录失败: {ex.Message}" });
}
}
[HttpPost]
[Route("download")]
public IHttpActionResult DownloadFile([FromBody] FileRequestDto request)
{
try
{
if (request == null || string.IsNullOrEmpty(request.RelativePath))
return Ok(new { success = false, message = "文件路径不能为空" });
string fullPath = Path.Combine(_basePath, request.RelativePath.Replace('/', Path.DirectorySeparatorChar));
if (!IsPathSafe(fullPath) || !System.IO.File.Exists(fullPath))
return Ok(new { success = false, message = "文件不存在" });
var fileInfo = new FileInfo(fullPath);
var contentType = GetContentType(fileInfo.Name);
var response = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StreamContent(new FileStream(fullPath, FileMode.Open, FileAccess.Read, FileShare.Read))
};
response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(contentType);
response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment")
{
FileName = fileInfo.Name
};
return ResponseMessage(response);
}
catch (Exception ex)
{
return Ok(new { success = false, message = $"下载文件失败: {ex.Message}" });
}
}
}
}