2016-08-01 3 views
1

Я пытаюсь написать инструмент, который может загружать шейп-файлы с FTP-сайта TIGER бюро переписи, который находится здесь: ftp://ftp2.census.gov/geo/tiger/TIGER2015/TRACT. Я могу перечислить файлы просто отлично, но когда я пытаюсь загрузить файл, я получаю строку, которая является просто именем файла, а не самим содержимым файла. Код ниже.Получение имени файла вместо содержимого при загрузке файла с помощью FtpWebRequest

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, он терпит неудачу с ошибкой 550 для .NET 3.5, но работает отлично для .NET 4.6. Соответствующий код прокомментирован выше.

Сайт переписи немного утончен, поэтому вполне возможно, что их сайт делает странные вещи. Вот почему я предоставил URL-адрес, если кто-либо с большим количеством знаний по FTP, чем я, может диагностировать плохой сервер.

+0

Если бы вы создали [mcve] для своего вопроса, вы бы заметили проблему самостоятельно. См. Мой ответ. –

ответ

2

В вашем методе FtpRequest вы всегда используете метод WebRequestMethods.Ftp.ListDirectory, даже для загрузки. Следовательно, вы фактически «перечислите» файл, поэтому вы получите его имя в ответе.

Чтобы загрузить файл, вы должны использовать WebRequestMethods.Ftp.DownloadFile method.

+0

Мальчик я глуп. Я имею в виду, ничего себе, это был главный надзор. Давайте обвиним его в понедельник. – siride