使用 FtpWebRequest 下载文件时获取文件名而不是内容
Getting file name instead of contents when downloading file with FtpWebRequest
我正在尝试编写一个可以从人口普查局的 TIGER FTP 站点下载 shapefile 的工具,该站点位于:ftp://ftp2.census.gov/geo/tiger/TIGER2015/TRACT。我能够很好地列出文件,但是当我尝试下载文件时,我得到的字符串只是文件名,而不是文件内容本身。代码如下。
private static T FtpRequest<T, TReader>(string url, string method, Func<TReader, T> responseAction) where TReader : IDisposable {
var request = (FtpWebRequest)WebRequest.Create(url);
request.Method = WebRequestMethods.Ftp.ListDirectory;
request.Credentials = new NetworkCredential("anonymous", "anonymous");
request.UseBinary = true;
request.UsePassive = true;
var response = (FtpWebResponse)request.GetResponse();
using(var responseStream = response.GetResponseStream())
using(var reader = (TReader)Activator.CreateInstance(typeof(TReader), responseStream)) {
return responseAction(reader);
}
}
private static IList<string> ListDirectory(string url) {
return FtpRequest(url,
WebRequestMethods.Ftp.ListDirectory,
(StreamReader reader) => reader.ReadAllLines()
.Select(file => new Uri(new Uri(url), new Uri(file, UriKind.Relative)).AbsoluteUri)
.ToArray());
}
private static byte[] DownloadBinaryFile(string url) {
// NOTE: following code works in 4.6, but not 3.5
//using(var client = new WebClient()) {
// return client.DownloadData(url);
//}
// this code returns file name as string in both 4.6 and 3.5
return FtpRequest(url,
WebRequestMethods.Ftp.DownloadFile,
(BinaryReader reader) => {
using(var memoryStream = new MemoryStream()) {
var buffer = new byte[2048];
for(;;) {
var bytesRead = reader.Read(buffer, 0, buffer.Length);
if(bytesRead == 0)
break;
memoryStream.Write(buffer, 0, bytesRead);
}
memoryStream.Position = 0;
return memoryStream.GetBuffer();
}
});
}
internal static void Main(string[] args) {
var baseUrl = "ftp://ftp2.census.gov/geo/tiger/TIGER2015/TRACT";
foreach(var file in ListDirectory(baseUrl)) {
Console.WriteLine("Downloading: {0}", file);
var contents = DownloadBinaryFile(file);
using(var zipStream = new MemoryStream(contents))
using(var zipFile = ZipFile.Read(zipStream)) {
foreach(var entry in zipFile) {
Console.WriteLine(" -> {0}", entry.FileName);
//using(var entryReader = entry.OpenReader()) {
//}
}
}
}
Console.ReadKey();
}
如果我使用 WebClient
,它会在 .NET 3.5 中失败并出现 550 错误,但在 .NET 4.6 中可以正常工作。上面注释掉了相关代码。
人口普查网站有点挑剔,所以他们的网站完全有可能在做奇怪的事情。这就是我提供 URL 的原因,以防任何 FTP 知识比我多的人可以诊断出故障服务器。
在您的 FtpRequest
方法中,您总是使用 WebRequestMethods.Ftp.ListDirectory
方法,即使是下载。因此,您实际上是 "list" 文件,这就是您在响应中获得其名称的原因。
您必须使用 WebRequestMethods.Ftp.DownloadFile
method 下载文件。
我正在尝试编写一个可以从人口普查局的 TIGER FTP 站点下载 shapefile 的工具,该站点位于:ftp://ftp2.census.gov/geo/tiger/TIGER2015/TRACT。我能够很好地列出文件,但是当我尝试下载文件时,我得到的字符串只是文件名,而不是文件内容本身。代码如下。
private static T FtpRequest<T, TReader>(string url, string method, Func<TReader, T> responseAction) where TReader : IDisposable {
var request = (FtpWebRequest)WebRequest.Create(url);
request.Method = WebRequestMethods.Ftp.ListDirectory;
request.Credentials = new NetworkCredential("anonymous", "anonymous");
request.UseBinary = true;
request.UsePassive = true;
var response = (FtpWebResponse)request.GetResponse();
using(var responseStream = response.GetResponseStream())
using(var reader = (TReader)Activator.CreateInstance(typeof(TReader), responseStream)) {
return responseAction(reader);
}
}
private static IList<string> ListDirectory(string url) {
return FtpRequest(url,
WebRequestMethods.Ftp.ListDirectory,
(StreamReader reader) => reader.ReadAllLines()
.Select(file => new Uri(new Uri(url), new Uri(file, UriKind.Relative)).AbsoluteUri)
.ToArray());
}
private static byte[] DownloadBinaryFile(string url) {
// NOTE: following code works in 4.6, but not 3.5
//using(var client = new WebClient()) {
// return client.DownloadData(url);
//}
// this code returns file name as string in both 4.6 and 3.5
return FtpRequest(url,
WebRequestMethods.Ftp.DownloadFile,
(BinaryReader reader) => {
using(var memoryStream = new MemoryStream()) {
var buffer = new byte[2048];
for(;;) {
var bytesRead = reader.Read(buffer, 0, buffer.Length);
if(bytesRead == 0)
break;
memoryStream.Write(buffer, 0, bytesRead);
}
memoryStream.Position = 0;
return memoryStream.GetBuffer();
}
});
}
internal static void Main(string[] args) {
var baseUrl = "ftp://ftp2.census.gov/geo/tiger/TIGER2015/TRACT";
foreach(var file in ListDirectory(baseUrl)) {
Console.WriteLine("Downloading: {0}", file);
var contents = DownloadBinaryFile(file);
using(var zipStream = new MemoryStream(contents))
using(var zipFile = ZipFile.Read(zipStream)) {
foreach(var entry in zipFile) {
Console.WriteLine(" -> {0}", entry.FileName);
//using(var entryReader = entry.OpenReader()) {
//}
}
}
}
Console.ReadKey();
}
如果我使用 WebClient
,它会在 .NET 3.5 中失败并出现 550 错误,但在 .NET 4.6 中可以正常工作。上面注释掉了相关代码。
人口普查网站有点挑剔,所以他们的网站完全有可能在做奇怪的事情。这就是我提供 URL 的原因,以防任何 FTP 知识比我多的人可以诊断出故障服务器。
在您的 FtpRequest
方法中,您总是使用 WebRequestMethods.Ftp.ListDirectory
方法,即使是下载。因此,您实际上是 "list" 文件,这就是您在响应中获得其名称的原因。
您必须使用 WebRequestMethods.Ftp.DownloadFile
method 下载文件。