【问题标题】:Invalid character exception when adding Metadata to a CloudBlob将元数据添加到 CloudBlob 时出现无效字符异常
【发布时间】:2013-01-31 17:00:59
【问题描述】:

任务

使用原始文件名将文件上传到Azure Blob Storage,并将文件名作为meta-data 分配给CloudBlob

问题

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 中作为一种解决方法!

【问题讨论】:

  • 你应该使用blob.Properties.ContentDisposition=$"filename=\"{file.FileName}\"";保存文件名

标签: azure character-encoding azure-storage azure-blob-storage


【解决方案1】:

刚刚得到azure-sdk-for-net team on GitHub 的确认,只有ASCII 字符作为blob meta-data 中的数据有效。

乔格评论:
Blob 元数据中支持的字符必须是 ASCII 字符。解决方法 这您可以转义字符串(百分比编码)、base64 编码等。

Source on GitHub

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

  • 按照joeg 的建议转义字符串(百分比编码)、base64 编码等
  • 使用我在other answer 中提到的技术。

【讨论】:

    【解决方案2】:

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

    解决方法

    为了让它发挥作用,我结合使用以下方法:

    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 Burninator

    /// <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;
    }
    

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

    【讨论】:

      【解决方案3】:

      为了扩展 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 的实际文件名。

      【讨论】:

        【解决方案4】:

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

        var htmlEncodedValue = System.Web.HttpUtility.HtmlEncode(value)
        var originalValue = System.Web.HttpUtility.HtmlDecode(value)
        

        【讨论】:

        • 但这将如何帮助我搜索和索引文件?问题中提到了...
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-02-10
        • 2019-06-30
        • 1970-01-01
        相关资源
        最近更新 更多