Failed to write large amount of data to stream

前端 未结 2 671
甜味超标
甜味超标 2021-01-03 05:09

When I\'m trying to write very large amount of data (list with 300 000 rows and more) to memory stream using CsvHelper, it throws the exception \"System.IO.IOExcepti

相关标签:
2条回答
  • 2021-01-03 05:52

    Many thanks Spender, like he mentioned in the comment below the question, it has been fixed by replacing MemoryStream with FileStream and writing data direct into the file.

    It was absolutely useless in my case to write data to MemoryStream and then copy it again into the file without any reason. Thanks him again for opening my eyes on that fact.

    My fixed code below.

    using (var fileStream = File.Create(path))
    {
        using (var streamWriter = new StreamWriter(fileStream, encoding ?? Encoding.ASCII))
        {
            var csvWriter = new CsvWriter(streamWriter, GetConfiguration(delimiter, mappingClassType, mappingActions));
            csvWriter.WriteRecords(data);
        }
    }
    

    Now it works with any amount of input data.

    0 讨论(0)
  • 2021-01-03 05:56

    You can address this limitation of 2GB by writing your own MemoryStream :

        class HugeMemoryStream : Stream
        {
            #region Fields
    
            private const int PAGE_SIZE = 1024000;
            private const int ALLOC_STEP = 1024;
    
            private byte[][] _streamBuffers;
    
            private int _pageCount = 0;
            private long _allocatedBytes = 0;
    
            private long _position = 0;
            private long _length = 0;
    
            #endregion Fields
    
            #region Internals
    
            private int GetPageCount(long length)
            {
                int pageCount = (int)(length / PAGE_SIZE) + 1;
    
                if ((length % PAGE_SIZE) == 0)
                    pageCount--;
    
                return pageCount;
            }
    
            private void ExtendPages()
            {
                if (_streamBuffers == null)
                {
                    _streamBuffers = new byte[ALLOC_STEP][];
                }
                else
                {
                    byte[][] streamBuffers = new byte[_streamBuffers.Length + ALLOC_STEP][];
    
                    Array.Copy(_streamBuffers, streamBuffers, _streamBuffers.Length);
    
                    _streamBuffers = streamBuffers;
                }
    
                _pageCount = _streamBuffers.Length;
            }
    
            private void AllocSpaceIfNeeded(long value)
            {
                if (value < 0)
                    throw new InvalidOperationException("AllocSpaceIfNeeded < 0");
    
                if (value == 0)
                    return;
    
                int currentPageCount = GetPageCount(_allocatedBytes);
                int neededPageCount = GetPageCount(value);
    
                while (currentPageCount < neededPageCount)
                {
                    if (currentPageCount == _pageCount)
                        ExtendPages();
    
                    _streamBuffers[currentPageCount++] = new byte[PAGE_SIZE];
                }
    
                _allocatedBytes = (long)currentPageCount * PAGE_SIZE;
    
                value = Math.Max(value, _length);
    
                if (_position > (_length = value))
                    _position = _length;
            }
    
            #endregion Internals
    
            #region Stream
    
            public override bool CanRead => true;
    
            public override bool CanSeek => true;
    
            public override bool CanWrite => true;
    
            public override long Length => _length;
    
            public override long Position
            {
                get { return _position; }
                set
                {
                    if (value > _length)
                        throw new InvalidOperationException("Position > Length");
                    else if (value < 0)
                        throw new InvalidOperationException("Position < 0");
                    else
                        _position = value;
                }
            }
    
            public override void Flush() { }
    
            public override int Read(byte[] buffer, int offset, int count)
            {
                int currentPage = (int)(_position / PAGE_SIZE);
                int currentOffset = (int)(_position % PAGE_SIZE);
                int currentLength = PAGE_SIZE - currentOffset;
    
                long startPosition = _position;
    
                if (startPosition + count > _length)
                    count = (int)(_length - startPosition);
    
                while (count != 0 && _position < _length)
                {
                    if (currentLength > count)
                        currentLength = count;
    
                    Array.Copy(_streamBuffers[currentPage++], currentOffset, buffer, offset, currentLength);
    
                    offset += currentLength;
                    _position += currentLength;
                    count -= currentLength;
    
                    currentOffset = 0;
                    currentLength = PAGE_SIZE;
                }
    
                return (int)(_position - startPosition);
            }
    
            public override long Seek(long offset, SeekOrigin origin)
            {
                switch (origin)
                {
                    case SeekOrigin.Begin:
                        break;
    
                    case SeekOrigin.Current:
                        offset += _position;
                        break;
    
                    case SeekOrigin.End:
                        offset = _length - offset;
                        break;
    
                    default:
                        throw new ArgumentOutOfRangeException("origin");
                }
    
                return Position = offset;
            }
    
            public override void SetLength(long value)
            {
                if (value < 0)
                    throw new InvalidOperationException("SetLength < 0");
    
                if (value == 0)
                {
                    _streamBuffers = null;
                    _allocatedBytes = _position = _length = 0;
                    _pageCount = 0;
                    return;
                }
    
                int currentPageCount = GetPageCount(_allocatedBytes);
                int neededPageCount = GetPageCount(value);
    
                // Removes unused buffers if decreasing stream length
                while (currentPageCount > neededPageCount)
                    _streamBuffers[--currentPageCount] = null;
    
                AllocSpaceIfNeeded(value);
    
                if (_position > (_length = value))
                    _position = _length;
            }
    
            public override void Write(byte[] buffer, int offset, int count)
            {
                int currentPage = (int)(_position / PAGE_SIZE);
                int currentOffset = (int)(_position % PAGE_SIZE);
                int currentLength = PAGE_SIZE - currentOffset;
    
                long startPosition = _position;
    
                AllocSpaceIfNeeded(_position + count);
    
                while (count != 0)
                {
                    if (currentLength > count)
                        currentLength = count;
    
                    Array.Copy(buffer, offset, _streamBuffers[currentPage++], currentOffset, currentLength);
    
                    offset += currentLength;
                    _position += currentLength;
                    count -= currentLength;
    
                    currentOffset = 0;
                    currentLength = PAGE_SIZE;
                }
            }
    
            #endregion Stream
        }
    using ICSharpCode.SharpZipLib.GZip;
    using System;
    using System.IO;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    
                // HugeMemoryStrem Test
    
                string filename = @"gzip-filename.gz";
    
                HugeMemoryStream ms = new HugeMemoryStream();
    
                using (StreamWriter sw = new StreamWriter(ms, Encoding.UTF8, 16384, true))
                using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
                using (GZipInputStream gzipStream = new GZipInputStream(fs))
                using (StreamReader sr = new StreamReader(gzipStream, Encoding.UTF8, false, 16384, true))
                {
                    for (string line = sr.ReadLine(); line != null; line = sr.ReadLine())
                        sw.WriteLine(line);
                }
    
                ms.Seek(0, SeekOrigin.Begin);
    
                using (StreamReader srm = new StreamReader(ms, Encoding.UTF8, false, 16384, true))
                using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
                using (GZipInputStream gzipStream = new GZipInputStream(fs))
                using (StreamReader sr = new StreamReader(gzipStream, Encoding.UTF8, false, 16384, true))
                {
                    for (string line1 = sr.ReadLine(), line2 = srm.ReadLine(); line1 != null; line1 = sr.ReadLine(), line2 = srm.ReadLine())
                    {
                        if (line1 != line2)
                            throw new InvalidDataException();
                    }
                }
    
    0 讨论(0)
提交回复
热议问题