在C#开发中,操作本地文件可以通过System.IO命名空间下的类轻松实现,而操作WebDav服务器上的文件往往需要手动处理HTTP请求、认证、路径拼接等复杂逻辑。通过封装WebDav操作的核心逻辑,我们可以让WebDav文件操作拥有和本地文件操作一致的API体验,大幅降低使用门槛。

WebDav操作的核心原理
WebDav是基于HTTP协议的扩展协议,支持文件的创建、读取、修改、删除等操作。要实现类本地文件的操作,核心是将WebDav的HTTP请求封装成和System.IO.File、System.IO.Directory方法对应的接口,同时处理服务器认证、路径转换等细节。
基础认证处理
大部分WebDav服务器需要用户名密码认证,我们可以通过设置HTTP请求的Authorization头来实现。以下是基础的认证请求封装代码:
using System;
using System.Net;
using System.Text;
public class WebDavClient
{
private readonly string _baseUrl;
private readonly NetworkCredential _credential;
public WebDavClient(string baseUrl, string userName, string password)
{
_baseUrl = baseUrl.TrimEnd('/') + "/";
_credential = new NetworkCredential(userName, password);
}
private HttpWebRequest CreateRequest(string path, string method)
{
string fullUrl = _baseUrl + path.TrimStart('/');
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(fullUrl);
request.Method = method;
request.Credentials = _credential;
return request;
}
}
封装文件读写方法
接下来我们封装和本地文件操作对应的方法,包括读取文件、写入文件、判断文件是否存在、删除文件等,让使用方式和System.IO.File类保持一致。
读取WebDav文件内容
对应本地文件的File.ReadAllBytes方法,实现WebDav文件的读取:
using System.IO;
public byte[] ReadAllBytes(string remotePath)
{
HttpWebRequest request = CreateRequest(remotePath, "GET");
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
using (Stream stream = response.GetStream())
using (MemoryStream ms = new MemoryStream())
{
stream.CopyTo(ms);
return ms.ToArray();
}
}
// 读取文本文件,对应File.ReadAllText
public string ReadAllText(string remotePath, Encoding encoding = null)
{
encoding = encoding ?? Encoding.UTF8;
byte[] bytes = ReadAllBytes(remotePath);
return encoding.GetString(bytes);
}
写入文件到WebDav服务器
对应本地文件的File.WriteAllBytes方法,实现文件上传写入:
public void WriteAllBytes(string remotePath, byte[] content)
{
HttpWebRequest request = CreateRequest(remotePath, "PUT");
request.ContentLength = content.Length;
using (Stream stream = request.GetRequestStream())
{
stream.Write(content, 0, content.Length);
}
// 获取响应确保请求成功
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) { }
}
// 写入文本内容,对应File.WriteAllText
public void WriteAllText(string remotePath, string content, Encoding encoding = null)
{
encoding = encoding ?? Encoding.UTF8;
byte[] bytes = encoding.GetBytes(content);
WriteAllBytes(remotePath, bytes);
}
封装目录操作方法
除了文件操作,我们还需要支持目录的创建、删除、枚举等,对应System.IO.Directory类的功能。
创建WebDav目录
WebDav创建目录使用MKCOL方法,封装如下:
public void CreateDirectory(string remotePath)
{
HttpWebRequest request = CreateRequest(remotePath, "MKCOL");
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) { }
}
枚举目录下的文件和子目录
WebDav通过PROPFIND方法获取目录下的资源列表,解析返回的XML即可得到文件和目录信息:
using System.Collections.Generic;
using System.Xml;
public List<string> GetFiles(string remotePath)
{
List<string> files = new List<string>();
HttpWebRequest request = CreateRequest(remotePath, "PROPFIND");
request.Headers.Add("Depth", "1");
request.ContentType = "text/xml";
// 发送PROPFIND请求体
string propFindBody = "<?xml version='1.0' encoding='utf-8'?><propfind xmlns='DAV:'><prop><displayname/><iscollection/></prop></propfind>";
byte[] bodyBytes = Encoding.UTF8.GetBytes(propFindBody);
request.ContentLength = bodyBytes.Length;
using (Stream stream = request.GetRequestStream())
{
stream.Write(bodyBytes, 0, bodyBytes.Length);
}
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
using (Stream responseStream = response.GetStream())
using (XmlReader reader = XmlReader.Create(responseStream))
{
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element && reader.Name == "D:response")
{
// 解析资源路径和是否为集合
string href = "";
bool isCollection = false;
while (reader.Read() && reader.Name != "D:response")
{
if (reader.Name == "D:href")
{
href = reader.ReadElementContentAsString();
}
else if (reader.Name == "D:iscollection")
{
isCollection = reader.ReadElementContentAsString() == "1";
}
}
// 排除当前目录本身,只添加文件
if (!isCollection && !string.IsNullOrEmpty(href) && href != remotePath)
{
files.Add(href);
}
}
}
}
return files;
}
使用示例
封装完成后,使用方式和操作本地文件几乎没有区别,以下是完整的使用示例:
class Program
{
static void Main()
{
// 初始化WebDav客户端,替换为你的服务器地址、用户名、密码
WebDavClient client = new WebDavClient("http://ipipp.com/webdav", "testuser", "testpass");
// 创建目录
client.CreateDirectory("testdir");
// 写入文本文件
client.WriteAllText("testdir/demo.txt", "这是WebDav上的测试内容");
// 读取文件内容
string content = client.ReadAllText("testdir/demo.txt");
Console.WriteLine("读取到的内容:" + content);
// 枚举目录下的文件
List<string> files = client.GetFiles("testdir");
Console.WriteLine("目录下的文件:");
foreach (var file in files)
{
Console.WriteLine(file);
}
}
}
注意事项
- WebDav服务器路径需要注意大小写敏感问题,不同服务器的实现可能有差异
- 大文件操作建议使用流式传输,避免一次性加载全部内容到内存
- 需要处理网络异常、权限不足等错误场景,建议在实际项目中添加try-catch逻辑
- 如果服务器使用HTTPS,需要确保证书有效,或者根据需求配置证书验证逻辑