继承类Stream的流并​​且可以序列化C#

时间:2011-09-09 08:21:33

标签: c# asp.net serialization stream

我有一个ASP.NET MVC应用程序(我也使用jQuery)。 我允许用户使用HttpPostedFileBase类上传文件。 然后,我使用类型InputStream的{​​{1}}属性将文件流保存到我拥有的某个数据库,在那里我首先对我的对象进行serislize。 Stream是可以分割的,所以这里没有问题。

问题在用户没有上传文件时开始,我想在这种情况下使用我在某处的另一个默认文件。 在这种情况下,一切都必须与第一种情况类似,所以最终我的数据库中会有一个Stream。所以我必须实例Stream并存储它。 Stream是抽象的,所以我不能实例Stream。相反,我使用了Stream,它继承了FileStream。问题是Stream不可分解,所以我遇到了问题。

我该如何解决?是否有另一个我可以使用的流继承FileStream并且可序列化?

2 个答案:

答案 0 :(得分:4)

不要序列化流存储;流是“软管”,而不是“桶”。相反,读取流并存储二进制数据(大多数数据库将具有二进制数据的数据类型,例如varbinary(max))。如果这是对象模型的一部分,我倾向于拥有byte[]属性(具有有意义的名称);这将作为模型的一部分轻松序列化。只需阅读流即可创建byte[];任务完成。例如:

public static byte[] ReadToEnd(this Stream s) {
    using(var ms = new MemoryStream()) {
        s.CopyTo(ms);
        return ms.ToArray();
    }
}

答案 1 :(得分:0)

JonMarc都有很好的答案。我更喜欢Marc's,因为您可以选择从流中顺序读取SQL层,而不是缓冲内存中的所有数据(这可能会导致OutOfMemoryException)。

但是,在基础级别,您正在接近这个错误。一般来说,SQL引擎真的不喜欢处理大的列值 - 它们的效率非常低。您可以使用另一个“数据库” - 您的文件系统。

通常,您将按如下方式定义数据库结构:

CREATE TABLE [dbo].[Files]
(
   [ID] INT IDENTITY(1,1) PRIMARY KEY NOT NULL,
   [Name] NVARCHAR(255) NOT NULL,
   [Storage] UNIQUEIDENTIFIER NOT NULL
);

在C#land中,您首先将文件写入磁盘,然后使用该标识符更新数据库:

/// <summary>
/// Writes a stream to a file and returns a <see cref="Guid"/> that
/// can be used to retrieve it again.
/// </summary>
/// <param name="incomingFile">The incoming file.</param>
/// <returns>The <see cref="Guid"/> that should be used to identify the file.</returns>
public static Guid WriteFile(Stream incomingFile)
{
    var path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "MyApplication");
    path = Path.Combine(path, "BinaryData");

    var guid = Guid.NewGuid();
    var ba = guid.ToByteArray();

    // Create the path for the GUID.
    path = Path.Combine(ba[0].ToString("x2"));
    path = Path.Combine(ba[1].ToString("x2"));
    path = Path.Combine(ba[2].ToString("x2"));
    Directory.CreateDirectory(path); // Always succeeds, even if the directory already exists.

    path = Path.Combine(guid.ToString() + ".dat");
    using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None))
    {
        var buffer = new byte[Environment.SystemPageSize];
        var length = 0;
        while ((length = incomingFile.Read(buffer, 0, buffer.Length)) != 0)
            fs.Write(buffer, 0, buffer.Length);
    }

    return guid;
}

/// <summary>
/// Deletes a file created by <see cref="WriteFile"/>.
/// </summary>
/// <param name="guid">The original <see cref="Guid"/> that was returned by <see cref="WriteFile"/>.</param>
public static void DeleteFile(Guid guid)
{
    var path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "MyApplication");
    path = Path.Combine(path, "BinaryData");

    var ba = guid.ToByteArray();

    // Create the path for the GUID.
    path = Path.Combine(ba[0].ToString("x2"));
    path = Path.Combine(ba[1].ToString("x2"));
    path = Path.Combine(ba[2].ToString("x2"));
    path = Path.Combine(guid.ToString() + ".dat");
    if (File.Exists(path))
        File.Delete(path);
}

/// <summary>
/// Reads the a file that was created by <see cref="WriteFile"/>.
/// </summary>
/// <param name="guid">The original <see cref="Guid"/> that was returned by <see cref="WriteFile"/>.</param>
/// <returns>The stream that can be used to read the file.</returns>
public static Stream ReadFile(Guid guid)
{
    var path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "MyApplication");
    path = Path.Combine(path, "BinaryData");

    var ba = guid.ToByteArray();

    // Create the path for the GUID.
    path = Path.Combine(ba[0].ToString("x2"));
    path = Path.Combine(ba[1].ToString("x2"));
    path = Path.Combine(ba[2].ToString("x2"));
    path = Path.Combine(guid.ToString() + ".dat");
    return new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
}

您还应调查Transactional NTFS以确保您的数据库和文件系统保持同步。在MsSQL中存储BLOB的效率低是Microsoft实现TxF的原因之一 - 所以你应该听取他们的建议 - 不要在SQL中存储BLOB / Files

备注:拥有嵌套文件夹(ba[0 through 2])对性能和文件系统限制都很重要 - 单个文件夹无法容纳大量文件。