使用c#从NVarchar(Max)列流式传输数据

时间:2015-04-16 10:45:59

标签: c# sql-server database

我想将一些文件的内容放入数据库,以便通过单独的进程读取。这是一个两步的事情,因为文件将被上传到java服务器,但后来由一个定期运行的单独的c#应用程序处理。

我打算使用nvarchar(Max)列来表示数据,但我看不清楚如何以合理的方式从这种列中读取。我不想使用SqlDataReader.GetString,因为这将迫使我立即将所有数据保存在内存中。这些文件并不大,但这似乎是一个愚蠢的事情 - 它会把它作为一个单独的字符串,然后需要分成几行,所以整个方法将完全倒退。

我假设我只能使用普通的流阅读器,但是调用GetStream失败,说它不适用于这种类型的列。

有什么想法吗?是否只是更容易让数据库假装这不是真正的文本并将其存储为字节,以便我可以流式传输它?

1 个答案:

答案 0 :(得分:3)

我前段时间写了这个扩展方法:

public static class DataExtensions
{
    public static Stream GetStream(this IDataRecord record, int ordinal)
    {
        return new DbBinaryFieldStream(record, ordinal);
    }

    public static Stream GetStream(this IDataRecord record, string name)
    {
        int i = record.GetOrdinal(name);
        return record.GetStream(i);
    }

    private class DbBinaryFieldStream : Stream
    {
        private readonly IDataRecord _record;
        private readonly int _fieldIndex;
        private long _position;
        private long _length = -1;

        public DbBinaryFieldStream(IDataRecord record, int fieldIndex)
        {
            _record = record;
            _fieldIndex = fieldIndex;
        }

        public override bool CanRead
        {
            get { return true; }
        }

        public override bool CanSeek
        {
            get { return true; }
        }

        public override bool CanWrite
        {
            get { return false; }
        }

        public override void Flush()
        {
            throw new NotSupportedException();
        }

        public override long Length
        {
            get
            {
                if (_length < 0)
                {
                    _length = _record.GetBytes(_fieldIndex, 0, null, 0, 0);
                }
                return _length;
            }
        }

        public override long Position
        {
            get
            {
                return _position;
            }
            set
            {
                _position = value;
            }
        }

        public override int Read(byte[] buffer, int offset, int count)
        {
            long nRead = _record.GetBytes(_fieldIndex, _position, buffer, offset, count);
            _position += nRead;
            return (int)nRead;
        }

        public override long Seek(long offset, SeekOrigin origin)
        {
            long newPosition = _position;
            switch (origin)
            {
                case SeekOrigin.Begin:
                    newPosition = offset;
                    break;
                case SeekOrigin.Current:
                    newPosition = _position + offset;
                    break;
                case SeekOrigin.End:
                    newPosition = this.Length - offset;
                    break;
                default:
                    break;
            }
            if (newPosition < 0)
                throw new ArgumentOutOfRangeException("offset");
            _position = newPosition;
            return _position;
        }

        public override void SetLength(long value)
        {
            throw new NotSupportedException();
        }

        public override void Write(byte[] buffer, int offset, int count)
        {
            throw new NotSupportedException();
        }
    }
}

它是为BLOB设计的,但它也适用于NVARCHAR(最大)(至少在SQL Server上)。

你可以像这样使用它:

    using (var dataReader = command.ExecuteReader())
    {
        dataReader.Read();
        using (var stream = dataReader.GetStream("Text"))
        using (var streamReader = new StreamReader(stream))
        {
            // read the text using the StreamReader...
        }
    }
相关问题