21

任务

使用原始文件名上传文件,Azure Blob Storage并将文件名分配meta-dataCloudBlob

问题

名称中不允许使用这些字符,meta-data但可以接受这些字符blob

š Š ñ Ñ ç Ç ÿ Ÿ ž Ž Ð œ Œ « » éèëêð ÉÈËÊ àâä ÀÁÂÃÄÅ àáâãäå ÙÚÛÜ ùúûüµ òóôõöø ÒÓÔÕÖØ ìíîï ÌÍÎÏ

问题

  • 有没有办法将这些字符存储在meta-data? 我们是否缺少某些导致此异常的设置?
  • 这些字符中的大多数都是某些语言的标准字形,那么如何处理呢?
  • 是否有任何可用的文档可以提供有关此问题的建议?我找到blobmeta-data命名约定,但没有关于数据本身!

代码

var dirtyFileName      = file.FileName;
var normalizedFileName = file.FileName.CleanOffDiacriticAndNonASCII();

// Blob name accepts almost characters that are acceptable as filenames in Windows
var blob = container.GetBlobReference(dirtyFileName);

//Upload content to the blob, which will create the blob if it does not already exist.
blob.Metadata["FileName"] = normalizedFileName;
blob.Attributes.Properties.ContentType = file.ContentType;

// ERROR: Occurs here!
blob.UploadFromStream(file.InputStream);

blob.SetMetadata();
blob.SetProperties();

错误

例外

参考


解决方法

文件名中的非法字符只是冰山一角,仅为了这个问题而放大!更大的图景是我们使用索引这些文件Lucene.net,因此需要大量meta-data存储在blob. 请不要建议将它们全部单独存储在数据库中,只是不要!到目前为止,我们很幸运只遇到了一个带有变音符号的文件!

因此,目前我们正在努力避免将文件名保存在 中meta-data作为解决方法!

4

4 回答 4

18

刚刚azure-sdk-for-net在 GitHub 上得到团队的确认,只有ASCII字符在blob meta-data.

joeg 评论:
blob 元数据中支持的字符必须是 ASCII 字符。要解决此问题,您可以转义字符串(百分比编码)、base64 编码等。

来源在 GitHub

因此,作为一种解决方法,要么:

  • 按照joeg的建议,转义字符串(百分比编码)、base64 编码等
  • 使用我在其他答案中提到的技术。
于 2013-02-20T11:37:15.413 回答
8

除非我得到真正解决问题的答案,否则此解决方法是解决上述问题的方法!

解决方法

为了让它工作,我使用以下方法的组合:

  1. 将所有可能的字符转换为它们的 ascii/english 等价物
  2. 逃脱此清理的无效字符实际上已从字符串中删除

但这并不理想,因为我们正在丢失数据!

ASCII 变音符号

/// <summary>
/// Converts all Diacritic characters in a string to their ASCII equivalent
/// Courtesy: http://stackoverflow.com/a/13154805/476786
/// A quick explanation:
/// * Normalizing to form D splits charactes like è to an e and a nonspacing `
/// * From this, the nospacing characters are removed
/// * The result is normalized back to form C (I'm not sure if this is neccesary)
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static string ConvertDiacriticToASCII(this string value)
{
    if (value == null) return null;
    var chars =
        value.Normalize(NormalizationForm.FormD)
             .ToCharArray()
             .Select(c => new {c, uc = CharUnicodeInfo.GetUnicodeCategory(c)})
             .Where(@t => @t.uc != UnicodeCategory.NonSpacingMark)
             .Select(@t => @t.c);
    var cleanStr = new string(chars.ToArray()).Normalize(NormalizationForm.FormC);
    return cleanStr;
}

非 ASCII燃烧器

/// <summary>
/// Removes all non-ASCII characters from the string
/// Courtesy: http://stackoverflow.com/a/135473/476786
/// Uses the .NET ASCII encoding to convert a string. 
/// UTF8 is used during the conversion because it can represent any of the original characters. 
/// It uses an EncoderReplacementFallback to to convert any non-ASCII character to an empty string.
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static string RemoveNonASCII(this string value)
{
    string cleanStr = 
           Encoding.ASCII
                   .GetString(
                              Encoding.Convert(Encoding.UTF8,
                                               Encoding.GetEncoding(Encoding.ASCII.EncodingName,
                                                                    new EncoderReplacementFallback(string.Empty),
                                                                    new DecoderExceptionFallback()
                                                                    ),
                                               Encoding.UTF8.GetBytes(value)
                                               )
                              );
    return cleanStr;
}

我真的希望得到答案,因为解决方法显然并不理想,而且为什么这不可能也没有任何意义!

于 2013-02-15T16:51:51.737 回答
4

为了扩展 bPratik 的答案,我们发现 Base64 编码元数据效果很好。我们使用这种扩展方法进行编码和解码:

    public static class Base64Extensions
    {
        public static string ToBase64(this string input)
        {
            var bytes = Encoding.UTF8.GetBytes(input);
            return Convert.ToBase64String(bytes);
        }

        public static string FromBase64(this string input)
        {
            var bytes = Convert.FromBase64String(input);
            return Encoding.UTF8.GetString(bytes);
        }
    }

然后在设置 blob 元数据时:

blobReference.Metadata["Filename"] = filename.ToBase64();

并在检索它时:

var filename = blobReference.Metadata["Filename"].FromBase64();

对于搜索,您必须在将文件名呈现给索引器之前对其进行解码,或者假设您仍在使用原始文件名,则使用 blob 的实际文件名。

于 2016-09-07T07:53:50.737 回答
0

如果上面的列表很详尽,应该可以将元数据编码为 HTML,然后在需要时对其进行解码:

var htmlEncodedValue = System.Web.HttpUtility.HtmlEncode(value)
var originalValue = System.Web.HttpUtility.HtmlDecode(value)
于 2013-06-11T09:12:16.313 回答