【问题标题】:Azure function to copy files from FTP to blob storage using FluentFTP使用 FluentFTP 将文件从 FTP 复制到 blob 存储的 Azure 功能
【发布时间】:2019-07-02 08:07:11
【问题描述】:

我有一个添加每日文件的 FTP 源,我需要使用 azure 函数中的 FluentFTP 库每天将文件从 FTP 复制到 blob 存储

我在 Azure 函数中使用 C#,我完成了所有编码部分,但缺少从 FTP 下载文件以将其直接复制到 blob 目标。

//#r "FluentFTP"
#r "Newtonsoft.Json"
#r "System.Data"
#r "Microsoft.WindowsAzure.Storage"

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using System.Globalization;
using System;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Auth;
using Microsoft.WindowsAzure.Storage.Blob;

using System.Net;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
using Newtonsoft.Json;
using FluentFTP;

public static async Task<IActionResult> Run(HttpRequest req, ILogger log)
{
    string blobConnectionString = "ConnectionString";

    // Gestione BLOB Storage
    CloudStorageAccount storageAccount = CloudStorageAccount.Parse(blobConnectionString);
    CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
    CloudBlobContainer container = blobClient.GetContainerReference("out");

    using (FtpClient conn = new FtpClient()) 
    {
        conn.Host = "ftp server";
        conn.Credentials = new NetworkCredential("username", "pass");

        // get a list of files and directories in the "/OUT" folder
        foreach (FtpListItem item in conn.GetListing("/OUT")) 
        {
            // if this is a file and ends with CSV
            if (
            item.Type == FtpFileSystemObjectType.File
            &&
            item.FullName.ToLower().EndsWith(".csv")
            )
            {

                string yyyy = item.FullName.Substring(10,4);
                string mm   = item.FullName.Substring(14,2);
                string dd   = item.FullName.Substring(16,2);
                var fileName = "out/brt/" + yyyy + "/"+ mm + "/"+ dd + "/" + item.Name;

                CloudBlockBlob blockBlob = container.GetBlockBlobReference(fileName);
                // download the file
                conn.DownloadFile( blockBlob , item.FullName);
            }
        }

        return new OkObjectResult($"Hello");
    }
}

如果我可以使用 blob 容器作为 FluentFTP 函数的目标,那将是最好的,但这样我会收到错误,即我正在使用的这个 blob 块不是目标

这是我得到的错误

无法从“Microsoft.WindowsAzure.Storage.Blob.CloudBlockBlob”转换为“字符串”

我不知道是否有其他方法可以在本地下载文件,以便我可以将其上传到 blob,而不是使用 client.DownloadFile 函数。

【问题讨论】:

    标签: c# ftp azure-functions azure-blob-storage fluentftp


    【解决方案1】:

    如果您想使用 FluentFTP,您可以使用以下两种方法之一获取 Blob 上传流:

    1. CloudBlockBlob.OpenWrite()
    2. CloudBlockBlob.OpenWriteAsync()

    然后您可以使用FTPClient.Download 方法,该方法采用Stream

    public bool Download(Stream outStream, string remotePath, IProgress<double> progress = null)
    

    类似这样的:

    [FunctionName("HttpTriggerCSharp")]
        public static async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req, ILogger log)
        {
            log.LogInformation("C# HTTP trigger function processed a request.");
    
            var ftpHost = "xxxxx";
            var ftpUserName = "xxxx";
            var ftpPassword = "xxxx";
            var filename = "xxxxx";            
            string blobConnectionString = "xxxxxxxxxxx";
    
            CloudStorageAccount storageAccount = CloudStorageAccount.Parse(blobConnectionString);
            CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
            CloudBlobContainer container = blobClient.GetContainerReference("xxxxx");
    
    
            FtpClient client = new FtpClient(ftpHost, ftpUserName, ftpPassword); // or set Host & Credentials
            client.EncryptionMode = FtpEncryptionMode.Implicit;
            client.SslProtocols = SslProtocols.None;
            client.ValidateCertificate += new FtpSslValidation(OnValidateCertificate);
            client.Connect();
    
            void OnValidateCertificate(FtpClient control, FtpSslValidationEventArgs e) {
                // add logic to test if certificate is valid here
                e.Accept = true;
            }
    
            CloudBlockBlob blockBlob = container.GetBlockBlobReference(filename);
            var outStream = blockBlob.OpenWrite();
            client.Download(outStream,filename);
            outStream.Commit(); // I'm not sure if this is needed?
    
            log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");
    
    
            return  (ActionResult)new OkObjectResult($"Action succeeded.");
        }
    

    【讨论】:

    • outStream.Commit 是非常需要的,否则你最终会在 blob 存储中得到一个 0b 文件;)
    • 针对我之前的评论,我现在刚刚使用 Azure Blob SDK 的 v12 进行了测试,并且不需要提交来保存文件。但 v11 需要它。
    【解决方案2】:

    Fluent FTP 可能无法实现。

    FtpClient.Download 方法采用Stream

    public bool Download(Stream outStream, string remotePath, IProgress<double> progress = null)
    

    但似乎没有 API 可以获取“blob 上传流”

    相反,您无法从 FluentFTP 获取 “FTP 下载流”(您可以使用 blob API)。


    但是你可以使用原生 .NET FtpWebRequest FTP 客户端,它有 API 来获取 “FTP 下载流”

    public static async System.Threading.Tasks.Task RunAsync([TimerTrigger("0 */1 * * * *")]TimerInfo myTimer, ILogger log)
    {
        var ftpUserName = "xxxxxx";
        var ftpPassword = "xxxxxxxxx";
        var filename = "test.png";
        string blobConnectionString = "xxxxxxx";
        CloudStorageAccount storageAccount = CloudStorageAccount.Parse(blobConnectionString);
        CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
        CloudBlobContainer container = blobClient.GetContainerReference("myblobcontainer");
        FtpWebRequest fileRequest = (FtpWebRequest)WebRequest.Create("ftp://xxxxxx/" + filename);
        fileRequest.Method = WebRequestMethods.Ftp.DownloadFile;
        fileRequest.Credentials = new NetworkCredential(ftpUserName, ftpPassword);
        FtpWebResponse fileResponse = (FtpWebResponse)fileRequest.GetResponse();
        Stream fileStream = fileResponse.GetResponseStream();
        CloudBlockBlob blockBlob = container.GetBlockBlobReference(filename);
    
        await blockBlob.UploadFromStreamAsync(fileStream);
        log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");
    }
    

    【讨论】:

    • 你确定它有效吗?它在过去不起作用:stackoverflow.com/q/47599211/850848 - 但也许他们已经改进了它。
    • @Martin Prikryl,我确定。我在本地测试并且它可以工作,它确实上传了文件。
    • 如果您不介意,我已经在我的解释中合并了为什么不能使用 FluentFTP(OP 要求的)。这样我就可以愉快地删除我的答案并为你的答案投票,因为它是完整的。
    • @George Chen 我确认它工作正常,非常感谢
    【解决方案3】:

    您不能使用 SDK 直接将文件从 FTP 移动到 Blob。您必须先临时下载文件 - 下载到流中(取决于它们的大小)或临时文件。

    但是,如果您只想按计划将文件从 FTP 移动到 Blob,我实际上会考虑使用专为此类任务构建的 Azure 数据工厂:https://docs.microsoft.com/en-us/azure/data-factory/connector-ftp

    【讨论】:

    • 谢谢你的回答,你能给我一些库或提示如何在流或临时文件中下载它们(我以前没有这样做),关于数据工厂,我已经使用过它,但我正在研究使用该功能,因为 DF 并不便宜。
    • 我没有在 C# 中使用过 FTP 库(至少很长时间没有使用过)。但我假设您在那里使用的 FluentFtp 库将有类似下载的内容。当你说数据工厂不便宜时,你会考虑定价吗? ADF 收取“数据移动活动:0.211 欧元/DIU 小时”的费用。
    • 感谢您的澄清,我将重新检查 DF。
    猜你喜欢
    • 2020-08-18
    • 2021-07-29
    • 2017-01-19
    • 2019-04-01
    • 2017-05-06
    • 2017-02-20
    • 2020-03-23
    • 2018-09-25
    • 1970-01-01
    相关资源
    最近更新 更多