You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

2023年C#控制台程序上传文件至SharePoint文档库子文件夹方案问询

C# 自动上传文件至SharePoint文档库子文件夹(2023环境兼容方案)

所需NuGet包

  • Microsoft.SharePointOnline.CSOM(版本16.0.24121.12000及以上,适配新版SharePoint Online)
  • Microsoft.IdentityModel.Clients.ActiveDirectory(仅应用权限认证方案需要)

必要Using语句

using Microsoft.SharePoint.Client;
using System.IO;
using System.Security;
using System.Linq;
using Microsoft.IdentityModel.Clients.ActiveDirectory; // 仅方案2需要

方案1:基于用户名/密码认证(已禁用MFA场景)

适合已关闭MFA的环境,可使用用户密码或应用密码认证:

class Program
{
    static void Main(string[] args)
    {
        // 配置参数
        string siteUrl = "https://5mhhvs.sharepoint.com/sites/Documents";
        string libraryName = "Documents"; // 目标文档库名称
        string targetSubFolderPath = "年度报告/2024"; // 子文件夹路径(相对于文档库根目录)
        string localFilePath = @"C:\LocalFiles\2024年度报告.pdf";

        // 认证信息
        string userName = "your-account@5mhhvs.onmicrosoft.com";
        string password = "your-password-or-app-password";

        using (ClientContext context = new ClientContext(siteUrl))
        {
            // 设置凭证
            SecureString securePwd = new SecureString();
            foreach (char c in password) securePwd.AppendChar(c);
            context.Credentials = new SharePointOnlineCredentials(userName, securePwd);

            try
            {
                // 获取文档库根文件夹
                List library = context.Web.Lists.GetByTitle(libraryName);
                context.Load(library.RootFolder);
                context.ExecuteQuery();

                // 创建或获取目标子文件夹
                Folder targetFolder = GetOrCreateFolder(context, library.RootFolder.ServerRelativeUrl, targetSubFolderPath);

                // 上传文件(可设置是否覆盖现有文件)
                UploadFileToFolder(context, targetFolder, localFilePath, overwriteExisting: true);

                Console.WriteLine("文件上传成功");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"上传失败:{ex.Message}");
            }
        }
    }

    // 递归创建/获取子文件夹
    private static Folder GetOrCreateFolder(ClientContext context, string parentFolderUrl, string subFolderPath)
    {
        string[] folderSegments = subFolderPath.Split('/');
        string currentFolderUrl = parentFolderUrl;

        foreach (string folderName in folderSegments)
        {
            FolderCollection folders = context.Web.GetFolderByServerRelativeUrl(currentFolderUrl).Folders;
            context.Load(folders);
            context.ExecuteQuery();

            Folder targetFolder = folders.FirstOrDefault(f => f.Name.Equals(folderName, StringComparison.OrdinalIgnoreCase));
            if (targetFolder == null)
            {
                targetFolder = context.Web.GetFolderByServerRelativeUrl(currentFolderUrl).Folders.Add(folderName);
                context.ExecuteQuery();
            }
            currentFolderUrl = targetFolder.ServerRelativeUrl;
        }
        return context.Web.GetFolderByServerRelativeUrl(currentFolderUrl);
    }

    // 上传文件到指定文件夹
    private static void UploadFileToFolder(ClientContext context, Folder targetFolder, string localFilePath, bool overwriteExisting)
    {
        string fileName = Path.GetFileName(localFilePath);
        byte[] fileBytes = File.ReadAllBytes(localFilePath);

        FileCreationInformation fileInfo = new FileCreationInformation
        {
            Content = fileBytes,
            Url = $"{targetFolder.ServerRelativeUrl}/{fileName}",
            Overwrite = overwriteExisting
        };

        Microsoft.SharePoint.Client.File uploadedFile = targetFolder.Files.Add(fileInfo);
        context.Load(uploadedFile);
        context.ExecuteQuery();
    }
}

方案2:基于客户端ID/密钥认证(应用权限,推荐自动化任务)

适合长期自动执行的场景,无需依赖用户密码,需提前在Azure AD和SharePoint配置应用权限:

class Program
{
    static void Main(string[] args)
    {
        // 配置参数
        string siteUrl = "https://5mhhvs.sharepoint.com/sites/Documents";
        string libraryName = "Documents";
        string targetSubFolderPath = "年度报告/2024";
        string localFilePath = @"C:\LocalFiles\2024年度报告.pdf";

        // 应用认证信息
        string clientId = "your-azure-ad-app-client-id";
        string clientSecret = "your-azure-ad-app-client-secret";
        string tenantId = "your-tenant-id";

        using (ClientContext context = new ClientContext(siteUrl))
        {
            // 设置应用凭证
            context.AuthenticationMode = ClientAuthenticationMode.Default;
            context.FormDigestHandlingEnabled = false;
            context.Credentials = GetAppOnlyCredentials(siteUrl, clientId, clientSecret, tenantId);

            try
            {
                // 复用方案1的文件夹处理和文件上传逻辑
                List library = context.Web.Lists.GetByTitle(libraryName);
                context.Load(library.RootFolder);
                context.ExecuteQuery();

                Folder targetFolder = GetOrCreateFolder(context, library.RootFolder.ServerRelativeUrl, targetSubFolderPath);
                UploadFileToFolder(context, targetFolder, localFilePath, overwriteExisting: true);

                Console.WriteLine("文件上传成功");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"上传失败:{ex.Message}");
            }
        }
    }

    // 获取应用权限凭证
    private static SharePointOnlineCredentials GetAppOnlyCredentials(string siteUrl, string clientId, string clientSecret, string tenantId)
    {
        string resource = new Uri(siteUrl).Authority;
        string authority = $"https://login.microsoftonline.com/{tenantId}";

        var authContext = new AuthenticationContext(authority);
        var clientCredential = new ClientCredential(clientId, clientSecret);
        var authResult = authContext.AcquireTokenAsync($"https://{resource}/", clientCredential).Result;

        return new SharePointOnlineCredentials(clientId, ConvertToSecureString(authResult.AccessToken));
    }

    private static SecureString ConvertToSecureString(string input)
    {
        SecureString secureStr = new SecureString();
        foreach (char c in input) secureStr.AppendChar(c);
        return secureStr;
    }

    // 复用方案1的GetOrCreateFolder和UploadFileToFolder方法
    private static Folder GetOrCreateFolder(ClientContext context, string parentFolderUrl, string subFolderPath)
    {
        // 同方案1代码
    }

    private static void UploadFileToFolder(ClientContext context, Folder targetFolder, string localFilePath, bool overwriteExisting)
    {
        // 同方案1代码
    }
}

问题解答

1. 若目标位置已存在文件,能否配置合并修改?

SharePoint无自动合并文件内容的原生功能,需根据文件类型自定义处理:

  • Office文档(Word/Excel/PowerPoint):可通过Open XML SDK或Office Interop下载云端文件,对比本地文件内容差异后手动实现合并逻辑,再上传覆盖并保留版本历史(需开启文档库版本控制)。
  • 非Office文件:仅支持覆盖旧文件(设置Overwrite = true),或自定义对比逻辑合并内容后上传。

2. 若文件正被SharePoint用户打开编辑,能否强制上传?

文件被用户打开时会处于锁定状态,直接上传会触发锁定异常。可尝试以下方式强制上传,但存在数据丢失风险:

  • 使用File.SaveBinaryDirect()方法搭配覆盖参数,直接替换锁定文件;
  • 先调用file.CheckOut()尝试解除锁定(若用户未独占编辑),再上传。

推荐优先检查文件锁定状态,若被锁定则记录日志并延后重试,避免破坏用户正在编辑的内容。

内容的提问来源于stack exchange,提问作者Dushan Rathnayake

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 04:57:42