如何在Azure存储文件共享中追加文件?

4

我想要将日志信息写入存储在Azure文件存储中的日志文件中。目前我有以下代码:

var log = "My log entry";

var client = _storageAccount.CreateCloudFileClient();
var share = client.GetShareReference(Config.LogShare);
share.CreateIfNotExists();
var root = share.GetRootDirectoryReference();
var logfile = root.GetFileReference("log.txt");
if (!logfile.Exists()) logfile.Create(0);

// What goes here to append to the file...?

我看到很多关于如何使用Blob的例子或者上传整个文件的示例,但是如何只追加到现有文件呢?

我尝试了以下方法:

var buffer = Encoding.GetEncoding("UTF-8").GetBytes(log.ToCharArray());

using (var fileStream = logfile.OpenWrite(0)) {
    fileStream.Write(buffer, (int)logfile.Properties.Length, buffer.Length);
}

但是我遇到了这个错误:

The remote server returned an error: (416) The range specified is invalid for the current size of the resource..
4个回答

5

我自己想出了解决方法。你只需要将文件大小增加到你想要写入的新字节数,然后将新数据写入文件末尾的这个新空间即可,操作如下:

var client = _storageAccount.CreateCloudFileClient();
var share = client.GetShareReference(Config.LogShare);
share.CreateIfNotExists();
var root = share.GetRootDirectoryReference();
var logfile = root.GetFileReference("log.txt");
if (!logfile.Exists()) logfile.Create(0);

var buffer = Encoding.UTF8.GetBytes($"{log}\r\n");

logfile.Resize(logfile.Properties.Length + buffer.Length);

using (var fileStream = logfile.OpenWrite(null)) {
    fileStream.Seek(buffer.Length * -1, SeekOrigin.End);
    fileStream.Write(buffer, 0, buffer.Length);
}

1
是的,这有点像“追加”,但实际上是通过1.调整大小,2.将数据写入新区域来完成的。追加应该是一种原子操作,直接追加数据并使文件大小变大。 :) - Zhaoxing Lu
fileStream.Seek(buffer.Length * -1, SeekOrigin.End); 这行代码出现了错误。"Azure.Storage.Files.Shares: 指定的方法不受支持。" - Chamika Goonetilaka

1
Azure文件存储REST API不支持追加到现有文件。为了实现这一点,请将文件共享挂载到您的计算机上作为驱动器,并像简单本地文件一样追加到文件中。
实际上,根据您上面的代码,我认为您并不真正需要追加功能。您可以在CloudFile.OpenWrite() / CloudFile.Create()中指定文件大小,或者尝试使用CloudFile.UploadFromStream()而不是CloudFile.OpenWrite()。

实际上,您可以添加...请查看我的答案 :) - BG100

1

1
看起来原始博客链接现在重定向到通用的Azure博客页面,但是这里有一篇关于更大的Azure存储的博客文章,提到了“附加Blob”和一个带有一些细节的文档页面 - patridge

0

这个错误也可能是由于多线程访问引起的。 我敢打赌,如果你在访问文件之前锁定它,你就不会遇到这个问题。 有很多方法可以更新文件。 既然你已经成功获取了共享、根目录、文件夹和文件... 这是我的一部分代码,对我有效。

if (!fileLock.IsWriteLockHeld) fileLock.EnterWriteLock();


        try
        {
            using (var stream = new MemoryStream(content, false))
            {
                file.UploadFromStream(stream, null, options);
            }
        }
        catch (Exception ex)
        {
            File.AppendAllText(FileName, ex.ToString());
        }
        finally
        {
            if (fileLock.IsWriteLockHeld)
                fileLock.ExitWriteLock();
        }

fileLock的声明位置如下:

  protected ReaderWriterLockSlim fileLock = new ReaderWriterLockSlim();

话虽如此,我并不是说这是最好的方法。 以下是两个需要记住的事项: 1-锁定可能被多个线程访问的资源(在AZURE中非常常见) 2-熟悉Azure提供的异步方法。在适当的时候使用它们。

回到您原来关于追加到现有文件的问题... 所有CloudFile的方法都会覆盖现有文件。Cloud Files不适合频繁写入,如果您经常在其上写入,它们确实会影响性能,再加上lock对性能的影响,它们将变得可怕。

Cloud files旨在一次性存储大量数据,如果您想添加另一个大块,则可以选择创建另一个文件。 将所有数据与客户端保持一致,直到它们达到某个大小,并创建一个算法来选择文件名并一次性上传它们。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接