找回密码
 立即注册
首页 业界区 业界 .NET4通过HTTP操作MINIO

.NET4通过HTTP操作MINIO

挚魉 2025-9-26 11:41:17
MINIO是提供.NET SDK的,但是这么老的版本没找到,于是使用http的方式直接调用,方便简单。
我这里需求不复杂,只需要上传下载删除即可,如果后续有需求再补充方法。
1.png

核心代码MinioHttpOperatorDemo如下:
  1. using System;
  2. using System.IO;
  3. using System.Net;
  4. using System.Text;
  5. using System.Collections.Specialized; // For NameValueCollection, though not directly used in this version, good to keep for potential expansion.
  6. using System.Security.Cryptography; // For HMACSHA256, SHA256Managed
  7. using System.Globalization; // For CultureInfo.InvariantCulture
  8. using System.Collections.Generic; // For SortedList
  9. using System.Linq; // For string.Join and other LINQ operations
  10. using System.Xml.Linq;
  11. namespace MinioHttpOperatorDemo
  12. {
  13.     /// <summary>
  14.     /// MinIO HTTP 操作类,适用于 .NET Framework 4.0 环境,不依赖 MinIO SDK。
  15.     /// 使用 HttpWebRequest 和 HttpWebResponse 进行文件上传、下载和删除操作。
  16.     /// 已加入 AWS Signature Version 4 认证的简化实现,并进行了进一步的完善。
  17.     /// </summary>
  18.     public class MinioHttpOperator
  19.     {
  20.         private readonly string _minioEndpoint; // MinIO 服务器的端点地址,例如: http://localhost:9000
  21.         private readonly string _accessKey;     // MinIO Access Key
  22.         private readonly string _secretKey;     // MinIO Secret Key
  23.         private readonly string _region;        // S3 兼容 API 需要的区域,MinIO 通常用 "us-east-1"
  24.         private readonly string _service;       // S3 兼容 API 需要的服务名称,通常是 "s3"
  25.         /// <summary>
  26.         /// 构造函数,初始化 MinIO 操作器。
  27.         /// </summary>
  28.         /// <param name="minioEndpoint">MinIO 服务器的 URL,例如 "http://localhost:9000"</param>
  29.         /// <param name="accessKey">Access Key,用于认证。</param>
  30.         /// <param name="secretKey">Secret Key,用于认证。</param>
  31.         /// <param name="region">S3 兼容 API 需要的区域,默认为 "us-east-1"。</param>
  32.         /// <param name="service">S3 兼容 API 需要的服务名称,默认为 "s3"。</param>
  33.         public MinioHttpOperator(string minioEndpoint, string accessKey, string secretKey, string region = "cn-north-1", string service = "s3")
  34.         {
  35.             // 移除末尾的斜杠,确保 URL 格式正确
  36.             _minioEndpoint = minioEndpoint.TrimEnd('/');
  37.             _accessKey = accessKey;
  38.             _secretKey = secretKey;
  39.             _region = region;
  40.             _service = service;
  41.             if (string.IsNullOrEmpty(_accessKey) || string.IsNullOrEmpty(_secretKey))
  42.             {
  43.                 // 抛出异常而不是警告,因为没有凭据就无法认证
  44.                 throw new ArgumentNullException("AccessKey 和 SecretKey 不能为空,因为需要进行认证。");
  45.             }
  46.         }
  47.         /// <summary>
  48.         /// 上传文件到 MinIO。
  49.         /// </summary>
  50.         /// <param name="bucketName">目标桶的名称。</param>
  51.         /// <param name="objectName">在桶中保存的对象名称(包含路径,例如 "myfolder/myfile.txt")。</param>
  52.         /// <param name="filePath">本地待上传文件的完整路径。</param>
  53.         /// <param name="contentType">文件的 MIME 类型,例如 "application/octet-stream"、"image/jpeg"、"text/plain"。</param>
  54.         /// <returns>如果上传成功返回 true,否则返回 false。</returns>
  55.         public bool UploadFile(string bucketName, string objectName, string filePath, string contentType = "application/octet-stream")
  56.         {
  57.             try
  58.             {
  59.                 if (!File.Exists(filePath))
  60.                 {
  61.                     Console.WriteLine($"错误:文件未找到,路径:{filePath}");
  62.                     return false;
  63.                 }
  64.                 string url = $"{_minioEndpoint}/{bucketName}/{objectName}";
  65.                 HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
  66.                 request.Method = "PUT";
  67.                 request.ContentType = contentType;
  68.                 // 计算文件内容的 SHA256 哈希值
  69.                 string contentHash;
  70.                 using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
  71.                 {
  72.                     using (SHA256 sha256 = new SHA256Managed())
  73.                     {
  74.                         byte[] hashBytes = sha256.ComputeHash(fileStream);
  75.                         contentHash = BitConverter.ToString(hashBytes).Replace("-", "").ToLowerInvariant();
  76.                     }
  77.                     fileStream.Position = 0; // 重置流位置以便后续读取
  78.                     request.ContentLength = fileStream.Length; // 设置请求内容长度
  79.                     // 签名请求
  80.                     SignRequest(request, bucketName, objectName, contentHash);
  81.                     // 获取请求流并写入文件内容
  82.                     using (Stream requestStream = request.GetRequestStream())
  83.                     {
  84.                         byte[] buffer = new byte[4096]; // 4KB 缓冲区
  85.                         int bytesRead;
  86.                         while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) > 0)
  87.                         {
  88.                             requestStream.Write(buffer, 0, bytesRead);
  89.                         }
  90.                     }
  91.                 }
  92.                 using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
  93.                 {
  94.                     if (response.StatusCode == HttpStatusCode.OK)
  95.                     {
  96.                         Console.WriteLine($"成功上传文件 {objectName} 到桶 {bucketName}。");
  97.                         return true;
  98.                     }
  99.                     else
  100.                     {
  101.                         Console.WriteLine($"上传文件 {objectName} 失败。状态码:{response.StatusCode}");
  102.                         return false;
  103.                     }
  104.                 }
  105.             }
  106.             catch (WebException webEx)
  107.             {
  108.                 HandleWebException(webEx, "上传");
  109.                 return false;
  110.             }
  111.             catch (Exception ex)
  112.             {
  113.                 Console.WriteLine($"上传时发生未知错误:{ex.Message}");
  114.                 return false;
  115.             }
  116.         }
  117.         /// <summary>
  118.         /// 从 MinIO 下载文件。
  119.         /// </summary>
  120.         /// <param name="bucketName">源桶的名称。</param>
  121.         /// <param name="objectName">要下载的对象名称。</param>
  122.         /// <param name="savePath">本地保存文件的完整路径。</param>
  123.         /// <returns>如果下载成功返回 true,否则返回 false。</returns>
  124.         public bool DownloadFile(string bucketName, string objectName, string savePath)
  125.         {
  126.             try
  127.             {
  128.                 string url = $"{_minioEndpoint}/{bucketName}/{objectName}";
  129.                 HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
  130.                 request.Method = "GET";
  131.                 // 对于 GET 请求,payload hash 是固定的空字符串的 SHA256 哈希
  132.                 string contentHash = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; // SHA256("")
  133.                 SignRequest(request, bucketName, objectName, contentHash);
  134.                 using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
  135.                 {
  136.                     if (response.StatusCode == HttpStatusCode.OK)
  137.                     {
  138.                         using (Stream responseStream = response.GetResponseStream())
  139.                         using (FileStream fileStream = new FileStream(savePath, FileMode.Create, FileAccess.Write))
  140.                         {
  141.                             byte[] buffer = new byte[4096];
  142.                             int bytesRead;
  143.                             while ((bytesRead = responseStream.Read(buffer, 0, buffer.Length)) > 0)
  144.                             {
  145.                                 fileStream.Write(buffer, 0, bytesRead);
  146.                             }
  147.                         }
  148.                         Console.WriteLine($"成功下载文件 {objectName} 到 {savePath}。");
  149.                         return true;
  150.                     }
  151.                     else
  152.                     {
  153.                         Console.WriteLine($"下载文件 {objectName} 失败。状态码:{response.StatusCode}");
  154.                         return false;
  155.                     }
  156.                 }
  157.             }
  158.             catch (WebException webEx)
  159.             {
  160.                 HandleWebException(webEx, "下载");
  161.                 return false;
  162.             }
  163.             catch (Exception ex)
  164.             {
  165.                 Console.WriteLine($"下载时发生未知错误:{ex.Message}");
  166.                 return false;
  167.             }
  168.         }
  169.         /// <summary>
  170.         /// 从 MinIO 删除文件。
  171.         /// </summary>
  172.         /// <param name="bucketName">文件所在桶的名称。</param>
  173.         /// <param name="objectName">要删除的对象名称。</param>
  174.         /// <returns>如果删除成功返回 true,否则返回 false。</returns>
  175.         public bool DeleteFile(string bucketName, string objectName)
  176.         {
  177.             try
  178.             {
  179.                 string url = $"{_minioEndpoint}/{bucketName}/{objectName}";
  180.                 HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
  181.                 request.Method = "DELETE";
  182.                 // 对于 DELETE 请求,payload hash 是固定的空字符串的 SHA256 哈希
  183.                 string contentHash = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; // SHA256("")
  184.                 SignRequest(request, bucketName, objectName, contentHash);
  185.                 using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
  186.                 {
  187.                     // 成功的 DELETE 请求通常返回 204 No Content
  188.                     if (response.StatusCode == HttpStatusCode.NoContent)
  189.                     {
  190.                         Console.WriteLine($"成功删除文件 {objectName} 从桶 {bucketName}。");
  191.                         return true;
  192.                     }
  193.                     else
  194.                     {
  195.                         Console.WriteLine($"删除文件 {objectName} 失败。状态码:{response.StatusCode}");
  196.                         return false;
  197.                     }
  198.                 }
  199.             }
  200.             catch (WebException webEx)
  201.             {
  202.                 HandleWebException(webEx, "删除");
  203.                 return false;
  204.             }
  205.             catch (Exception ex)
  206.             {
  207.                 Console.WriteLine($"删除时发生未知错误:{ex.Message}");
  208.                 return false;
  209.             }
  210.         }
  211.         /// <summary>
  212.         /// 处理 Web 请求异常并输出详细信息。
  213.         /// </summary>
  214.         /// <param name="webEx">WebException 实例。</param>
  215.         /// <param name="operation">发生异常的操作名称(例如:"上传"、"下载")。</param>
  216.         private void HandleWebException(WebException webEx, string operation)
  217.         {
  218.             if (webEx.Response != null)
  219.             {
  220.                 using (StreamReader reader = new StreamReader(webEx.Response.GetResponseStream()))
  221.                 {
  222.                     string responseText = reader.ReadToEnd();
  223.                     Console.WriteLine($"{operation}时发生 Web 异常:{webEx.Message}。状态码:{(int)((HttpWebResponse)webEx.Response).StatusCode}。响应内容:{responseText}");
  224.                 }
  225.             }
  226.             else
  227.             {
  228.                 Console.WriteLine($"{operation}时发生 Web 异常:{webEx.Message}");
  229.             }
  230.         }
  231.         /// <summary>
  232.         /// 为 HttpWebRequest 签名 AWS Signature Version 4 认证头部。
  233.         /// 这是 AWS Signature Version 4 规范的简化实现,旨在与 MinIO 兼容。
  234.         /// </summary>
  235.         /// <param name="request">要签名的 HttpWebRequest 实例。</param>
  236.         /// <param name="bucketName">桶名称。</param>
  237.         /// <param name="objectName">对象名称。</param>
  238.         /// <param name="contentHash">请求体的 SHA256 哈希值。</param>
  239.         private void SignRequest(HttpWebRequest request, string bucketName, string objectName, string contentHash)
  240.         {
  241.             // --- 步骤 1: 创建 Canonical Request ---
  242.             // 1.1 HTTP 方法
  243.             string httpRequestMethod = request.Method;
  244.             // 1.2 Canonical URI
  245.             // 对象名必须进行 URI 编码,但斜杠 (/) 作为路径分隔符不能被编码。
  246.             // Uri.EscapeDataString 会编码 '/' 为 '%2F',需要将其替换回来。
  247.             // 确保 objectName 不以斜杠开头,因为 canonicalUri 会添加一个。
  248.             string cleanedObjectName = objectName.StartsWith("/") ? objectName.Substring(1) : objectName;
  249.             string encodedObjectName = Uri.EscapeDataString(cleanedObjectName).Replace("%2F", "/");
  250.             string canonicalUri = $"/{bucketName}/{encodedObjectName}";
  251.             // 1.3 Canonical Query String (本示例不处理查询参数,因此为空)
  252.             string canonicalQueryString = "";
  253.             // 1.4 Canonical Headers
  254.             // 头部名称必须小写,并按字典序排序。
  255.             // 头部值必须去除前导/尾随空格,多个空格替换为单个空格。
  256.             // Host 头部必须包含端口(如果是非默认端口)。
  257.             var headersToSign = new SortedList<string, string>();
  258.             // Host 头部
  259.             string hostHeaderValue = request.RequestUri.Host;
  260.             if (!request.RequestUri.IsDefaultPort)
  261.             {
  262.                 hostHeaderValue += ":" + request.RequestUri.Port;
  263.             }
  264.             headersToSign.Add("host", hostHeaderValue);
  265.             // x-amz-content-sha256 头部
  266.             headersToSign.Add("x-amz-content-sha256", contentHash);
  267.             // x-amz-date 头部
  268.             DateTime requestDateTime = DateTime.UtcNow;
  269.             string amzDate = requestDateTime.ToString("yyyyMMddTHHmmssZ", CultureInfo.InvariantCulture);
  270.             headersToSign.Add("x-amz-date", amzDate);
  271.             // Content-Type 头部 (仅用于 PUT/POST 请求)
  272.             if (request.Method == "PUT" || request.Method == "POST")
  273.             {
  274.                 string actualContentType = request.ContentType;
  275.                 if (string.IsNullOrEmpty(actualContentType))
  276.                 {
  277.                     actualContentType = "application/octet-stream"; // 签名时使用的默认 Content-Type
  278.                 }
  279.                 headersToSign.Add("content-type", actualContentType);
  280.             }
  281.             // 构建 canonicalHeaders 字符串
  282.             StringBuilder canonicalHeadersBuilder = new StringBuilder();
  283.             foreach (var header in headersToSign)
  284.             {
  285.                 canonicalHeadersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}:{1}\n", header.Key, header.Value.Trim()); // trim header values
  286.             }
  287.             string canonicalHeaders = canonicalHeadersBuilder.ToString();
  288.             // 1.5 Signed Headers
  289.             // 包含在规范化头部中所有头部名称的列表,小写,按字典序排序,用分号分隔。
  290.             string signedHeaders = string.Join(";", headersToSign.Keys.ToArray());
  291.             // 1.6 Payload Hash (已在方法参数中提供)
  292.             // 1.7 组合 Canonical Request
  293.             string canonicalRequest = string.Format(CultureInfo.InvariantCulture,
  294.                 "{0}\n{1}\n{2}\n{3}\n{4}\n{5}",
  295.                 httpRequestMethod,
  296.                 canonicalUri,
  297.                 canonicalQueryString,
  298.                 canonicalHeaders, // 注意这里已经包含了末尾的换行符
  299.                 signedHeaders,
  300.                 contentHash);
  301.             // --- 步骤 2: 创建 String to Sign ---
  302.             // Algorithm
  303.             string algorithm = "AWS4-HMAC-SHA256";
  304.             // Credential Scope
  305.             string dateStamp = requestDateTime.ToString("yyyyMMdd", CultureInfo.InvariantCulture);
  306.             string credentialScope = string.Format(CultureInfo.InvariantCulture,
  307.                 "{0}/{1}/{2}/aws4_request",
  308.                 dateStamp,
  309.                 _region,
  310.                 _service);
  311.             // Hash of Canonical Request
  312.             string hashedCanonicalRequest = ToHex(Hash(Encoding.UTF8.GetBytes(canonicalRequest)));
  313.             // 组合 String to Sign
  314.             string stringToSign = string.Format(CultureInfo.InvariantCulture,
  315.                 "{0}\n{1}\n{2}\n{3}",
  316.                 algorithm,
  317.                 amzDate,
  318.                 credentialScope,
  319.                 hashedCanonicalRequest);
  320.             // --- 步骤 3: 计算签名 ---
  321.             // Signing Key 派生
  322.             byte[] kSecret = Encoding.UTF8.GetBytes("AWS4" + _secretKey);
  323.             byte[] kDate = HmacSha256(kSecret, dateStamp);
  324.             byte[] kRegion = HmacSha256(kDate, _region);
  325.             byte[] kService = HmacSha256(kRegion, _service);
  326.             byte[] kSigning = HmacSha256(kService, "aws4_request");
  327.             // 计算最终签名
  328.             byte[] signatureBytes = HmacSha256(kSigning, stringToSign);
  329.             string signature = ToHex(signatureBytes);
  330.             // --- 步骤 4: 添加 Authorization 头部 ---
  331.             string authorizationHeader = string.Format(CultureInfo.InvariantCulture,
  332.                 "{0} Credential={1}/{2}, SignedHeaders={3}, Signature={4}",
  333.                 algorithm,
  334.                 _accessKey,
  335.                 credentialScope,
  336.                 signedHeaders,
  337.                 signature);
  338.             request.Headers["Authorization"] = authorizationHeader;
  339.             // 设置 x-amz-date 头部(如果尚未设置)
  340.             request.Headers["x-amz-date"] = amzDate;
  341.             // 设置 x-amz-content-sha256 头部(如果尚未设置)
  342.             request.Headers["x-amz-content-sha256"] = contentHash;
  343.         }
  344.         /// <summary>
  345.         /// 计算字节数组的 SHA256 哈希值。
  346.         /// </summary>
  347.         private static byte[] Hash(byte[] bytes)
  348.         {
  349.             using (SHA256 sha256 = new SHA256Managed())
  350.             {
  351.                 return sha256.ComputeHash(bytes);
  352.             }
  353.         }
  354.         /// <summary>
  355.         /// 计算 HMAC-SHA256 哈希值。
  356.         /// </summary>
  357.         private static byte[] HmacSha256(byte[] key, string data)
  358.         {
  359.             using (HMACSHA256 hmac = new HMACSHA256(key))
  360.             {
  361.                 return hmac.ComputeHash(Encoding.UTF8.GetBytes(data));
  362.             }
  363.         }
  364.         /// <summary>
  365.         /// 将字节数组转换为十六进制字符串。
  366.         /// </summary>
  367.         private static string ToHex(byte[] bytes)
  368.         {
  369.             return BitConverter.ToString(bytes).Replace("-", "").ToLowerInvariant();
  370.         }
  371.     }
  372. }
复制代码
测试代码如下:
  1. using System;
  2. using System.IO;
  3. using System.Threading;
  4. namespace MinioHttpOperatorDemo
  5. {
  6.     class Program
  7.     {
  8.         static void Main(string[] args)
  9.         {   // 替换为您的 MinIO 实例的地址
  10.             string minioEndpoint = "http://127.xxx.xxx.xxx:9000";
  11.             // 如果您的 MinIO 实例需要认证,请在这里提供您的 AccessKey 和 SecretKey。
  12.             // 例如:
  13.             string accessKey = "accessKey ";
  14.             string secretKey = "secretKey ";
  15.             MinioHttpOperator minioOperator = new MinioHttpOperator(minioEndpoint, accessKey, secretKey);
  16.             // 如果 MinIO 允许匿名访问,则无需提供 AccessKey 和 SecretKey
  17.             //MinioHttpOperator minioOperator = new MinioHttpOperator(minioEndpoint);
  18.             // 确保此桶在 MinIO 中存在或 MinIO 服务器允许自动创建桶。
  19.             string bucketName = "bucketName ";
  20.             string testFolder = "test";
  21.             // --- 准备多个测试文件 ---
  22.             string localFilePath1 = Path.Combine(Path.GetTempPath(), "testfile1.txt");
  23.             string localFilePath2 = Path.Combine(Path.GetTempPath(), "testfile2.jpg"); // 模拟图片文件
  24.             string minioObjectName1 = $"{testFolder}/document1.txt";
  25.             string minioObjectName2 = $"{testFolder}/image.jpg";
  26.             string content1 = "This is the content for document one.";
  27.             byte[] content2 = new byte[1024]; // 模拟一个1KB的二进制数据作为图片内容
  28.             new Random().NextBytes(content2); // 填充随机字节
  29.             try
  30.             {
  31.                 File.WriteAllText(localFilePath1, content1);
  32.                 File.WriteAllBytes(localFilePath2, content2);
  33.                 Console.WriteLine($"已在本地创建测试文件:{localFilePath1} 和 {localFilePath2}");
  34.             }
  35.             catch (Exception ex)
  36.             {
  37.                 Console.WriteLine($"创建测试文件失败:{ex.Message}");
  38.                 Console.WriteLine("请检查文件路径和权限。程序将退出。");
  39.                 Console.ReadKey();
  40.                 return;
  41.             }
  42.             Console.WriteLine("\n--- 开始 MinIO 批量操作 ---");
  43.             // --- 上传第一个文件 ---
  44.             Console.WriteLine($"\n尝试上传文件:{localFilePath1} 到 {minioEndpoint}/{bucketName}/{minioObjectName1}...");
  45.             if (minioOperator.UploadFile(bucketName, minioObjectName1, localFilePath1, "text/plain"))
  46.             {
  47.                 Console.WriteLine("文件上传成功。");
  48.             }
  49.             else
  50.             {
  51.                 Console.WriteLine("文件上传失败。");
  52.             }
  53.             Thread.Sleep(1000); // 稍作等待
  54.             // --- 上传第二个文件 ---
  55.             Console.WriteLine($"\n尝试上传文件:{localFilePath2} 到 {minioEndpoint}/{bucketName}/{minioObjectName2}...");
  56.             if (minioOperator.UploadFile(bucketName, minioObjectName2, localFilePath2, "image/jpeg"))
  57.             {
  58.                 Console.WriteLine("文件上传成功。");
  59.             }
  60.             else
  61.             {
  62.                 Console.WriteLine("文件上传失败。");
  63.             }
  64.             Thread.Sleep(1000); // 稍作等待
  65.             Console.WriteLine("\n----------------------------------------");
  66.             // --- 下载第一个文件 ---
  67.             string downloadSavePath1 = Path.Combine(Path.GetTempPath(), "downloaded_document1.txt");
  68.             Console.WriteLine($"\n尝试从 {minioEndpoint}/{bucketName}/{minioObjectName1} 下载文件到 {downloadSavePath1}...");
  69.             if (minioOperator.DownloadFile(bucketName, minioObjectName1, downloadSavePath1))
  70.             {
  71.                 Console.WriteLine("文件下载成功。");
  72.                 try
  73.                 {
  74.                     Console.WriteLine($"下载文件的内容:{File.ReadAllText(downloadSavePath1)}");
  75.                 }
  76.                 catch (Exception ex)
  77.                 {
  78.                     Console.WriteLine($"读取下载文件内容失败:{ex.Message}");
  79.                 }
  80.             }
  81.             else
  82.             {
  83.                 Console.WriteLine("文件下载失败。");
  84.             }
  85.             Thread.Sleep(1000); // 稍作等待
  86.             // --- 尝试下载一个不存在的文件 ---
  87.             string nonExistentObject = $"{testFolder}/nonexistent.pdf";
  88.             string downloadNonExistentPath = Path.Combine(Path.GetTempPath(), "nonexistent.pdf");
  89.             Console.WriteLine($"\n尝试下载不存在的文件:{nonExistentObject}...");
  90.             if (!minioOperator.DownloadFile(bucketName, nonExistentObject, downloadNonExistentPath))
  91.             {
  92.                 Console.WriteLine("下载不存在的文件失败(预期结果)。");
  93.             }
  94.             Thread.Sleep(1000); // 稍作等待
  95.             Console.WriteLine("\n----------------------------------------");
  96.             // --- 删除第一个文件 ---
  97.             Console.WriteLine($"\n尝试从 {minioEndpoint}/{bucketName} 删除文件 {minioObjectName1}...");
  98.             if (minioOperator.DeleteFile(bucketName, minioObjectName1))
  99.             {
  100.                 Console.WriteLine("文件删除成功。");
  101.             }
  102.             else
  103.             {
  104.                 Console.WriteLine("文件删除失败。");
  105.             }
  106.             Thread.Sleep(1000); // 稍作等待
  107.             // --- 删除第二个文件 ---
  108.             Console.WriteLine($"\n尝试从 {minioEndpoint}/{bucketName} 删除文件 {minioObjectName2}...");
  109.             if (minioOperator.DeleteFile(bucketName, minioObjectName2))
  110.             {
  111.                 Console.WriteLine("文件删除成功。");
  112.             }
  113.             else
  114.             {
  115.                 Console.WriteLine("文件删除失败。");
  116.             }
  117.             Console.WriteLine("\n--- MinIO 批量操作结束 ---");
  118.             // 清理本地创建的测试文件
  119.             try
  120.             {
  121.                 if (File.Exists(localFilePath1))
  122.                 {
  123.                     File.Delete(localFilePath1);
  124.                     Console.WriteLine($"已清理本地测试文件:{localFilePath1}");
  125.                 }
  126.                 if (File.Exists(localFilePath2))
  127.                 {
  128.                     File.Delete(localFilePath2);
  129.                     Console.WriteLine($"已清理本地测试文件:{localFilePath2}");
  130.                 }
  131.                 if (File.Exists(downloadSavePath1))
  132.                 {
  133.                     File.Delete(downloadSavePath1);
  134.                     Console.WriteLine($"已清理本地下载文件:{downloadSavePath1}");
  135.                 }
  136.                 if (File.Exists(downloadNonExistentPath))
  137.                 {
  138.                     File.Delete(downloadNonExistentPath);
  139.                     Console.WriteLine($"已清理本地下载文件:{downloadNonExistentPath}");
  140.                 }
  141.             }
  142.             catch (Exception ex)
  143.             {
  144.                 Console.WriteLine($"清理本地文件失败:{ex.Message}");
  145.             }
  146.             Console.WriteLine("\n按任意键退出程序。");
  147.             Console.ReadKey();
  148.         }
  149.     }
  150. }
复制代码
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册