【问题标题】:Upload file using a virtual path provider and Amazon S3 SDK使用虚拟路径提供程序和 Amazon S3 SDK 上传文件
【发布时间】:2012-11-30 18:22:33
【问题描述】:

这个问题的背景是基于我正在开发的虚拟文件系统。我使用的概念是不同类型存储类型的虚拟路径提供程序,即本地文件系统、保管箱和亚马逊 s3。我的虚拟文件基类如下所示:

public abstract class CommonVirtualFile : VirtualFile {
    public virtual string Url {
        get { throw new NotImplementedException(); }
    }
    public virtual string LocalPath {
        get { throw new NotImplementedException(); }
    }
    public override Stream Open() {
        throw new NotImplementedException();
    }
    public virtual Stream Open(FileMode fileMode) {
        throw new NotImplementedException();
    }
    protected CommonVirtualFile(string virtualPath) : base(virtualPath) { }
}

第二个 Open 方法的实现是我的问题所在。如果我们查看我的本地文件系统实现,即在磁盘上保存文件,它看起来像这样:

public override Stream Open(FileMode fileMode) {
    return new FileStream("The_Path_To_The_File_On_Disk"), fileMode);
}

如果我想在本地文件系统上保存一个文件,它看起来像这样:

    const string virtualPath = "/assets/newFile.txt";
    var file = HostingEnvironment.VirtualPathProvider.GetFile(virtualPath) as CommonVirtualFile;
    if (file == null) {
        var virtualDir = VirtualPathUtility.GetDirectory(virtualPath);
        var directory = HostingEnvironment.VirtualPathProvider.GetDirectory(virtualDir) as CommonVirtualDirectory;
        file = directory.CreateFile(VirtualPathUtility.GetFileName(virtualPath));
    }
    byte[] fileContent;
    using (var fileStream = new FileStream(@"c:\temp\fileToCopy.txt", FileMode.Open, FileAccess.Read)) {
        fileContent = new byte[fileStream.Length];
        fileStream.Read(fileContent, 0, fileContent.Length);
    }
    // write the content to the local file system
    using (Stream stream = file.Open(FileMode.Create)) {
        stream.Write(fileContent, 0, fileContent.Length);
    }

我想要的是,如果我切换到我的 amazon s3 虚拟路径提供程序,我希望这段代码可以直接工作而无需任何更改,所以总结一下,我如何使用 amazon s3 sdk 解决这个问题以及我应该如何实现我的我的 amazon s3 虚拟路径提供程序中的 Open(FileMode fileMode) 方法?

【问题讨论】:

  • 你应该使用SDK。
  • @AaronMcIver 抱歉,我的问题很模糊。我添加了更多信息
  • 你想做什么?你能在这里写下你的用例吗?
  • 我认为您需要做的是进行接口/工厂设计,以适应各种云存储提供商 SDK 实现。请检查您没有侵犯他们的任何专利,例如David Ebbo's Microsoft Patents - 您尝试做的事情听起来像是一项非常酷的技术开发!祝你好运!!

标签: c# amazon-s3


【解决方案1】:

嘿,我也支持这个问题,我通过实现流解决了它。

这是我的做法,也许有帮助:

public static Stream OpenStream(S3TransferUtility transferUtility, string key)
    {                     
        byte[] buffer  = new byte[Buffersize + Buffersize/2];

        S3CopyMemoryStream s3CopyStream =
            new S3CopyMemoryStream(key, buffer, transferUtility)
            .WithS3CopyFileStreamEvent(CreateMultiPartS3Blob);

        return s3CopyStream;
    }

我的带有构造函数的 Stream 覆盖了 close 和 write(array, offset, count) 方法,并将流部分上传到 amazon s3。

public class S3CopyMemoryStream : MemoryStream
    {

        public S3CopyMemoryStream WithS3CopyFileStreamEvent(StartUploadS3CopyFileStreamEvent doing)
        {
            S3CopyMemoryStream s3CopyStream = new S3CopyMemoryStream(this._key, this._buffer, this._transferUtility);

            s3CopyStream.StartUploadS3FileStreamEvent = new S3CopyMemoryStream.StartUploadS3CopyFileStreamEvent(CreateMultiPartS3Blob);

            return s3CopyStream;
        }

        public S3CopyMemoryStream(string key, byte[] buffer, S3TransferUtility transferUtility)
            : base(buffer)
        {
            if (buffer.LongLength > int.MaxValue)
                throw new ArgumentException("The length of the buffer may not be longer than int.MaxValue", "buffer");

            InitiatingPart = true;
            EndOfPart = false;
            WriteCount = 1;
            PartETagCollection = new List<PartETag>();

            _buffer = buffer;
            _key = key;
            _transferUtility = transferUtility;
        }

StartUploadS3FileStreamEvent 事件调用一个调用,该调用启动、上传部分并完成上传。

或者,您可以实现一个更容易的 FileStream,因为您可以使用

TransferUtilityUploadRequest request =
            new TransferUtilityUploadRequest()
            .WithAutoCloseStream(false).WithBucketName(
                transferUtility.BucketName)
                .WithKey(key)
                .WithPartSize(stream.PartSize)
                .WithInputStream(stream) as TransferUtilityUploadRequest;

        transferUtility.Upload(request);

在被覆盖的 FileStream 的 close 方法中。缺点是必须先将数据全部写入磁盘,然后才能上传。

【讨论】:

  • 抱歉回复晚了,但我很好奇 close 和 write 方法的实现是什么样子的。我已经设法上传了一个文件,但是我的测试文件的内容像这样被损坏了cl.ly/Lbcn
  • 你想做什么?类:Memorystream 还是类:FileStream?使用 Multipart API 或 TransferUtility 接口?还是您尝试异步上传?您使用流还是文件路径?也许您必须寻找流直到开始然后上传?
  • 我用 Google 搜索了 CreateMultiPartS3Blob 并找到了你的另一篇帖子 stackoverflow.com/questions/13604916/…,我在那里得到了答案,将位置设置为 0 解决了我的问题。我使用与您的帖子中几乎相同的实现,并且效果很好。似乎您的代码中有一个固定的缓冲区,或者您是否使用文件的大小作为缓冲区长度?我在write方法中引用了这行代码if(Position >= Buffersize)。
  • 这是一个固定的相应可配置缓冲区大小。目前为 9MB。考虑一个 2GB 的文件。那么内存的缓冲区是2GB。我认为这有点太多了。 !编辑:我的解决方案是可以改进的。这不是最终版本。
猜你喜欢
  • 2010-12-03
  • 1970-01-01
  • 1970-01-01
  • 2013-10-03
  • 2014-05-07
  • 1970-01-01
  • 2011-05-13
  • 2020-05-09
  • 2021-09-10
相关资源
最近更新 更多