チェンジセット 1692 (default)


以下の違いを無視:
日時:
2024/10/02 22:41:28 (4日前)
更新者:
hizuya@…
ログメッセージ:
  • ストリームからバッファに読み込む為の IOUtility.Fill メソッドを追加。
  • ストリームから残りの全てのデータを返す IOUtility.ReadToEnd メソッドを追加。
場所:
framework/trunk
ファイル:
2個の更新

凡例:

未変更
追加
削除
  • framework/trunk/CoreLibrary/Sources/IO/IOUtility.cs

    r1690 r1692  
    11371137        /// I/O エラーが発生しました。 
    11381138        /// </exception> 
     1139        [Obsolete("Use ReadToEnd()", false)] 
    11391140        public static byte[] ReadAll(Stream stream) 
    11401141        { 
    1141             // 引数をチェック 
    1142             if (stream == null) 
    1143             { 
    1144                 throw new ArgumentNullException("stream"); 
    1145             } 
    1146  
    1147             const int BufferSize = 0x2000; 
    1148  
    1149             using (MemoryStream memoryStream = new MemoryStream()) 
    1150             { 
    1151                 int readLength; 
    1152                 byte[] buffer = new byte[BufferSize]; 
    1153                 while ((readLength = stream.Read(buffer, 0, BufferSize)) > 0) 
    1154                 { 
    1155                     memoryStream.Write(buffer, 0, readLength); 
    1156                 } 
    1157  
    1158                 return memoryStream.ToArray(); 
    1159             } 
     1142            return ReadToEnd(stream); 
    11601143        } 
    11611144 
     
    13761359                        length)); 
    13771360            } 
     1361        } 
     1362 
     1363        /// <summary> 
     1364        /// ストリームからバイトシーケンスを読み取り、読み取ったバイト数の分だけストリームの位置を進めます。 
     1365        /// </summary> 
     1366        /// <param name="stream">読み取るストリーム。</param> 
     1367        /// <param name="buffer"> 
     1368        /// バイト配列。このメソッドが戻るとき、指定したバイト配列の <paramref name="offset"/> 
     1369        /// から (<paramref name="offset"/> + <paramref name="count"/> -1) までの値が、 
     1370        /// 現在のソースから読み取られたバイトに置き換えられます。 
     1371        /// </param> 
     1372        /// <param name="offset"> 
     1373        /// 読み取ったデータの格納を開始する位置を示す 
     1374        /// <paramref name="buffer"/> 内のバイト オフセット。インデックス番号は <c>0</c> から始まります。 
     1375        /// </param> 
     1376        /// <param name="count">現在のストリームから読み取るバイト数。</param> 
     1377        /// <returns> 
     1378        /// ストリームから読み取り <paramref name="buffer"/> に格納したバイト数。 
     1379        /// </returns> 
     1380        /// <exception cref="ArgumentNullException"> 
     1381        /// <paramref name="stream"/> または 
     1382        /// <paramref name="buffer"/> が <see langword="null"/> です。 
     1383        /// </exception> 
     1384        /// <exception cref="ArgumentOutOfRangeException"> 
     1385        /// <paramref name="offset"/> または 
     1386        /// <paramref name="count"/> が負の値です。 
     1387        /// </exception> 
     1388        /// <exception cref="ArgumentException"> 
     1389        /// <paramref name="offset"/> と <paramref name="count"/> が 
     1390        /// <paramref name="buffer"/> の無効な範囲を示しています。 
     1391        /// </exception> 
     1392        /// <exception cref="IOException"> 
     1393        /// I/O エラーが発生しました。 
     1394        /// </exception> 
     1395        public static int Fill(Stream stream, byte[] buffer, int offset, int count) 
     1396        { 
     1397            // ReSharper disable once ExceptionNotDocumented 
     1398            return Fill(stream, buffer, offset, count, false); 
     1399        } 
     1400 
     1401        /// <summary> 
     1402        /// ストリームからバイトシーケンスを読み取り、読み取ったバイト数の分だけストリームの位置を進めます。 
     1403        /// </summary> 
     1404        /// <param name="stream">読み取るストリーム。</param> 
     1405        /// <param name="buffer"> 
     1406        /// バイト配列。このメソッドが戻るとき、指定したバイト配列の <paramref name="offset"/> 
     1407        /// から (<paramref name="offset"/> + <paramref name="count"/> -1) までの値が、 
     1408        /// 現在のソースから読み取られたバイトに置き換えられます。 
     1409        /// </param> 
     1410        /// <param name="offset"> 
     1411        /// 読み取ったデータの格納を開始する位置を示す 
     1412        /// <paramref name="buffer"/> 内のバイト オフセット。インデックス番号は <c>0</c> から始まります。 
     1413        /// </param> 
     1414        /// <param name="count">現在のストリームから読み取るバイト数。</param> 
     1415        /// <param name="throwOnNotEnough"> 
     1416        /// <paramref name="count"/> で指定したバイト数分だけ読み込む前にストリームの末尾に達した時に例外を投げる場合は <see langword="true"/>。 
     1417        /// それ以外の場合は <see langword="false"/>。 
     1418        /// </param> 
     1419        /// <returns> 
     1420        /// ストリームから読み取り <paramref name="buffer"/> に格納したバイト数。 
     1421        /// </returns> 
     1422        /// <exception cref="ArgumentNullException"> 
     1423        /// <paramref name="stream"/> または 
     1424        /// <paramref name="buffer"/> が <see langword="null"/> です。 
     1425        /// </exception> 
     1426        /// <exception cref="ArgumentOutOfRangeException"> 
     1427        /// <paramref name="offset"/> または 
     1428        /// <paramref name="count"/> が負の値です。 
     1429        /// </exception> 
     1430        /// <exception cref="ArgumentException"> 
     1431        /// <paramref name="offset"/> と <paramref name="count"/> が 
     1432        /// <paramref name="buffer"/> の無効な範囲を示しています。 
     1433        /// </exception> 
     1434        /// <exception cref="IOException"> 
     1435        /// I/O エラーが発生しました。 
     1436        /// </exception> 
     1437        /// <exception cref="EndOfStreamException"> 
     1438        /// <paramref name="throwOnNotEnough"/> に <see langword="true"/> が指定されていて 
     1439        /// <paramref name="count"/> を読み込む前にストリームの末尾に達しました。 
     1440        /// </exception> 
     1441        public static int Fill(Stream stream, byte[] buffer, int offset, int count, bool throwOnNotEnough) 
     1442        { 
     1443            // 引数をチェック 
     1444            if (stream == null) 
     1445            { 
     1446                throw new ArgumentNullException("stream"); 
     1447            } 
     1448 
     1449 
     1450            if (buffer == null) 
     1451            { 
     1452                throw new ArgumentNullException("buffer"); 
     1453            } 
     1454 
     1455            if (offset < 0) 
     1456            { 
     1457                throw new ArgumentOutOfRangeException( 
     1458                    "offset", 
     1459                    offset, 
     1460                    Resources.ArgumentOutOfRange_NeedNonNegNum); 
     1461            } 
     1462 
     1463            if (count < 0) 
     1464            { 
     1465                throw new ArgumentOutOfRangeException( 
     1466                    "count", 
     1467                    count, 
     1468                    Resources.ArgumentOutOfRange_NeedNonNegNum); 
     1469            } 
     1470 
     1471            if (buffer.Length - offset < count) 
     1472            { 
     1473                throw new ArgumentException( 
     1474                    Resources.Argument_InvalidOffLen); 
     1475            } 
     1476 
     1477            if (count == 0) 
     1478            { 
     1479                return 0; 
     1480            } 
     1481 
     1482            int remainingCount = count; 
     1483            for (;;) 
     1484            { 
     1485                int readLength; 
     1486                if ((readLength = stream.Read(buffer, offset, remainingCount)) == 0) 
     1487                { 
     1488                    if (throwOnNotEnough) 
     1489                    { 
     1490                        throw new EndOfStreamException(); 
     1491                    } 
     1492 
     1493                    return count - remainingCount; 
     1494                } 
     1495 
     1496                // 全て読み込んだ場合 
     1497                if (readLength == remainingCount) 
     1498                { 
     1499                    return count; 
     1500                } 
     1501 
     1502                offset += readLength; 
     1503                remainingCount -= readLength; 
     1504            } 
     1505        } 
     1506 
     1507        /// <summary> 
     1508        /// ストリームの末尾まで読み取りバイト配列で返します。 
     1509        /// </summary> 
     1510        /// <param name="stream">読み込むストリーム。</param> 
     1511        /// <returns> 
     1512        /// 末尾まででのデータを格納したバイト配列。 
     1513        /// </returns> 
     1514        /// <exception cref="ArgumentNullException"> 
     1515        /// <paramref name="stream"/> が <see langword="null"/> です。 
     1516        /// </exception> 
     1517        /// <exception cref="IOException"> 
     1518        /// I/O エラーが発生しました。 
     1519        /// </exception> 
     1520        public static byte[] ReadToEnd(Stream stream) 
     1521        { 
     1522            return ReadToEnd(stream, int.MaxValue, 0x1000); 
     1523        } 
     1524 
     1525        /// <summary> 
     1526        /// ストリームの末尾まで読み取りバイト配列で返します。 
     1527        /// </summary> 
     1528        /// <param name="stream">読み込むストリーム。</param> 
     1529        /// <param name="limitSize">読み取り可能な最大のバイト数。</param> 
     1530        /// <param name="blockSize">読み込む時に使用するブロックサイズ。</param> 
     1531        /// <returns> 
     1532        /// 末尾まででのデータを格納したバイト配列。 
     1533        /// </returns> 
     1534        /// <exception cref="ArgumentNullException"> 
     1535        /// <paramref name="stream"/> が <see langword="null"/> です。 
     1536        /// </exception> 
     1537        /// <exception cref="ArgumentOutOfRangeException"> 
     1538        /// <paramref name="limitSize"/> が 0 未満、または 
     1539        /// <paramref name="blockSize"/> が 1 未満です。 
     1540        /// </exception> 
     1541        /// <exception cref="IOException"> 
     1542        /// I/O エラーが発生しました。 
     1543        /// </exception> 
     1544        public static byte[] ReadToEnd(Stream stream, int limitSize, int blockSize) 
     1545        { 
     1546            // 引数をチェック 
     1547            if (stream == null) 
     1548            { 
     1549                throw new ArgumentNullException("stream"); 
     1550            } 
     1551 
     1552            if (limitSize < 0) 
     1553            { 
     1554                throw new ArgumentOutOfRangeException( 
     1555                    "limitSize", 
     1556                    limitSize, 
     1557                    Resources.ArgumentOutOfRange_NeedNonNegNum); 
     1558            } 
     1559 
     1560            if (blockSize <= 0) 
     1561            { 
     1562                throw new ArgumentOutOfRangeException( 
     1563                    "blockSize", 
     1564                    blockSize, 
     1565                    string.Format( 
     1566                        CultureInfo.CurrentCulture, 
     1567                        Resources.ArgumentOutOfRange_MustBeOneOrGreater, 
     1568                        "blockSize")); 
     1569            } 
     1570 
     1571            // リミットが 0 の場合は読み込まずに返す 
     1572            if (limitSize == 0) 
     1573            { 
     1574                return new byte[0]; 
     1575            } 
     1576 
     1577            // ブロックサイズよりリミットの方が小さい場合は、ブロックサイズをリミットに合わせる 
     1578            if (limitSize < blockSize) 
     1579            { 
     1580                blockSize = limitSize; 
     1581            } 
     1582 
     1583            int bufferLength = blockSize; 
     1584            byte[] buffer = new byte[bufferLength]; 
     1585            int offset = 0; 
     1586            int readLength; 
     1587            while ((readLength = stream.Read(buffer, offset, blockSize)) != 0) 
     1588            { 
     1589                offset += readLength; 
     1590 
     1591                // リミットまで読み込んだ場合 
     1592                if (offset == limitSize) 
     1593                { 
     1594                    Debug.Assert(bufferLength == limitSize, "Invalid buffer size"); 
     1595                    return buffer; 
     1596                } 
     1597 
     1598                // 残りの部分に読み込める場合 
     1599                if (bufferLength - offset >= blockSize) 
     1600                { 
     1601                    continue; 
     1602                } 
     1603 
     1604                int newBufferLength; 
     1605                if (limitSize - bufferLength >= bufferLength) 
     1606                { 
     1607                    // 2 倍に拡張 
     1608                    newBufferLength = bufferLength * 2; 
     1609                } 
     1610                else if (bufferLength < limitSize) 
     1611                { 
     1612                    // 2 倍までは拡張できない場合は、全体で limitSize になるようにする 
     1613                    newBufferLength = limitSize; 
     1614 
     1615                    // 読み込み可能な残りのサイズがブロックサイズより小さい場合は、ブロックサイズを残りのサイズに合わせる 
     1616                    if (newBufferLength - offset < blockSize) 
     1617                    { 
     1618                        blockSize = newBufferLength - offset; 
     1619                    } 
     1620                } 
     1621                else 
     1622                { 
     1623                    // これ以上拡張できない場合 
     1624 
     1625                    // 読み込み可能な残りのサイズがブロックサイズより小さい場合は、ブロックサイズを残りのサイズに合わせる 
     1626                    if (bufferLength - offset < blockSize) 
     1627                    { 
     1628                        blockSize = bufferLength - offset; 
     1629                    } 
     1630 
     1631                    continue; 
     1632                } 
     1633 
     1634                // バッファを拡張 
     1635                byte[] newBuffer = new byte[newBufferLength]; 
     1636                Buffer.BlockCopy(buffer, 0, newBuffer, 0, offset); 
     1637                buffer = newBuffer; 
     1638                bufferLength = newBufferLength; 
     1639            } 
     1640 
     1641            // ストリームの末尾に達した場合は、バッファの末尾には必ず余りがあるので削除 
     1642            byte[] resultBuffer = new byte[offset]; 
     1643            Buffer.BlockCopy(buffer, 0, resultBuffer, 0, offset); 
     1644            return resultBuffer; 
    13781645        } 
    13791646 
  • framework/trunk/CoreTest/Sources/IO/IOUtilityTest.cs

    r1690 r1692  
    2929    using System.Globalization; 
    3030    using System.IO; 
     31    using System.Linq; 
    3132    using System.Text; 
    3233    using FCSoft.SilverFrost.Framework.Security; 
     34    using FCSoft.SilverFrost.Framework.Test; 
    3335    using FCSoft.SilverFrost.Framework.Text; 
    3436    using FCSoft.SilverFrost.Framework.UnitTest; 
     
    772774 
    773775        /// <summary> 
     776        /// <see cref="IOUtility.Fill(System.IO.Stream,byte[],int,int)"/> をテストします。 
     777        /// </summary> 
     778        /// <param name="bufferSize">読み込む時に使用するバッファサイズ。</param> 
     779        /// <param name="maxReadSize">一度に読める最大サイズ。</param> 
     780        [Test] 
     781        [TestCase(0, 4)] 
     782        [TestCase(1, 4)] 
     783        [TestCase(2, 4)] 
     784        [TestCase(3, 4)] 
     785        [TestCase(4, 4)] 
     786        [TestCase(5, 4)] 
     787        [TestCase(6, 4)] 
     788        [TestCase(7, 4)] 
     789        [TestCase(8, 4)] 
     790        [TestCase(9, 4)] 
     791        [TestCase(16, 4)] 
     792        [TestCase(16, 16)] 
     793        [TestCase(20, 4)] 
     794        [TestCase(20, 16)] 
     795        public void TestFill(int bufferSize, int maxReadSize) 
     796        { 
     797            byte[] sourceData = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x8, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F }; 
     798 
     799            using (MemoryStream memoryStream = new MemoryStream(sourceData, false)) 
     800            { 
     801                using (ReadSizeLimitedStream readSizeLimitedStream = new ReadSizeLimitedStream(memoryStream, maxReadSize)) 
     802                { 
     803                    byte[] buffer = new byte[bufferSize + 2]; 
     804                    for (int i = 0; i < buffer.Length; i++) 
     805                    { 
     806                        buffer[i] = 0xFF; 
     807                    } 
     808 
     809                    Assert.That( 
     810                        IOUtility.Fill(readSizeLimitedStream, buffer, 1, bufferSize), 
     811                        Is.EqualTo(Math.Min(bufferSize, sourceData.Length)), 
     812                        "Fill"); 
     813 
     814                    byte[] expectedData = new byte[bufferSize + 2]; 
     815                    for (int i = 0; i < buffer.Length; i++) 
     816                    { 
     817                        expectedData[i] = 0xFF; 
     818                    } 
     819 
     820                    Buffer.BlockCopy(sourceData, 0, expectedData, 1, Math.Min(bufferSize, sourceData.Length)); 
     821 
     822                    Assert.That(buffer, Is.EqualTo(expectedData), "Buffer"); 
     823                } 
     824            } 
     825        } 
     826 
     827        /// <summary> 
     828        /// <see cref="IOUtility.ReadToEnd(System.IO.Stream,int,int)"/> をテストします。 
     829        /// </summary> 
     830        /// <param name="limitSize">読み取り可能な最大のバイト数。</param> 
     831        /// <param name="blockSize">読み込む時に使用するブロックサイズ。</param> 
     832        /// <param name="maxReadSize">一度に読める最大サイズ。</param> 
     833        [Test] 
     834        [TestCase(0, 1, 4)] 
     835        [TestCase(1, 2, 4)] 
     836        [TestCase(2, 2, 4)] 
     837        [TestCase(3, 2, 4)] 
     838        [TestCase(4, 2, 4)] 
     839        [TestCase(5, 2, 4)] 
     840        [TestCase(6, 2, 4)] 
     841        [TestCase(7, 2, 4)] 
     842        [TestCase(8, 2, 4)] 
     843        [TestCase(9, 2, 4)] 
     844        [TestCase(1, 2, 1)] 
     845        [TestCase(2, 2, 1)] 
     846        [TestCase(3, 2, 1)] 
     847        [TestCase(4, 2, 1)] 
     848        [TestCase(5, 2, 1)] 
     849        [TestCase(6, 2, 1)] 
     850        [TestCase(7, 2, 1)] 
     851        [TestCase(8, 2, 1)] 
     852        [TestCase(9, 2, 1)] 
     853        [TestCase(1, 3, 2)] 
     854        [TestCase(2, 3, 2)] 
     855        [TestCase(3, 3, 2)] 
     856        [TestCase(4, 3, 2)] 
     857        [TestCase(5, 3, 2)] 
     858        [TestCase(6, 3, 2)] 
     859        [TestCase(7, 3, 2)] 
     860        [TestCase(8, 3, 2)] 
     861        [TestCase(9, 3, 2)] 
     862        public void TestReadToEnd(int limitSize, int blockSize, int maxReadSize) 
     863        { 
     864            byte[] sourceData = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x8, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F }; 
     865 
     866            using (MemoryStream memoryStream = new MemoryStream(sourceData, false)) 
     867            { 
     868                using (ReadSizeLimitedStream readSizeLimitedStream = new ReadSizeLimitedStream(memoryStream, maxReadSize)) 
     869                { 
     870                    byte[] resultData = IOUtility.ReadToEnd(readSizeLimitedStream, limitSize, blockSize); 
     871 
     872                    Assert.That(resultData, Is.EqualTo(sourceData.Take(limitSize).ToArray())); 
     873                } 
     874            } 
     875        } 
     876 
     877        /// <summary> 
    774878        /// <see cref="IOUtility.CreateCloseExceptionIgnorableTextWriter"/> をテストします。 
    775879        /// </summary> 
     
    868972            } 
    869973        } 
     974 
     975 
     976        /// <summary> 
     977        /// 一度に読み込める最大のサイズの制限があるストリームです。 
     978        /// </summary> 
     979        private sealed class ReadSizeLimitedStream : 
     980            FilterStream 
     981        { 
     982            /// <summary> 
     983            /// 一度に読み込める最大のサイズ。 
     984            /// </summary> 
     985            private readonly int maxReadSize; 
     986 
     987 
     988            /// <summary> 
     989            /// インスタンスを作成します。 
     990            /// </summary> 
     991            /// <param name="stream">元にするストリーム。</param> 
     992            /// <param name="maxReadSize">一度に読み込める最大のサイズ。</param> 
     993            internal ReadSizeLimitedStream(Stream stream, int maxReadSize) 
     994                : base(stream, true) 
     995            { 
     996                this.maxReadSize = maxReadSize; 
     997            } 
     998 
     999            /// <summary> 
     1000            /// 現在のストリームからバイト シーケンスを読み取り、読み取ったバイト数の分だけストリームの位置を進めます。 
     1001            /// </summary> 
     1002            /// <param name="buffer"> 
     1003            /// バイト配列。このメソッドが戻るとき、指定したバイト配列の 
     1004            /// <paramref name="offset"/> から 
     1005            /// (<paramref name="offset"/> + <paramref name="count"/> <c>-1</c>) までの値が、 
     1006            /// 現在のソースから読み取られたバイトに置き換えられます。 
     1007            /// </param> 
     1008            /// <param name="offset"> 
     1009            /// 現在のストリームから読み取ったデータの格納を開始する位置を示す 
     1010            /// <paramref name="buffer"/> 内のバイト オフセット。 
     1011            /// インデックス番号は <c>0</c> から始まります。 
     1012            /// </param> 
     1013            /// <param name="count"> 
     1014            /// 現在のストリームから読み取る最大バイト数。 
     1015            /// </param> 
     1016            /// <returns> 
     1017            /// バッファに読み取られた合計バイト数。 
     1018            /// 要求しただけのバイト数を読み取ることができなかった場合、 
     1019            /// この値は要求したバイト数より小さくなります。 
     1020            /// ストリームの末尾に到達した場合は <c>0</c> (ゼロ) になることがあります。 
     1021            /// </returns> 
     1022            /// <exception cref="ArgumentException"> 
     1023            /// <paramref name="offset"/> と <paramref name="count"/> の合計値が、バッファ長より大きい値です。 
     1024            /// </exception> 
     1025            /// <exception cref="ArgumentNullException"><paramref name="buffer"/> が <see langword="null"/> です。 
     1026            /// </exception> 
     1027            /// <exception cref="ArgumentOutOfRangeException"> 
     1028            /// <paramref name="offset"/> または <paramref name="count"/> が負の値です。 
     1029            /// </exception> 
     1030            /// <exception cref="IOException"> 
     1031            /// I/O エラーが発生しました。 
     1032            /// </exception> 
     1033            /// <exception cref="NotSupportedException"> 
     1034            /// ストリームが読み取りをサポートしていません。 
     1035            /// </exception> 
     1036            /// <exception cref="ObjectDisposedException"> 
     1037            /// ストリームが閉じられた後でメソッドが呼び出されました。 
     1038            /// </exception> 
     1039            public override int Read(byte[] buffer, int offset, int count) 
     1040            { 
     1041                return base.Read(buffer, offset, Math.Min(count, maxReadSize)); 
     1042            } 
     1043        } 
    8701044    } 
    8711045} 
詳しい使い方は TracChangeset を参照してください。