Files
16-Xikai-MesProjectNew/Interface_WebAPI/SlMesDbIterface/WebAPI/Controller/IFileController.cs
2026-05-29 09:34:04 +08:00

278 lines
10 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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}" });
}
}
}
}