2013-03-20T02:16:19の更新内容

programming/netfx/string/4_stringbuilder/index.wiki.txt

current previous
104,7 104,7
 
}}
}}
 
#tabpage-end
#tabpage-end
 

        

        
~
#prompt(実行結果){{
#prompt{{
 
String       : The quick brown fox jumps over the lazy dog
String       : The quick brown fox jumps over the lazy dog
 
StringBuilder: The quick brown fox jumps over the lazy dog
StringBuilder: The quick brown fox jumps over the lazy dog
 
Remove
Remove
158,17 158,13
 
}}
}}
 
#tabpage-end
#tabpage-end
 

        

        
~
#prompt(実行結果){{
#prompt{{
 
The quick brown fox jumps over the lazy dog
The quick brown fox jumps over the lazy dog
 
}}
}}
 

        

        
 
*StringBuilderと文字列操作
*StringBuilderと文字列操作
 
**文字列の結合 (Append, AppendLine, AppendFormat)
**文字列の結合 (Append, AppendLine, AppendFormat)
~
&msdn(netfx,member,System.Text.StringBuilder.Append){StringBuilder.Append};メソッドは、バッファに文字列を追加するメソッドで、String.Concatメソッドや加算演算子+による文字列の連結操作に相当します。
&msdn(netfx,member,System.Text.StringBuilder.Append){StringBuilder.Append};メソッドは、バッファに文字列を追加するメソッドで、String.Concatメソッドや加算演算子+による文字列の連結操作に相当します。 また、&msdn(netfx,member,System.Text.StringBuilder.AppendLine){StringBuilder.AppendLine};メソッドは、バッファに文字列を追加する点はAppendメソッドと同様ですが、自動的に末尾に改行文字も追加されます。 改行文字は常にEnvironment.NewLineが使われます。 &msdn(netfx,member,System.Text.StringBuilder.AppendFormat){StringBuilder.AppendFormat};メソッドは、指定された書式に整形してからバッファに追加するメソッドです。 String.Formatメソッドによる書式化と文字列の連結を同時に行う操作に相当します。
+

          
+
また、&msdn(netfx,member,System.Text.StringBuilder.AppendLine){StringBuilder.AppendLine};メソッドは、バッファに文字列を追加する点はAppendメソッドと同様ですが、自動的に末尾に改行文字も追加されます。 改行文字は''常にEnvironment.NewLineが使われます''。 AppendLineメソッドに引数を指定しなかった場合は、改行文字のみが追加されます。
+

          
+
&msdn(netfx,member,System.Text.StringBuilder.AppendFormat){StringBuilder.AppendFormat};メソッドは、指定された書式に整形してからバッファに追加するメソッドです。 String.Formatメソッドによる書式化と文字列の連結を同時に行う操作に相当します。 String.FormatメソッドやConsole.WriteLineメソッドなどと同様に[[書式指定子>programming/netfx/string_formatting/0_formatstrings]]を指定することができます。
 

        

        
 
#tabpage(C#)
#tabpage(C#)
 
#code(cs){{
#code(cs){{
250,7 246,7
 
}}
}}
 
#tabpage-end
#tabpage-end
 

        

        
~
#prompt(実行結果){{
#prompt{{
 
<>
<>
 
<The quick brown fox jumps>
<The quick brown fox jumps>
 
<The quick brown fox jumps over the lazy dog
<The quick brown fox jumps over the lazy dog
266,7 262,9
 
72 0072 72.0000>
72 0072 72.0000>
 
}}
}}
 

        

        
~
AppendFormatメソッドでは任意の引数を書式化して追加することが出来ますが、Appendメソッドでも文字列以外の値を追加することが出来ます。 この場合、引数として指定された値は既定の書式で自動的に文字列化されてから追加されます。
AppendLineメソッドに引数を指定しなかった場合は、改行文字のみが追加されます。 先に述べたとおり、改行文字は常にEnvironment.NewLineが追加されるので、実行環境によって改行文字が変わると不都合がある困る場合や、CRまたはLFのみを追加したいといった場合は、Appendメソッドを使う必要があります。
-

          
-
AppendFormatメソッドでは任意の引数を書式化して追加することが出来ますが、Appendメソッドでも文字列以外の値を追加することが出来ます。 この場合、引数として指定された値は自動的に文字列化されてから追加されます。
 

        

        
 
#tabpage(C#)
#tabpage(C#)
 
#code(cs){{
#code(cs){{
336,7 334,7
 
}}
}}
 
#tabpage-end
#tabpage-end
 

        

        
~
#prompt(実行結果){{
#prompt{{
 
<>
<>
 
<16
<16
 
>
>
349,88 347,6
 
>
>
 
}}
}}
 

        

        
+
***StringBuilderと改行文字
+
先に述べたとおり、AppendLineメソッドで追加される改行文字は''常にEnvironment.NewLineが使用されます''。 そのため、実行環境によって改行文字が変わると不都合がある困る場合や、CRまたはLFのみを追加したいといった場合は、AppendLineメソッドの代わりにAppendメソッドを使い、個別に改行文字を書き込む必要があります。
+

          
+
なお、[[StringWriterクラス>programming/netfx/string/5_stringreaderwriter]]を使うことにより、StringBuilderへの文字列の追加に際して任意の改行文字を使うようにすることができます。 &msdn(netfx,member,System.IO.StringWriter.NewLine){StreamWriter.NewLineプロパティ};を変更すると、書き込まれる改行文字を変更することができます。 次の例では、結果が分かりやすいように改行文字を"↵\r\n"に変更しています。 もちろん、改行文字にCRまたはLFのみを指定することもできます。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+
using System.Text;
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    StringBuilder sb = new StringBuilder(); // 空のStringBuilderを作成
+

          
+
    // StringBuilderに文字列を書き込むためのStringWriterを作成
+
    using (StringWriter writer = new StringWriter(sb))
+
    {
+
      // 改行文字を変更する
+
      writer.NewLine = "↵\r\n";
+

          
+
      // 改行文字を付けて文字列を書き込む
+
      writer.WriteLine("The quick brown fox jumps");
+
      writer.WriteLine("over the lazy dog");
+

          
+
      // 改行文字のみを書き込む
+
      writer.WriteLine();
+

          
+
      // 数値を書き込む
+
      writer.WriteLine(16);
+
      writer.WriteLine(Math.PI);
+
    }
+

          
+
    Console.WriteLine(sb);
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+
Imports System.Text
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim sb As New StringBuilder() ' 空のStringBuilderを作成
+

          
+
    ' StringBuilderに文字列を書き込むためのStringWriterを作成
+
    Using writer As New StringWriter(sb)
+
      ' 改行文字を変更する
+
      writer.NewLine = "↵" + vbCrLf
+

          
+
      ' 改行文字を付けて文字列を書き込む
+
      writer.WriteLine("The quick brown fox jumps")
+
      writer.WriteLine("over the lazy dog")
+

          
+
      ' 改行文字のみを書き込む
+
      writer.WriteLine()
+

          
+
      ' 数値を書き込む
+
      writer.WriteLine(16)
+
      writer.WriteLine(Math.PI)
+
    End Using
+

          
+
    Console.WriteLine(sb)
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
The quick brown fox jumps↵
+
over the lazy dog↵
+
+
16↵
+
3.14159265358979↵
+
}}
+

          
+
StringWriterクラスについて詳しくは[[programming/netfx/string/5_stringreaderwriter]]をご覧ください。
+

          
 
**文字列の挿入・削除・置換 (Insert, Remove, Replace)
**文字列の挿入・削除・置換 (Insert, Remove, Replace)
 
Stringクラスと同様、文字列の挿入・削除・置換には&msdn(netfx,member,System.Text.StringBuilder.Insert){StringBuilder.Insert};、&msdn(netfx,member,System.Text.StringBuilder.Remove){StringBuilder.Remove};、&msdn(netfx,member,System.Text.StringBuilder.Replace){StringBuilder.Replace};の各メソッドが使えます。 引数と動作はStringクラスのものとほぼ同じですが、InsertメソッドはAppendメソッド同様に文字列以外も追加出来ます。 なお、String.Removeメソッドとは異なり、StringBuilder.Removeメソッドでは削除する文字数を省略することは出来ません。
Stringクラスと同様、文字列の挿入・削除・置換には&msdn(netfx,member,System.Text.StringBuilder.Insert){StringBuilder.Insert};、&msdn(netfx,member,System.Text.StringBuilder.Remove){StringBuilder.Remove};、&msdn(netfx,member,System.Text.StringBuilder.Replace){StringBuilder.Replace};の各メソッドが使えます。 引数と動作はStringクラスのものとほぼ同じですが、InsertメソッドはAppendメソッド同様に文字列以外も追加出来ます。 なお、String.Removeメソッドとは異なり、StringBuilder.Removeメソッドでは削除する文字数を省略することは出来ません。
 

        

        
534,7 450,7
 
}}
}}
 
#tabpage-end
#tabpage-end
 

        

        
~
#prompt(実行結果){{
#prompt{{
 
<The quick brown fox jumps over the lazy dog>
<The quick brown fox jumps over the lazy dog>
 
<The brown fox jumps over the lazy dog>
<The brown fox jumps over the lazy dog>
 
<The brown fox jumps over the  dog>
<The brown fox jumps over the  dog>
594,7 510,7
 
}}
}}
 
#tabpage-end
#tabpage-end
 

        

        
~
#prompt(実行結果){{
#prompt{{
 
String       : <The quick brown fox jumps over the lazy dog>
String       : <The quick brown fox jumps over the lazy dog>
 
StringBuilder: <The quick brown fox jumps over the lazy dog>
StringBuilder: <The quick brown fox jumps over the lazy dog>
 
String       : <The fax jumps aver the 3 white dags>
String       : <The fax jumps aver the 3 white dags>
687,7 603,7
 
}}
}}
 
#tabpage-end
#tabpage-end
 

        

        
~
#prompt(実行結果){{
#prompt{{
 
<The quick brown fox jumps over the lazy dog> (Length=43)
<The quick brown fox jumps over the lazy dog> (Length=43)
 
<The quick brown fox jumps> (Length=25)
<The quick brown fox jumps> (Length=25)
 
<> (Length=0)
<> (Length=0)
768,7 684,7
 
}}
}}
 
#tabpage-end
#tabpage-end
 

        

        
~
#prompt(実行結果){{
#prompt{{
 
<The quick brown fox jumps over the lazy dog> (Length=43)
<The quick brown fox jumps over the lazy dog> (Length=43)
 
<> (Length=0)
<> (Length=0)
 
<The quick brown fox> (Length=19)
<The quick brown fox> (Length=19)
874,7 790,7
 
}}
}}
 
#tabpage-end
#tabpage-end
 

        

        
~
#prompt(実行結果){{
#prompt{{
 
(Length=0, Capacity=8) <>
(Length=0, Capacity=8) <>
 
(Length=19, Capacity=19) <The quick brown fox>
(Length=19, Capacity=19) <The quick brown fox>
 
(Length=19, Capacity=38) <The quick brown fox>
(Length=19, Capacity=38) <The quick brown fox>
952,7 868,7
 
}}
}}
 
#tabpage-end
#tabpage-end
 

        

        
~
#prompt(実行結果){{
#prompt{{
 
MaxCapacity: 32
MaxCapacity: 32
 
(Length=0, Capacity=24) <>
(Length=0, Capacity=24) <>
 
(Length=19, Capacity=24) <The quick brown fox>
(Length=19, Capacity=24) <The quick brown fox>

programming/netfx/tips/convert_struct_and_bytearray/index.wiki.txt

current previous
1,537 0,0
+
${smdncms:title,BinaryReader・BinaryWriterでの構造体の読み書き}
+
${smdncms:header_title,BinaryReader・BinaryWriterでの構造体の読み書き (構造体⇔バイト配列の変換)}
+
${smdncms:keywords,C#,VB.NET,struct,Structure,構造体,バイト配列,変換,Stream,BinaryReader,BinaryWriter,Marshal.StructureToPtr,Marshal.PtrToStructure,Marshal.GCAlloc,Marshal.AddrOfPinnedObject,BinaryFormatter}
+
${smdncms:tags,api/.net,lang/c#,lang/vb}
+
${smdncms:document_versions,codelang=cs,codelang=vb}
+

          
+
構造体とバイト配列の相互変換を行う方法、およびBinaryReader・BinaryWriterで構造体の読み書きを行う方法について。
+

          
+
-関連するページ
+
--[[programming/netfx/structlayout_fieldoffset]]
+
--[[programming/netfx/stream]]
+
---[[programming/netfx/stream/3_binaryreader_binarywriter]]
+
--[[programming/netfx/conversion]]
+
---[[programming/netfx/conversion/0_basetype]]
+
--[[programming/netfx/serialization]]
+
---[[programming/netfx/serialization/0_abstract]]
+
---[[programming/netfx/serialization/1_formatter]]
+

          
+
#googleadunit
+

          
+
.NET Frameworkでは任意の構造体とバイト配列を相互に変換するクラスやメソッドが用意されていない。 また、&msdn(netfx,type,System.IO.Stream){Stream};・&msdn(netfx,type,System.IO.BinaryReader){BinaryReader};・&msdn(netfx,type,System.IO.BinaryWriter){BinaryWriter};などのクラスも構造体の読み書きをサポートしていない。 そのため、以下で紹介するような方法を使って独自に実装する必要がある。
+

          
+
*Marshal.AllocHGlobal + Marshal.StructureToPtr/PtrToStructure [#ReadWriteStructWithAllocHGlobal]
+
この方法では、&msdn(netfx,member,System.Runtime.InteropServices.Marshal.AllocHGlobal){Marshal.AllocHGlobal};を使ってバイト配列の読み書きを行う領域を作成し、&msdn(netfx,member,System.Runtime.InteropServices.Marshal.Copy){Marshal.Copy};で構造体のバイト表現をコピーする。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+
using System.Runtime.InteropServices;
+

          
+
/// <summary>
+
/// ポインタを得るためにMarshal.AllocHGlobalでバイト配列のコピー用領域を作成し、
+
/// Marshal.PtrToStructure・Marshal.StructureToPtrで変換して構造体の読み書きを行う
+
/// </summary>
+
/// <remarks>参照型のフィールドを持つ構造体は読み書きできない</remarks>
+
static class ReadWriteStructWithAllocHGlobal {
+
  public static void WriteTo<TStruct>(BinaryWriter writer, TStruct s) where TStruct : struct
+
  {
+
    var size = Marshal.SizeOf(typeof(TStruct));
+
    var buffer = new byte[size];
+
    var ptr = IntPtr.Zero;
+

          
+
    try {
+
      ptr = Marshal.AllocHGlobal(size);
+

          
+
      Marshal.StructureToPtr(s, ptr, false);
+

          
+
      Marshal.Copy(ptr, buffer, 0, size);
+
    }
+
    finally {
+
      if (ptr != IntPtr.Zero)
+
        Marshal.FreeHGlobal(ptr);
+
    }
+

          
+
    writer.Write(buffer);
+
  }
+

          
+
  public static TStruct ReadFrom<TStruct>(BinaryReader reader) where TStruct : struct
+
  {
+
    var size = Marshal.SizeOf(typeof(TStruct));
+
    var ptr = IntPtr.Zero;
+

          
+
    try {
+
      ptr = Marshal.AllocHGlobal(size);
+

          
+
      Marshal.Copy(reader.ReadBytes(size), 0, ptr, size);
+

          
+
      return (TStruct)Marshal.PtrToStructure(ptr, typeof(TStruct));
+
    }
+
    finally {
+
      if (ptr != IntPtr.Zero)
+
        Marshal.FreeHGlobal(ptr);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+
Imports System.Runtime.InteropServices
+

          
+
''' <summary>
+
''' ポインタを得るためにMarshal.AllocHGlobalでバイト配列のコピー用領域を作成し、
+
''' Marshal.PtrToStructure・Marshal.StructureToPtrで変換して構造体の読み書きを行う
+
''' </summary>
+
''' <remarks>参照型のフィールドを持つ構造体は読み書きできない</remarks>
+
Module ReadWriteStructWithAllocHGlobal
+
  Public Sub WriteTo(Of TStruct As Structure)(ByVal writer As BinaryWriter, ByVal s As TStruct)
+
    Dim size As Integer = Marshal.SizeOf(GetType(TStruct))
+
    Dim buffer As Byte() = New Byte(size - 1) {}
+
    Dim ptr As IntPtr = IntPtr.Zero 
+

          
+
    Try
+
      ptr = Marshal.AllocHGlobal(size)
+

          
+
      Marshal.StructureToPtr(s, ptr, false)
+

          
+
      Marshal.Copy(ptr, buffer, 0, size)
+
    Finally
+
      If ptr <> IntPtr.Zero Then Marshal.FreeHGlobal(ptr)
+
    End Try
+

          
+
    writer.Write(buffer)
+
  End Sub
+

          
+
  Public Function ReadFrom(Of TStruct As Structure)(ByVal reader As BinaryReader) As TStruct
+
    Dim size As Integer = Marshal.SizeOf(GetType(TStruct))
+
    Dim ptr As IntPtr = IntPtr.Zero 
+

          
+
    Try
+
      ptr = Marshal.AllocHGlobal(size)
+

          
+
      Marshal.Copy(reader.ReadBytes(size), 0, ptr, size)
+

          
+
      Return DirectCast(Marshal.PtrToStructure(ptr, GetType(TStruct)), TStruct)
+
    Finally
+
      If ptr <> IntPtr.Zero Then Marshal.FreeHGlobal(ptr)
+
    End Try
+
  End Function
+
End Module
+
}}
+
#tabpage-end
+

          
+
*Marshal.GCAlloc + Marshal.StructureToPtr/PtrToStructure [#ReadWriteStructWithAllocGCHandle]
+
この方法では、Marshal.AllocHGlobalを使うかわりに&msdn(netfx,member,System.Runtime.InteropServices.GCHandle.Alloc){GCHandle.Alloc};を使うことで直接バイト配列のポインタを取得し、&msdn(netfx,member,System.Runtime.InteropServices.Marshal.PtrToStructure){Marshal.PtrToStructure};・&msdn(netfx,member,System.Runtime.InteropServices.Marshal.StructureToPtr){Marshal.StructureToPtr};で構造体に変換する。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+
using System.Runtime.InteropServices;
+

          
+
/// <summary>
+
/// ポインタを得るためにGCHandle.Allocでバイト配列のピニングを行い、
+
/// Marshal.PtrToStructure・Marshal.StructureToPtrで変換して構造体の読み書きを行う
+
/// </summary>
+
/// <remarks>参照型のフィールドを持つ構造体は読み書きできない</remarks>
+
static class ReadWriteStructWithAllocGCHandle {
+
  public static void WriteTo<TStruct>(BinaryWriter writer, TStruct s) where TStruct : struct
+
  {
+
    var buffer = new byte[Marshal.SizeOf(typeof(TStruct))];
+
    var handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
+

          
+
    try {
+
      Marshal.StructureToPtr(s, handle.AddrOfPinnedObject(), false);
+
    }
+
    finally {
+
      handle.Free();
+
    }
+

          
+
    writer.Write(buffer);
+
  }
+

          
+
  public static TStruct ReadFrom<TStruct>(BinaryReader reader) where TStruct : struct
+
  {
+
    var buffer = reader.ReadBytes(Marshal.SizeOf(typeof(TStruct)));
+
    var handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
+

          
+
    try {
+
      return (TStruct)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(TStruct));
+
    }
+
    finally {
+
      handle.Free();
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+

          
+
Imports System
+
Imports System.IO
+
Imports System.Runtime.InteropServices
+

          
+
''' <summary>
+
''' ポインタを得るためにGCHandle.Allocでバイト配列のピニングを行い、
+
''' Marshal.PtrToStructure・Marshal.StructureToPtrで変換して構造体の読み書きを行う
+
''' </summary>
+
''' <remarks>参照型のフィールドを持つ構造体は読み書きできない</remarks>
+
Module ReadWriteStructWithAllocGCHandle
+
  Public Sub WriteTo(Of TStruct As Structure)(ByVal writer As BinaryWriter, ByVal s As TStruct)
+
    Dim buffer As Byte() = New Byte(Marshal.SizeOf(GetType(TStruct)) - 1) {}
+
    Dim handle As GCHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned)
+

          
+
    Try
+
      Marshal.StructureToPtr(s, handle.AddrOfPinnedObject(), false)
+
    Finally
+
      handle.Free()
+
    End Try
+

          
+
    writer.Write(buffer)
+
  End Sub
+

          
+
  Public Function ReadFrom(Of TStruct As Structure)(ByVal reader As BinaryReader) As TStruct
+
    Dim buffer As Byte() = reader.ReadBytes(Marshal.SizeOf(GetType(TStruct)))
+
    Dim handle As GCHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned)
+

          
+
    Try
+
      Return DirectCast(Marshal.PtrToStructure(handle.AddrOfPinnedObject(), GetType(TStruct)), TStruct)
+
    Finally
+
      handle.Free()
+
    End Try
+
  End Function
+
End Module
+
}}
+
#tabpage-end
+

          
+
*ポインタのキャスト・代入 [#ReadWriteStructWithFixedPointer]
+
この方法では、Marshalクラスのメソッドは使わず、直接ポインタを操作してバイト配列と構造体の変換を行う。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+
using System.Runtime.InteropServices;
+

          
+
/// <summary>
+
/// fixedステートメントでポインタを取得し、
+
/// ポインタのキャスト・代入により構造体の読み書きを行う
+
/// </summary>
+
/// <remarks>参照型のフィールドを持つ構造体は読み書きできない</remarks>
+
static unsafe class ReadWriteStructWithFixedPointer {
+
  public static void WriteTo<TStruct>(BinaryWriter writer, TStruct s) where TStruct : struct
+
  {
+
    var buffer = new byte[Marshal.SizeOf(typeof(TStruct))];
+

          
+
    fixed (byte* ptr = buffer) {
+
      *((TStruct*)ptr) = s;
+
    }
+

          
+
    writer.Write(buffer);
+
  }
+

          
+
  public static TStruct ReadFrom<TStruct>(BinaryReader reader) where TStruct : struct
+
  {
+
    var buffer = reader.ReadBytes(Marshal.SizeOf(typeof(TStruct)));
+

          
+
    fixed (byte* ptr = buffer) {
+
      return *((TStruct*)ptr);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
(VBではポインタが使用できないためこの方法は使えない)
+
#tabpage-end
+

          
+
*BinaryFormatterによるシリアライズ・デシリアライズ [#ReadWriteStructWithBinaryFormatter]
+
この方法では、&msdn(netfx,type,System.Runtime.Serialization.Formatters.Binary.BinaryFormatter){BianryFormatter};でシリアライズすることで構造体のバイト表現を取得する。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+
using System.Runtime.Serialization.Formatters.Binary;
+

          
+
/// <summary>BianryFormatterを使って構造体の読み書きを行う</summary>
+
/// <remarks>
+
/// メモリ上のバイト表現とは異なるバイト表現で読み書きされる。
+
/// このメソッドで読み書きする構造体にはSerializableAttributeが付与されている必要がある。
+
/// </remarks>
+
static class ReadWriteStructWithBinaryFormatter {
+
  public static void WriteTo<TStruct>(BinaryWriter writer, TStruct s) where TStruct : struct
+
  {
+
    var formatter = new BinaryFormatter();
+

          
+
    formatter.Serialize(writer.BaseStream, s);
+
  }
+

          
+
  public static TStruct ReadFrom<TStruct>(BinaryReader reader) where TStruct : struct
+
  {
+
    var formatter = new BinaryFormatter();
+

          
+
    return (TStruct)formatter.Deserialize(reader.BaseStream);
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+
Imports System.Runtime.Serialization.Formatters.Binary
+

          
+
''' <summary>BianryFormatterを使って構造体の読み書きを行う</summary>
+
''' <remarks>
+
''' メモリ上のバイト表現とは異なるバイト表現で読み書きされる。
+
''' このメソッドで読み書きする構造体にはSerializableAttributeが付与されている必要がある。
+
''' </remarks>
+
Module ReadWriteStructWithBinaryFormatter
+
  Public Sub WriteTo(Of TStruct As Structure)(ByVal writer As BinaryWriter, ByVal s As TStruct)
+
    Dim formatter As New BinaryFormatter()
+

          
+
    formatter.Serialize(writer.BaseStream, s)
+
  End Sub
+

          
+
  Public Function ReadFrom(Of TStruct As Structure)(ByVal reader As BinaryReader) As TStruct
+
    Dim formatter As New BinaryFormatter()
+

          
+
    Return DirectCast(formatter.Deserialize(reader.BaseStream), TStruct)
+
  End Function
+
End Module
+
}}
+
#tabpage-end
+

          
+
*リフレクション [#ReadWriteStructWithReflection]
+
この方法では、構造体のバイト表現を直接取得するのではなく、構造体のフィールドをリフレクションによって取得し、フィールドに格納されている値を個別にバイト配列へと変換していく。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+
using System.Linq;
+
using System.Runtime.InteropServices;
+
using System.Reflection;
+

          
+
/// <summary>リフレクションとBitConverterクラスのバイト配列変換メソッドを使って構造体の読み書きを行う</summary>
+
/// <exception>フィールドの型がBitConverterでは変換できない型の場合はNotSupportedException</exception>
+
/// <remarks>
+
/// この実装は不完全で、フィールドが構造体の場合は再帰的に呼び出しを行うなどの処理を追加する必要がある。
+
/// </remarks>
+
static class ReadWriteStructWithReflection {
+
  public static void WriteTo<TStruct>(BinaryWriter writer, TStruct s) where TStruct : struct
+
  {
+
    var type = s.GetType();
+

          
+
    // TStructの全フィールドを取得して、フィールドのオフセット順に並べ替え
+
    var fields = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
+
                     .OrderBy(f => Marshal.OffsetOf(type, f.Name).ToInt64());
+

          
+
    foreach (var field in fields) {
+
      if (field.FieldType == typeof(byte)) {
+
        // フィールドがbyteなら、そのまま書き込む
+
        writer.Write((byte)field.GetValue(s));
+
      }
+
      else {
+
        // フィールドがbyte以外なら、BitConverter.GetBytesメソッドでbyte[]に変換して書き込む
+
        var getBytes = typeof(BitConverter).GetMethod("GetBytes", new[] {field.FieldType});
+

          
+
        if (getBytes == null)
+
          throw new NotSupportedException("unsupported field type: " + field.FieldType.FullName);
+

          
+
        writer.Write((byte[])getBytes.Invoke(null, new[] {field.GetValue(s)}));
+
      }
+
    }
+
  }
+

          
+
  public static TStruct ReadFrom<TStruct>(BinaryReader reader) where TStruct : struct
+
  {
+
    var type = typeof(TStruct);
+
    var ret = default(TStruct);
+
    object retBoxed = ret; // boxing
+

          
+
    // TStructの全フィールドを取得して、フィールドのオフセット順に並べ替え
+
    var fields = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
+
                     .OrderBy(f => Marshal.OffsetOf(type, f.Name).ToInt64());
+

          
+
    foreach (var field in fields) {
+
      if (field.FieldType == typeof(byte)) {
+
        // フィールドがbyteなら読み込んだ値をそのままフィールドの値とする
+
        field.SetValue(retBoxed, reader.ReadByte());
+
      }
+
      else {
+
        // フィールドがbyte以外なら、BitConverter.ToXXXメソッドで該当する型に変換した値をフィールドの値とする
+
        var toXXX = typeof(BitConverter).GetMethods(BindingFlags.Static | BindingFlags.Public)
+
                                        .Where(m => m.Name.StartsWith("To") && m.ReturnType == field.FieldType)
+
                                        .FirstOrDefault();
+

          
+
        if (toXXX == null)
+
          throw new NotSupportedException("unsupported field type: " + field.FieldType.FullName);
+

          
+
        var size = Marshal.SizeOf(field.FieldType);
+

          
+
        field.SetValue(retBoxed, toXXX.Invoke(null, new object[] {reader.ReadBytes(size), 0}));
+
      }
+
    }
+

          
+
    return (TStruct)retBoxed; // unboxing
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections.Generic
+
Imports System.IO
+
Imports System.Linq
+
Imports System.Runtime.InteropServices
+
Imports System.Reflection
+

          
+
''' <summary>リフレクションとBitConverterクラスのバイト配列変換メソッドを使って構造体の読み書きを行う</summary>
+
''' <exception>フィールドの型がBitConverterでは変換できない型の場合はNotSupportedException</exception>
+
''' <remarks>
+
''' この実装は不完全で、フィールドが構造体の場合は再帰的に呼び出しを行うなどの処理を追加する必要がある。
+
''' </remarks>
+
Module ReadWriteStructWithReflection
+
  Public Sub WriteTo(Of TStruct As Structure)(ByVal writer As BinaryWriter, ByVal s As TStruct)
+
    Dim type As Type = s.GetType()
+

          
+
    ' TStructの全フィールドを取得して、フィールドのオフセット順に並べ替え
+
    Dim fields As IEnumerable(Of FieldInfo) = _
+
      type.GetFields(BindingFlags.Instance Or BindingFlags.NonPublic Or BindingFlags.Public) _
+
          .OrderBy(Function (f As FieldInfo) Marshal.OffsetOf(type, f.Name).ToInt64())
+

          
+
    For Each field As FieldInfo In Fields
+
      If field.FieldType = GetType(Byte) Then
+
        ' フィールドがByteなら、そのまま書き込む
+
        writer.Write(CByte(field.GetValue(s)))
+
      Else
+
        ' フィールドがByte以外なら、BitConverter.GetBytesメソッドでByte()に変換して書き込む
+
        Dim getBytes As MethodInfo = GetType(BitConverter).GetMethod("GetBytes", New Type() {field.FieldType})
+

          
+
        If getBytes Is Nothing Then Throw New NotSupportedException("unsupported field type: " + field.FieldType.FullName)
+

          
+
        writer.Write(DirectCast(getBytes.Invoke(Nothing, New Object() {field.GetValue(s)}), Byte()))
+
      End If
+
    Next
+
  End Sub
+

          
+
  Public Function ReadFrom(Of TStruct As Structure)(ByVal reader As BinaryReader) As TStruct
+
    Dim type As Type = GetType(TStruct)
+
    Dim ret As New TStruct
+

          
+
    ' VBでボックス化相当の処理を行う
+
    Dim retValue As ValueType = ret
+

          
+
    ' TStructの全フィールドを取得して、フィールドのオフセット順に並べ替え
+
    Dim fields As IEnumerable(Of FieldInfo) = _
+
      type.GetFields(BindingFlags.Instance Or BindingFlags.NonPublic Or BindingFlags.Public) _
+
          .OrderBy(Function (f As FieldInfo) Marshal.OffsetOf(type, f.Name).ToInt64())
+

          
+
    For Each field As FieldInfo In Fields
+
      If field.FieldType = GetType(Byte) Then
+
        ' フィールドがByteなら読み込んだ値をそのままフィールドの値とする
+
        field.SetValue(retValue, reader.ReadByte())
+
      Else
+
        ' フィールドがByte以外なら、BitConverter.ToXXXメソッドで該当する型に変換した値をフィールドの値とする
+
        Dim toXXX As MethodInfo = _
+
          GetType(BitConverter).GetMethods(BindingFlags.Static Or BindingFlags.Public) _
+
                               .Where(Function(m As MethodInfo) m.Name.StartsWith("To") AndAlso m.ReturnType = field.FieldType) _
+
                               .FirstOrDefault()
+

          
+
        If toXXX Is Nothing Then Throw New NotSupportedException("unsupported field type: " + field.FieldType.FullName)
+

          
+
        Dim size As Integer = Marshal.SizeOf(field.FieldType)
+

          
+
        field.SetValue(retValue, toXXX.Invoke(Nothing, New Object() {reader.ReadBytes(size), 0}))
+
      End If
+
    Next
+

          
+
    Return DirectCast(retValue, TStruct)
+
  End Function
+
End Module
+
}}
+
#tabpage-end
+

          
+
関連ページ: [[programming/netfx/tips/set_struct_field_using_reflection]]
+

          
+
*使用例
+
ここまでで紹介した方法を実際に使用する例。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+
using System.Runtime.InteropServices;
+

          
+
class Sample {
+
  // 読み書きを行う構造体
+
  [StructLayout(LayoutKind.Sequential)]
+
  struct Date {
+
    public short Year;
+
    public byte Month;
+
    public byte Day;
+
  }
+

          
+
  static void Main()
+
  {
+
    // ファイルdump.binに構造体の内容を書き出す
+
    using (var writer = new BinaryWriter(File.OpenWrite("dump.bin"))) {
+
      var d = new Date();
+

          
+
      d.Year = 2013;
+
      d.Month = 4;
+
      d.Day = 1;
+

          
+
      ReadWriteStructWithAllocGCHandle.WriteTo(writer, d);
+
    }
+

          
+
    // ファイルdump.binから構造体の内容を読み込む
+
    using (var reader = new BinaryReader(File.OpenRead("dump.bin"))) {
+
      var d = ReadWriteStructWithAllocGCHandle.ReadFrom<Date>(reader);
+

          
+
      Console.WriteLine("{0}-{1}-{2}", d.Year, d.Month, d.Day);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+
Imports System.Runtime.InteropServices
+

          
+
Class Sample
+
  ' 読み書きを行う構造体
+
  <StructLayout(LayoutKind.Sequential)> _
+
  Structure MyDate
+
    Public Year As Short
+
    Public Month As Byte
+
    Public Day As Byte
+
  End Structure
+

          
+
  Shared Sub Main()
+
    ' ファイルdump.binに構造体の内容を書き出す
+
    Using writer As New BinaryWriter(File.OpenWrite("dump.bin"))
+
      Dim d As New MyDate()
+

          
+
      d.Year = 2013
+
      d.Month = 4
+
      d.Day = 1
+

          
+
      ReadWriteStructWithAllocGCHandle.WriteTo(writer, d)
+
    End Using
+

          
+
    ' ファイルdump.binから構造体の内容を読み込む
+
    Using reader As New BinaryReader(File.OpenRead("dump.bin"))
+
      Dim d As MyDate= ReadWriteStructWithAllocGCHandle.ReadFrom(Of MyDate)(reader)
+

          
+
      Console.WriteLine("{0}-{1}-{2}", d.Year, d.Month, d.Day)
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          

programming/netfx/tips/set_struct_field_using_reflection/index.wiki.txt

current previous
1,203 0,0
+
${smdncms:title,リフレクションを使って構造体フィールドに値を設定する(FieldInfo.SetValue)}
+
${smdncms:keywords,C#,VB,VB.NET,構造体,フィールド,FieldInfo.SetValue,ボックス化,ValueType,TypedReference,MakeTypedReference,SetValueDirect}
+
${smdncms:tags,lang/c#,lang/vb,api/.net}
+

          
+
&msdn(netfx,member,System.Reflection.FieldInfo.SetValue){FieldInfo.SetValueメソッド};を使って構造体のフィールドに値を設定する方法について。
+

          
+
-参考
+
--[[FieldInfoのSetValueメソッド - Insider.NET - @IT:http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=4186&forum=7]]
+
--[[RuntimeHelpers.GetObjectValue Discussion - Visual Basic .NET:http://bytes.com/topic/visual-basic-net/answers/543783-runtimehelpers-getobjectvalue-discussion]]
+
--&msdn(netfx,member,System.Runtime.CompilerServices.RuntimeHelpers.GetObjectValue);
+
-関連するページ
+
--[[programming/netfx/cloning]]
+
--[[programming/netfx/tips/convert_struct_and_bytearray]]
+

          
+
#googleadunit
+

          
+
メソッドに構造体(値型)のインスタンスを渡す場合、メソッドにはインスタンスのコピーが渡される(&msdn(netfx,id,8b0bdca4){方法 : メソッドに構造体を渡すこととクラス参照を渡すことの違いを理解する (C# プログラミング ガイド)};)。
+

          
+
FieldInfo.SetValueも同様で、構造体のインスタンスを渡してもフィールドの値が変更されるのはコピーされたインスタンスの方で、元のインスタンスの方ではない。 そのため、FieldInfo.SetValueに構造体インスタンスを指定しても、見た目上はフィールドの値が変更されないよう見える。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Reflection;
+

          
+
struct S {
+
  public int F;
+
}
+

          
+
class Test {
+
  public static void Main()
+
  {
+
    var s = new S();
+
    var f = s.GetType().GetField("F");
+

          
+
    // 構造体SのフィールドFに値42をセット
+
    f.SetValue(s, 42);
+

          
+
    // フィールドにセットされた値を表示
+
    Console.WriteLine(s.F);
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Reflection
+

          
+
Structure S
+
  Public F As Integer
+
End Structure
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim s As New S
+
    Dim f As FieldInfo = s.GetType().GetField("F")
+

          
+
    ' 構造体SのフィールドFに値42をセット
+
    f.SetValue(s, 42)
+

          
+
    ' フィールドにセットされた値を表示
+
    Console.WriteLine(s.F)
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
0
+
}}
+

          
+
FieldInfo.SetValueメソッドには参照渡し(ref/ByRef)を行うようなオーバーロードは用意されていないので、FieldInfo.SetValueメソッドで構造体フィールドの値を設定するにはなんらかの代替策を取る必要がある。
+

          
+
*ボックス化する
+
Object型に構造体インスタンスを代入することによりボックス化を行い、ボックス化したものをFieldInfo.SetValueメソッドに指定することで参照渡しする。 その後、ボックス化を解除して構造体型に戻す。
+

          
+
#code(cs){{
+
using System;
+
using System.Reflection;
+

          
+
struct S {
+
  public int F;
+
}
+

          
+
class Test {
+
  public static void Main()
+
  {
+
    var s = new S();
+
    var f = s.GetType().GetField("F");
+

          
+
    // 一旦構造体インスタンスをボックス化する
+
    object boxed = s;
+

          
+
    // ボックス化したインスタンスを渡してフィールドに値をセット
+
    f.SetValue(boxed, 42);
+

          
+
    // ボックス化を解除する
+
    s = (S)boxed;
+

          
+
    // フィールドにセットされた値を表示
+
    Console.WriteLine(s.F);
+
  }
+
}
+
}}
+

          
+
VB.NETでは、このような方法でボックス化することはできない。
+

          
+
*ValueTypeを使う
+
Object型に代入してボックス化するかわりに、一旦&msdn(netfx,type,System.ValueType){ValueTypeクラス};に変換してFieldInfo.SetValueメソッドに渡す。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Reflection;
+

          
+
struct S {
+
  public int F;
+
}
+

          
+
class Test {
+
  public static void Main()
+
  {
+
    var s = new S();
+
    var f = s.GetType().GetField("F");
+

          
+
    // 一旦インスタンスをValueTypeに変換する
+
    ValueType v = s;
+

          
+
    // 変換したインスタンスを渡してフィールドに値をセット
+
    f.SetValue(v, 42);
+

          
+
    // 元の構造体型に戻す
+
    s = (S)v;
+

          
+
    // フィールドにセットされた値を表示
+
    Console.WriteLine(s.F);
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Reflection
+

          
+
Structure S
+
  Public F As Integer
+
End Structure
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim s As New S
+
    Dim f As FieldInfo = s.GetType().GetField("F")
+

          
+
    ' 一旦インスタンスをValueTypeに変換する
+
    Dim v As ValueType = s
+

          
+
    ' 変換したインスタンスを渡してフィールドに値をセット
+
    f.SetValue(v, 42)
+

          
+
    ' 元の構造体型に戻す
+
    s = DirectCast(v, S)
+

          
+
    ' フィールドにセットされた値を表示
+
    Console.WriteLine(s.F)
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
42
+
}}
+

          
+
*FieldInfo.SetValueDirectメソッドを使う
+
FieldInfo.SetValueメソッドの代わりに、&msdn(netfx,member,System.Reflection.FieldInfo.SetValueDirect){FieldInfo.SetValueDirectメソッド};を使う。 FieldInfo.SetValueDirectメソッドでは、値を設定したいインスタンスを指定するかわりに、&msdn(netfx,type,System.TypedReference){TypedReference};を指定する。 C#では、隠しキーワード __makeref を使用することでTypedReferenceを取得することができる。
+

          
+
#code(cs){{
+
using System;
+
using System.Reflection;
+

          
+
struct S {
+
  public int F;
+
}
+

          
+
class Test {
+
  public static void Main()
+
  {
+
    var s = new S();
+
    var f = s.GetType().GetField("F");
+

          
+
    // __makerefキーワードを使って参照を取得し、SetValueDirectでフィールドに値をセット
+
    f.SetValueDirect(__makeref(s), 42);
+

          
+
    // フィールドにセットされた値を表示
+
    Console.WriteLine(s.F);
+
  }
+
}
+
}}
+

          
+
#prompt(実行結果){{
+
42
+
}}
+

          

programming/netfx/stream/0_abstract/index.wiki.txt

current previous
1,1682 0,0
+
${smdncms:title,ストリームの基本とStreamクラス}
+
${smdncms:header_title,Streamクラス (System.IO)}
+
${smdncms:keywords,読み込み,書き込み,IO,入出力,FileStream,MemoryStream,NetworkStream,Read,Write,Seek,Flush,Close,CopyTo,Position,Length}
+
${smdncms:document_versions,codelang=cs,codelang=vb}
+

          
+
#navi(..)
+

          
+
ここでは.NET Frameworkにおいてストリームを扱うクラスである&msdn(netfx,type,System.IO.Stream){Streamクラス};と、Streamクラスを使ったデータの読み書きといった操作について見ていきます。
+

          
+
-関連するページ
+
--[[programming/netfx/disposing]]
+
--[[programming/netfx/embeddedresource]]
+
--[[programming/netfx/serialization]]
+
--[[programming/netfx/tips/convert_struct_and_bytearray]]
+

          
+
#googleadunit
+

          
+
*ストリームとは
+
データストリーム、もしくは単に''ストリーム''とは、一言で言えば''ひとつながりのデータ列''のことを表します。 データにはその実体が存在する場所や、データが''流れて''くる経路によって様々なものがあります。 例えば、ディスク上のファイルから読み込まれるデータ、メモリ上から読み取られるデータ、ネットワークを経由して転送されてくるデータ、プロセスの標準入出力を経由して渡されるデータなどがありますが、そういった何らかの経路を経て流れてくるデータ列を総称してストリームと呼びます。
+

          
+
ストリームにおいて重要なのは、データがどのような経路から流れてくるのかといった点を抽象化し、特に''流れてくるデータ''だけに着目できるようにするという点です。 経路や実体を抽象化して単なるデータ列と捉えることにより、様々なデータに対する読み込み・書き込みの操作を画一的な方法で扱えるようになります。
+

          
+
*.NET FrameworkにおけるストリームとStreamクラス
+
.NET Frameworkでは、ストリームを扱うためのクラスとして&msdn(netfx,type,System.IO.Stream){Streamクラス};が用意されています。 Streamクラスは単にストリームを表すだけでなく、ストリームに対する読み込み・書き込み・シークといった操作が用意されています。
+

          
+
Streamクラスはすべてのストリームの基本となる抽象型で、より具体的なストリームはこのクラスから継承して実装されます。 例えば、ファイルを開いて読み書きするためのクラスに[[FileStreamクラス>programming/netfx/stream/1_1_filestream]]がありますが、これはStreamクラスから派生したものです。
+

          
+
#tabpage(C#)
+
#code(cs,FileStreamを使ってファイルからデータを読み込む例){{
+
using System;
+
using System.IO;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    // ファイルsample.datを開き、読み取りアクセスを行うためのFileStreamを作成する
+
    using (FileStream stream = new FileStream("sample.dat", FileMode.Open, FileAccess.Read)) {
+
      // 読み込んだデータを格納するためのバッファ
+
      byte[] buffer = new byte[4];
+

          
+
      // FileStreamから4バイト読み込みバッファに格納する
+
      stream.Read(buffer, 0, 4);
+

          
+
      // 読み込んだデータをInt32(int)に変換して表示する
+
      int number = BitConverter.ToInt32(buffer, 0);
+

          
+
      Console.WriteLine(number);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb,FileStreamを使ってファイルからデータを読み込む例){{
+
Imports System
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub Main()
+
    ' ファイルsample.datを開き、読み取りアクセスを行うためのFileStreamを作成する
+
    Using stream As New FileStream("sample.dat", FileMode.Open, FileAccess.Read)
+
      ' 読み込んだデータを格納するためのバッファ
+
      Dim buffer(3) As Byte
+

          
+
      ' FileStreamから4バイト読み込みバッファに格納する
+
      stream.Read(buffer, 0, 4)
+

          
+
      ' 読み込んだデータをInt32(int)に変換して表示する
+
      Dim number As Integer = BitConverter.ToInt32(buffer, 0)
+

          
+
      Console.WriteLine(number)
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
上記の例のようにStreamクラスに用意されているメソッドを使うことでもデータの読み書きはできますが、Streamクラスではバイト単位・バイナリレベルでの読み書きしかできないので、例えば数値を扱うには[[BitConverterクラス>programming/netfx/conversion/0_basetype#ByteArrayConversion_BitConverter]]を使って読み書きの度に型変換を行わなければなりません。
+

          
+
しかし、それはStreamクラスを単体で使う場合に限ったことで、.NET FrameworkにはStreamクラスを使った数値・文字列の読み書きを簡単に行えるようにする便利なクラスが用意されています。 [[StreamReader・StreamWriter>programming/netfx/stream/2_streamreader_streamwriter]]や[[BinaryReader・BinaryWriter>programming/netfx/stream/3_binaryreader_binarywriter]]といったクラスをStreamクラスと組み合わせて使うことにより、数値・文字列など構造化されたデータをより簡単に読み書きできるようになります。
+

          
+
#tabpage(C#)
+
#code(cs,FileStreamとBinaryReaderを使ってファイルから数値を読み込む例){{
+
using System;
+
using System.IO;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    // ファイルsample.datを開き、読み取りアクセスを行うためのFileStreamを作成する
+
    using (FileStream stream = new FileStream("sample.dat", FileMode.Open, FileAccess.Read)) {
+
      // streamからデータを読み出すBinaryReaderを作成する
+
      BinaryReader reader = new BinaryReader(stream);
+

          
+
      // streamからInt32(int)のデータを読み込み、表示する
+
      int number = reader.ReadInt32();
+

          
+
      Console.WriteLine(number);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb,FileStreamとBinaryReaderを使ってファイルから数値を読み込む例){{
+
Imports System
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub Main()
+
    ' ファイルsample.datを開き、読み取りアクセスを行うためのFileStreamを作成する
+
    Using stream As New FileStream("sample.dat", FileMode.Open, FileAccess.Read)
+
      ' streamからデータを読み出すBinaryReaderを作成する
+
      Dim reader As New BinaryReader(stream)
+

          
+
      ' streamからInt32(Integer)のデータを読み込み、表示する
+
      Dim number As Integer = reader.ReadInt32()
+

          
+
      Console.WriteLine(number)
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#tabpage(C#)
+
#code(cs,FileStreamとStreamReaderを使ってファイルから文字列を読み込む例){{
+
using System;
+
using System.IO;
+
using System.Text;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    // ファイルsample.datを開き、読み取りアクセスを行うためのFileStreamを作成する
+
    using (FileStream stream = new FileStream("sample.dat", FileMode.Open, FileAccess.Read)) {
+
      // テキストエンコーディングにUTF-8を用いてstreamの読み込みを行うStreamReaderを作成する
+
      StreamReader reader = new StreamReader(stream, Encoding.UTF8);
+

          
+
      // streamから文字列を一行分読み込み、表示する
+
      string line = reader.ReadLine();
+

          
+
      Console.WriteLine(line);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb,FileStreamとStreamReaderを使ってファイルから文字列を読み込む例){{
+
Imports System
+
Imports System.IO
+
Imports System.Text
+

          
+
Class Sample
+
  Shared Sub Main()
+
    ' ファイルsample.datを開き、読み取りアクセスを行うためのFileStreamを作成する
+
    Using stream As New FileStream("sample.dat", FileMode.Open, FileAccess.Read)
+
      ' テキストエンコーディングにUTF-8を用いてstreamの読み込みを行うStreamReaderを作成する
+
      Dim reader As New StreamReader(stream, Encoding.UTF8)
+

          
+
      ' streamから文字列を一行分読み込み、表示する
+
      Dim line As String = reader.ReadLine()
+

          
+
      Console.WriteLine(line)
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
ここまでの例で挙げたFileStreamはファイルの読み書きを行うためのストリームですが、他にもStreamの一種としてバイト配列をストリームとして扱うための[[MemoryStream>programming/netfx/stream/1_2_memorystream]]が用意されています。
+

          
+
#tabpage(C#)
+
#code(cs,MemoryStreamとStreamReaderを使ってバイト配列から文字列を読み込む例){{
+
using System;
+
using System.IO;
+
using System.Text;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    // 何らかのデータが格納されているバイト配列を想定
+
    byte[] data = new byte[32];
+

          
+
    // バイト配列を読み取り専用のストリームとして扱うMemoryStreamを作成する
+
    using (MemoryStream stream = new MemoryStream(data, false)) {
+
      // テキストエンコーディングにUTF-8を用いてstreamの読み込みを行うStreamReaderを作成
+
      StreamReader reader = new StreamReader(stream, Encoding.UTF8);
+

          
+
      // streamから文字列を一行分読み込み、表示する
+
      string line = reader.ReadLine();
+

          
+
      Console.WriteLine(line);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb,MemoryStreamとStreamReaderを使ってバイト配列から文字列を読み込む例){{
+
Imports System
+
Imports System.IO
+
Imports System.Text
+

          
+
Class Sample
+
  Shared Sub Main()
+
    ' 何らかのデータが格納されているバイト配列を想定
+
    Dim data(31) As Byte
+

          
+
    ' バイト配列を読み取り専用のストリームとして扱うMemoryStreamを作成する
+
    Using stream As New MemoryStream(data, false)
+
      ' テキストエンコーディングにUTF-8を用いてstreamの読み込みを行うStreamReaderを作成
+
      Dim reader As New StreamReader(stream, Encoding.UTF8)
+

          
+
      ' streamから文字列を一行分読み込み、表示する
+
      Dim line As String = reader.ReadLine()
+

          
+
      Console.WriteLine(line)
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
入力ソースがFileStreamであってもMemoryStreamであっても、実際に読み込みを行う部分のコードはどちらも同じです。 このように、データがファイルとして存在するのか、バイト配列として存在するのかといった違いがあっても、それらがStreamである限りはいずれも同じように扱うことができます。
+

          
+
また、StreamReader・StreamWriterやBinaryReader・BinaryWriter以外にもStreamを使った読み取り・書き込みをサポートしているクラスは多数あります。 これらのクラスでは、Streamクラスをサポートすることによりファイルやメモリ以外の入力ソースにも幅広く柔軟に対応できるようになっています。
+

          
+
#image(stream_io.png,Streamクラスとデータの入出力)
+

          
+
FileStreamやMemoryStream以外にも、.NET Frameworkには各種データソースに対応したStream派生クラスが用意されています。 以下のクラスは、そのようなStream派生クラスの一例です。
+

          
+
|*Streamの派生クラス (一例)
+
|~クラス|~概要|h
+
|&msdn(netfx,type,System.IO.FileStream){FileStream};|ファイルシステム上のファイルへの読み書きを行うためのStream|
+
|&msdn(netfx,type,System.IO.MemoryStream){MemoryStream};|メモリ上に確保されているバイト配列への読み書きを行うためのStream|
+
|&msdn(netfx,type,System.IO.UnmanagedMemoryStream){UnmanagedMemoryStream};|アンマネージブロック上に確保されている領域への読み書きを行うためのStream|
+
|&msdn(netfx,type,System.Net.Sockets.NetworkStream){NetworkStream};|ソケットを使ってデータの送受信を行うためのStream|
+

          
+
データソースの種類によっては具体的なStream派生クラスが公開されていないものも存在しますが、そういったものでも何らかのメソッド呼び出しを利用することでStreamが取得できるものもあります。 Streamを取得するメソッドには次のようなものがあります。
+

          
+
|*Streamを取得するメソッド (一例)
+
|~クラス|~概要|h
+
|{{
+
&msdn(netfx,member,System.Console.OpenStandardInput){Console.OpenStandardInput};
+
&msdn(netfx,member,System.Console.OpenStandardOutput){Console.OpenStandardOutput};
+
&msdn(netfx,member,System.Console.OpenStandardError){Console.OpenStandardError};
+
}}|プロセスの標準ストリームを開いてStreamを取得するためのメソッド|
+
|{{
+
&msdn(netfx,member,System.Reflection.Assembly.GetManifestResourceStream){Assembly.GetManifestResourceStream};
+
}}|[[アセンブリに埋め込まれたリソース>programming/netfx/embeddedresource]]を開いてStreamを取得するためのメソッド|
+
|{{
+
&msdn(netfx,member,System.IO.File.Create){File.Create};
+
&msdn(netfx,member,System.IO.File.Open){File.Open};
+
&msdn(netfx,member,System.IO.File.OpenRead){File.OpenRead};
+
&msdn(netfx,member,System.IO.File.OpenWrite){File.OpenWrite};
+
}}|[[ファイルを開いてFileStreamを取得する>programming/netfx/stream/1_1_filestream#File_Open]]ためのメソッド&br;(FileStreamのコンストラクタ呼び出しをメソッド形式にして簡略化したもの)|
+

          
+
もちろん、Streamを継承して独自にストリームを実装したり、機能を拡張することも可能です。
+

          
+
FileStreamやMemoryStreamといったクラスは各種データソースからの読み書きを実装・抽象化したものですが、Streamには''Streamのラッパー''として動作するものが存在します。 例えば次のコードでは、&msdn(netfx,type,System.Security.Cryptography.CryptoStream){CryptoStream};を使ってデータをBase64形式にエンコードした上でFileStreamに書き込んでいます。
+

          
+
#tabpage(C#)
+
#code(cs,CryptoStreamを使ってBase64エンコードしたデータを書き込む例){{
+
using System;
+
using System.IO;
+
using System.Security.Cryptography;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    // ファイルsample.datを開き、書き込みアクセスを行うためのFileStreamを作成する
+
    using (Stream fileStream = new FileStream("sample.dat", FileMode.Create, FileAccess.Write)) {
+
      // Base64への変換を行った上でfileStreamに書き込みを行うCryptoStreamを作成する
+
      using (Stream base64Stream = new CryptoStream(fileStream, new ToBase64Transform(), CryptoStreamMode.Write)) {
+
        // 書き込むデータが格納されているバイト配列
+
        byte[] data = new byte[8] {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48};
+

          
+
        // データを書き込む
+
        // CryptoStreamによりデータはBase64にエンコードされ、次いで
+
        // FileStreamによりエンコードされたデータがファイルに書き込まれる
+
        base64Stream.Write(data, 0, 8);
+
      }
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb,CryptoStreamを使ってBase64エンコードしたデータを書き込む例){{
+
Imports System
+
Imports System.IO
+
Imports System.Security.Cryptography
+

          
+
Class Sample
+
  Shared Sub Main()
+
    ' ファイルsample.datを開き、書き込みアクセスを行うためのFileStreamを作成する
+
    Using fileStream As Stream = New FileStream("sample.dat", FileMode.Create, FileAccess.Write)
+
      ' Base64への変換を行った上でfileStreamに書き込みを行うCryptoStreamを作成する
+
      Using base64Stream As Stream = New CryptoStream(fileStream, New ToBase64Transform(), CryptoStreamMode.Write)
+
        ' 書き込むデータが格納されているバイト配列
+
        Dim data() As Byte = New Byte() {&h41, &h42, &h43, &h44, &h45, &h46, &h47, &h48}
+

          
+
        ' データを書き込む
+
        ' CryptoStreamによりデータはBase64にエンコードされ、次いで
+
        ' FileStreamによりエンコードされたデータがファイルに書き込まれる
+
        base64Stream.Write(data, 0, 8)
+
      End Using
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(sample.datに書き込まれる内容){{
+
QUJDREVGR0g=
+
}}
+

          
+
このように、CryptoStreamを使うことで他のStreamに対してBase64エンコードを行う機能を追加することができます。 CryptoStreamはBase64形式でのエンコード・デコード以外にも、様々な形式での暗号化やフォーマット変換を行うために使われます。
+

          
+
CryptoStream以外にも、ラッパーとして動作するStreamには次のようなものがあります。
+

          
+
|*ラッパーとして動作するStreamの派生クラス (一例)
+
|~クラス|~概要|h
+
|&msdn(netfx,type,System.IO.BufferedStream){BufferedStream};|Streamにバッファリングを行う機能を追加するためのStream|
+
|{{
+
&msdn(netfx,type,System.IO.Compression.GZipStream){GZipStream};
+
&msdn(netfx,type,System.IO.Compression.DeflateStream){DeflateStream};
+
}}|Streamにgzip形式・Deflate形式での圧縮・展開機能を追加するためのStream ([[使用例・解説>programming/netfx/fcl/System.IO.Compression.GZipStream]])|
+
|{{
+
&msdn(netfx,type,System.Net.Security.AuthenticatedStream){AuthenticatedStream};
+
&msdn(netfx,type,System.Net.Security.SslStream){SslStream};
+
}}|StreamにSSLなどのセキュリティ・プロトコルの署名・暗号化機能を追加するためのStream|
+
|&msdn(netfx,type,System.Security.Cryptography.CryptoStream){CryptoStream};|Streamに各種暗号化やフォーマット変換を行う機能を追加するためのStream|
+

          
+
これらのクラスは、多段に重ねて使うことも可能です。 例えば、NetworkStreamをSslStreamでラップすることでSSLによる通信を行い、さらにGZipStreamでラップしてデータをgzip形式で圧縮してから送信する、といったことができます。
+

          
+
このように、Streamクラスは単純なデータの読み書きからフォーマット変換などの高度な機能の追加まで、様々な目的・方法で汎用的に使用することが出来ます。
+

          
+

          
+

          
+
*Streamクラス [#Stream]
+
ここではStreamクラスの基本的な使い方について解説します。 Streamクラスには読み書きを行うメソッドが用意されていますが、これらを直接使って読み書きすることはまれで、ほとんどの場合は[[StreamReader・StreamWriter>programming/netfx/stream/2_streamreader_streamwriter]]や[[BinaryReader・BinaryWriter>programming/netfx/stream/3_binaryreader_binarywriter]]で事足ります。
+

          
+
以下の解説中にあるサンプルコードでは、具体例を提示する都合上[[FileStream>programming/netfx/stream/1_1_filestream]]を使っている箇所が多くありますが、特に注記している場合を除いてすべてのStreamに共通する事柄を述べています。 例えば、FileStreamを使っている箇所を[[MemoryStream>programming/netfx/stream/1_2_memorystream]]に置き換えても同じように動作します。
+

          
+
**読み込み操作
+
Streamクラスを使ってデータの読み込みを行う方法について。
+

          
+
***読み込み (Read, ReadByte) [#Stream.Read]
+
Streamからデータを読み込むには、&msdn(netfx,member,System.IO.Stream.Read){Readメソッド};を使います。 Readメソッドの引数・戻り値は次のとおりです。
+

          
+
:第1引数 &var{buffer};|Streamから読み込んだデータを格納するためのバイト配列
+
:第2引数 &var{offset};|Streamから読み込んだデータを格納する際の、格納先となるバイト配列中の開始インデックス
+
:第3引数 &var{count};|Streamから読み込むデータの最大バイト数
+
:戻り値|実際にStreamから読み込めたデータのバイト数
+

          
+
つまり、Readメソッドの戻り値を&var{len};とすると、ReadメソッドでStreamから読み込んだデータは&var{buffer};[&var{offset};]から&var{buffer};[&var{offset}; + &var{len}; - 1]の範囲に格納されることになります。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    using (Stream stream = File.OpenRead("sample.dat")) {
+
      // 読み込んだデータを格納するためのバッファ
+
      byte[] buffer = new byte[8];
+

          
+
      // streamから最大4バイトを読み込み、buffer[0]以降に格納する
+
      int len = stream.Read(buffer, 0, 4);
+

          
+
      // 実際に読み込めた分を表示する
+
      Console.WriteLine("{0} {1}", len, BitConverter.ToString(buffer, 0, len));
+

          
+
      // streamから最大2バイトを読み込み、buffer[4]以降に格納する
+
      len = stream.Read(buffer, 4, 2);
+

          
+
      // 実際に読み込めた分を表示する
+
      Console.WriteLine("{0} {1}", len, BitConverter.ToString(buffer, 4, len));
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Using stream As Stream = File.OpenRead("sample.dat")
+
      ' 読み込んだデータを格納するためのバッファ
+
      Dim buffer(7) As Byte
+

          
+
      ' streamから最大4バイトを読み込み、buffer(0)以降に格納する
+
      Dim len As Integer = stream.Read(buffer, 0, 4)
+

          
+
      ' 実際に読み込めた分を表示する
+
      Console.WriteLine("{0} {1}", len, BitConverter.ToString(buffer, 0, len))
+

          
+
      ' streamから最大2バイトを読み込み、buffer(4)以降に格納する
+
      len = stream.Read(buffer, 4, 2)
+

          
+
      ' 実際に読み込めた分を表示する
+
      Console.WriteLine("{0} {1}", len, BitConverter.ToString(buffer, 4, len))
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
(上記の例で使用している[[BitConverter.ToStringメソッド>programming/netfx/conversion/0_basetype#ByteArrayConversion_BitConverter]]はバイト配列を見やすい形式に変換するためのもので、Readメソッドを使った読み込み処理の本質とは無関係のものです)
+

          
+
Readメソッドでは、指定したバイト数の分だけ読み込みを試みますが、''指定したバイト数ちょうどのデータが一度に読み込まれるとは限りません''。 例えば、読み込んだ結果ストリームの終端に達した場合や、StreamがNetworkStreamdでデータが送受信の途中だった場合などは、指定したバイト数よりも少なくなります。 Readメソッドで実際に読み込めたデータの長さは戻り値で知ることができます。 Streamから読み込めるデータが無くなった場合(すでにストリームの終端に達している場合)は、戻り値として0が返されます。 Readメソッドでの読み込みが成功した場合、読み込めたバイト数だけストリームの[[現在位置(Position)>#Stream_PositionLength]]が移動します。
+

          
+
次の例は、用意したバッファがいっぱいになるまでReadメソッドで読み込みを行う例です。 このコードではバッファがいっぱいになるか、ストリームの終端に達するまで読み込みを続けます。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    using (Stream stream = File.OpenRead("sample.dat")) {
+
      byte[] buffer = new byte[16]; // 読み込んだデータを格納するためのバッファ
+
      int offset = 0;               // 読み込んだデータを格納する位置の初期値
+
      int count = buffer.Length;    // 読み込むバイト数の初期値
+

          
+
      for (;;) {
+
        // 最大countバイト読み込み、bufferのインデックスoffset以降に格納する
+
        int len = stream.Read(buffer, offset, count);
+

          
+
        if (len == 0) {
+
          break; // これ以上読み込めるデータが無いので、読み込みを終了する
+
        }
+
        else {
+
          offset += len;  // 読み込めた長さの分だけ、次回のReadでバッファに格納する位置を移動する
+
          count -= len;   // 読み込めた長さの分だけ、次回のReadで読み込むバイト数を減らす
+
        }
+
      }
+

          
+
      // 実際に読み込めた分を表示する
+
      Console.WriteLine(BitConverter.ToString(buffer, 0, offset));
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Using stream As Stream = File.OpenRead("sample.dat")
+
      Dim buffer(15) As Byte                ' 読み込んだデータを格納するためのバッファ
+
      Dim offset As Integer = 0             ' 読み込んだデータを格納する位置の初期値
+
      Dim count As Integer = buffer.Length  ' 読み込むバイト数の初期値
+

          
+
      Do
+
        ' 最大countバイト読み込み、bufferのインデックスoffset以降に格納する
+
        Dim len As Integer = stream.Read(buffer, offset, count)
+

          
+
        If len = 0 Then
+
          Exit Do ' これ以上読み込めるデータが無いので、読み込みを終了する
+
        Else
+
          offset += len ' 読み込めた長さの分だけ、次回のReadでバッファに格納する位置を移動する
+
          count -= len  ' 読み込めた長さの分だけ、次回のReadで読み込むバイト数を減らす
+
        End If
+
      Loop
+

          
+
      ' 実際に読み込めた分を表示する
+
      Console.WriteLine(BitConverter.ToString(buffer, 0, offset))
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
&msdn(netfx,member,System.IO.Stream.ReadByte){ReadByteメソッド};を使うと、Streamからデータを1バイトずつ読み込むことができます。 このメソッドでは、読み込めたデータは戻り値として返されます。 ただし、型はint/Integerとなっていて、既にストリームの終端に達していている場合は-1が返されます。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    using (Stream stream = File.OpenRead("sample.dat")) {
+
      for (;;) {
+
        // streamから1バイト読み込む
+
        int data = stream.ReadByte();
+

          
+
        if (data == -1)
+
          // 終端に達した
+
          break;
+

          
+
        // byteにキャストして表示
+
        byte b = (byte)data;
+

          
+
        Console.Write("{0:x2} ", b);
+
      }
+

          
+
      Console.WriteLine();
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Using stream As Stream = File.OpenRead("sample.dat")
+
      Do
+
        ' streamから1バイト読み込む
+
        Dim data As Integer = stream.ReadByte()
+

          
+
        If data = -1 Then Exit Do ' 終端に達した
+

          
+
        ' byteにキャストして表示
+
        Dim b As Byte = CByte(data)
+

          
+
        Console.Write("{0:x2} ", b)
+
      Loop
+

          
+
      Console.WriteLine()
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
Streamクラスは''バッファリングを行わない''ため、Peekなどのような先読みを行うメソッド・プロパティは用意されていません。
+

          
+
***現在位置と長さ (Position, Length) [#Stream_PositionLength]
+
ストリーム内の現在位置を取得するには&msdn(netfx,member,System.IO.Stream.Position){Positionプロパティ};を参照します。 この値は、[[Readメソッド>#Stream.Read]]・[[Writeメソッド>#Stream.Write]]で読み書きを行う際の開始位置となります。 読み書きの両方が可能なストリームでも、''読み込みと書き込みの開始位置は常に同じ''となる(別々ではない)点に注意してください。
+

          
+
また、ストリームの長さを取得するには&msdn(netfx,member,System.IO.Stream.Length){Lengthプロパティ};を参照します。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    using (Stream stream = File.OpenRead("sample.dat")) {
+
      // streamの長さと現在の位置を表示
+
      Console.WriteLine("Length : {0}", stream.Length);
+
      Console.WriteLine("Position : {0}", stream.Position);
+

          
+
      // streamからデータを読み込む
+
      byte[] buffer = new byte[8];
+

          
+
      int len = stream.Read(buffer, 0, buffer.Length);
+

          
+
      // 読み込めたバイト数と現在の位置を表示
+
      Console.WriteLine("Read() : {0}", len);
+
      Console.WriteLine("Position : {0}", stream.Position);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Using stream As Stream = File.OpenRead("sample.dat")
+
      ' streamの長さと現在の位置を表示
+
      Console.WriteLine("Length : {0}", stream.Length)
+
      Console.WriteLine("Position : {0}", stream.Position)
+

          
+
      ' streamからデータを読み込む
+
      Dim buffer(7) As Byte
+

          
+
      Dim len As Integer = stream.Read(buffer, 0, buffer.Length)
+

          
+
      ' 読み込めたバイト数と現在の位置を表示
+
      Console.WriteLine("Read() : {0}", len)
+
      Console.WriteLine("Position : {0}", stream.Position)
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果例){{
+
Length : 32
+
Position : 0
+
Read() : 8
+
Position : 8
+
}}
+

          
+
現在位置の変更(シーク)を行うにはPositionプロパティに値を設定するか、[[Seekメソッド>#Stream.Seek]]を使います。 また、ストリームの長さを変更するには[[SetLengthメソッド>#Stream.SetLength]]を使います。
+

          
+
現在位置や長さを取得できないストリームに対してPosition・Lengthを参照しようとした場合、例外&msdn(netfx,type,System.NotSupportedException){NotSupportedException};がスローされます。 例えば、NetworkStreamや標準入出力のストリームは長さや位置が取得できないストリームです。
+

          
+
***終端のチェック [#Stream_EndOfStream]
+
Streamクラスではバッファリングは行われず、またPeekなどの先読みを行うメソッド・プロパティは用意されないため、読み込みを行った結果''ストリームの終端に達したかどうかは事前に知ることはできず、次に読み込みを行ってみるまでわかりません''。
+

          
+
Readメソッドでは、ストリームの終端に達している場合に呼び出すと 0 が返されます。 ReadByteメソッドでは -1 が返されます。 Read・ReadByteメソッドは、ストリームの終端に達した後も呼び出すことは可能なので、その戻り値から終端に達したかどうかを判定することが出来ます。 (Streamクラスの読み込みを行うメソッドからは例外&msdn(netfx,type,System.IO.EndOfStreamException){EndOfStreamException};がスローされることはありません。)
+

          
+
ストリームの現在位置と長さを表すプロパティPositionとLengthの値を調べ、両者の値が同じならストリームの終端に達したと判断することも出来ます。 ただし、NetworkStreamや標準入力のストリームなどでは現在位置・長さを取得することはできずNotSupportedExceptionがスローされてしまうため、この場合はやはりRead・ReadByteメソッドの戻り値を見るほかありません。
+

          
+

          
+

          
+
**書き込み操作
+
Streamクラスを使ってデータの書き込みを行う方法について。
+

          
+
***書き込み (Write, WriteByte) [#Stream.Write]
+
Streamにデータを書き込むには、&msdn(netfx,member,System.IO.Stream.Write){Writeメソッド};を使います。 Writeメソッドの引数は次のとおりです。
+

          
+
:第1引数 &var{buffer};|Streamに書き込むデータを格納しているバイト配列
+
:第2引数 &var{offset};|Streamに書き込むバイト配列中の開始インデックス
+
:第3引数 &var{count};|Streamに書き込むデータのバイト数
+

          
+
つまりWriteメソッドでは、&var{buffer};[&var{offset};]から&var{buffer};[&var{offset}; + &var{count}; - 1]の範囲のデータがStreamに書き込まれることになります。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    using (Stream stream = File.OpenWrite("sample.dat")) {
+
      // 書き込むデータが格納されているバイト配列
+
      byte[] buffer = new byte[8] {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48};
+

          
+
      // bufferの0番目から4バイト分(buffer[0]〜buffer[3])をstreamに書き込む
+
      stream.Write(buffer, 0, 4);
+

          
+
      // bufferの4番目から4バイト分(buffer[4]〜buffer[7])をstreamに書き込む
+
      stream.Write(buffer, 4, 4);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Using stream As Stream = File.OpenWrite("sample.dat")
+
      ' 書き込むデータが格納されているバイト配列
+
      Dim buffer() As Byte = New Byte(7) {&h41, &h42, &h43, &h44, &h45, &h46, &h47, &h48}
+

          
+
      ' bufferの0番目から4バイト分(buffer(0)〜buffer(3))をstreamに書き込む
+
      stream.Write(buffer, 0, 4)
+

          
+
      ' bufferの4番目から4バイト分(buffer(4)〜buffer(7))をstreamに書き込む
+
      stream.Write(buffer, 4, 4)
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
Writeメソッドでの書き込みが成功した場合、書き込めたバイト数だけストリームの[[現在位置(Position)>#Stream_PositionLength]]が移動します。
+

          
+
&msdn(netfx,member,System.IO.Stream.WriteByte){WriteByteメソッド};を使うと、Streamにデータを1バイトずつ書き込むことができます。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    using (Stream stream = File.OpenWrite("sample.dat")) {
+
      // 書き込むデータが格納されているバイト配列
+
      byte[] data = new byte[8] {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48};
+

          
+
      for (int index = 0; index < data.Length; index++) {
+
        // streamに1バイトずつ書き込む
+
        stream.WriteByte(data[index]);
+
      }
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Using stream As Stream = File.OpenWrite("sample.dat")
+
      ' 書き込むデータが格納されているバイト配列
+
      Dim data() As Byte = New Byte(7) {&h41, &h42, &h43, &h44, &h45, &h46, &h47, &h48}
+

          
+
      For index As Integer = 0 To data.Length - 1
+
        ' streamに1バイトずつ書き込む
+
        stream.WriteByte(data(index))
+
      Next
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
***フラッシュ (Flush) [#Stream.Flush]
+
Writeメソッドで書き込んだデータをフラッシュさせるには、&msdn(netfx,member,System.IO.Stream.Flush){Flushメソッド};を呼び出します。 FileStreamなど、内部でバッファリングが行われるように実装されているStreamでは、Flushメソッドを呼び出すことで内部バッファに格納された内容を反映させることができます。 ただ、[[Closeメソッド>#Stream.Close]]を呼び出したりusingステートメントから抜け出る際には自動的にフラッシュされるので、Streamを閉じる前においてはFlushメソッドを呼び出す必要はありません。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    using (Stream stream = File.OpenWrite("sample.dat")) {
+
      // 書き込むデータが格納されているバイト配列
+
      byte[] buffer = new byte[8] {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48};
+

          
+
      // bufferの0番目から4バイト分(buffer[0]〜buffer[3])をstreamに書き込む
+
      stream.Write(buffer, 0, 4);
+

          
+
      // 書き込んだ内容をフラッシュする
+
      stream.Flush();
+

          
+
      // bufferの4番目から4バイト分(buffer[4]〜buffer[7])をstreamに書き込む
+
      stream.Write(buffer, 4, 4);
+
    }
+
    // usingステートメントから抜け出る際にもDisposeメソッドにより自動的にフラッシュされる
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Using stream As Stream = File.OpenWrite("sample.dat")
+
      ' 書き込むデータが格納されているバイト配列
+
      Dim buffer() As Byte = New Byte(7) {&h41, &h42, &h43, &h44, &h45, &h46, &h47, &h48}
+

          
+
      ' bufferの0番目から4バイト分(buffer(0)〜buffer(3))をstreamに書き込む
+
      stream.Write(buffer, 0, 4)
+

          
+
      ' 書き込んだ内容をフラッシュする
+
      stream.Flush()
+

          
+
      ' bufferの4番目から4バイト分(buffer(4)〜buffer(7))をstreamに書き込む
+
      stream.Write(buffer, 4, 4)
+
    End Using
+
    ' Usingステートメントから抜け出る際にもDisposeメソッドにより自動的にフラッシュされる
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
***ストリームの長さの設定 (SetLength) [#Stream.SetLength]
+
ストリームの長さを変更したい場合は、&msdn(netfx,member,System.IO.Stream.SetLength){SetLengthメソッド};を呼び出します。 SetLengthメソッドで現在のStreamの長さよりも短くする場合、その内容は切り捨てられます。 同時に、ストリームの書き込み・読み込み位置はストリームの終端に移動します。 逆に現在のStreamの長さよりも長くする場合、拡張した部分の内容は定義されません。 ストリームの読み込み・書き込み位置は変わりません。
+

          
+
Positionプロパティとは異なり&msdn(netfx,member,System.IO.Stream.Length){Lengthプロパティ};は読み取り専用なので、このプロパティに値を設定してストリームの長さを変更することは出来ません。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    using (Stream stream = File.OpenWrite("sample.dat")) {
+
      // 書き込むデータが格納されているバイト配列
+
      byte[] buffer = new byte[8] {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48};
+

          
+
      // bufferの8バイト分をstreamに書き込む
+
      stream.Write(buffer, 0, 8);
+

          
+
      // streamの長さを4バイトにする
+
      stream.SetLength(4);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Using stream As Stream = File.OpenWrite("sample.dat")
+
      ' 書き込むデータが格納されているバイト配列
+
      Dim buffer() As Byte = New Byte(7) {&h41, &h42, &h43, &h44, &h45, &h46, &h47, &h48}
+

          
+
      ' bufferの8バイト分をstreamに書き込む
+
      stream.Write(buffer, 0, 8)
+

          
+
      ' streamの長さを4バイトにする
+
      stream.SetLength(4)
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
長さが変更できないストリームに対してSetLengthを呼び出そうとした場合には、例外&msdn(netfx,type,System.NotSupportedException){NotSupportedException};がスローされます。 例えば、NetworkStreamや標準入出力のストリーム、固定長に設定されたMemoryStreamなどは長さが変更できないストリームです。
+

          
+
既存のファイルを開いて上書きしようとする場合など、既にストリームに何らかの内容が書き込まれている場合、書き込んだ後にSetLengthでストリームの長さも変更しないと以前の内容が残ります。 例えば、16バイトのファイルを開いて8バイトのデータを書き込む場合、SetLengthでストリームの長さも8バイトに設定しないとファイルの長さは16バイトのままになります。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    using (Stream stream = File.OpenWrite("sample.dat")) {
+
      // 現在のstreamの長さを表示
+
      Console.WriteLine(stream.Length);
+

          
+
      // 書き込むデータが格納されているバイト配列
+
      byte[] buffer = new byte[8] {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48};
+

          
+
      // bufferの8バイト分をstreamに書き込む
+
      stream.Write(buffer, 0, 8);
+

          
+
      Console.WriteLine(stream.Length);
+

          
+
      // 現在の書き込み位置(8バイト目)をstreamの長さとして設定する
+
      stream.SetLength(stream.Position);
+

          
+
      Console.WriteLine(stream.Length);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Using stream As Stream = File.OpenWrite("sample.dat")
+
      ' 現在のstreamの長さを表示
+
      Console.WriteLine(stream.Length)
+

          
+
      ' 書き込むデータが格納されているバイト配列
+
      Dim buffer() As Byte = New Byte(7) {&h41, &h42, &h43, &h44, &h45, &h46, &h47, &h48}
+

          
+
      ' bufferの8バイト分をstreamに書き込む
+
      stream.Write(buffer, 0, 8)
+

          
+
      Console.WriteLine(stream.Length)
+

          
+
      ' 現在の書き込み位置(8バイト目)をstreamの長さとして設定する
+
      stream.SetLength(stream.Position)
+

          
+
      Console.WriteLine(stream.Length)
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
上記の例ではすべての書き込みが終わって長さが確定してからSetLengthメソッドを呼び出していますが、次のようにあらかじめ長さを0にしてストリームの内容を破棄してから書き込むようにすれば、実際に書き込んだ長さを後から調べる必要がなくなり実装を簡略化できます。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    using (Stream stream = File.OpenWrite("sample.dat")) {
+
      // 現在のstreamの長さを表示
+
      Console.WriteLine(stream.Length);
+

          
+
      // streamの長さをいったん0にして現在の内容を破棄する
+
      stream.SetLength(0);
+

          
+
      // 書き込むデータが格納されているバイト配列
+
      byte[] buffer = new byte[8] {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48};
+

          
+
      // bufferの8バイト分をstreamに書き込む
+
      stream.Write(buffer, 0, 8);
+

          
+
      Console.WriteLine(stream.Length);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Using stream As Stream = File.OpenWrite("sample.dat")
+
      ' 現在のstreamの長さを表示
+
      Console.WriteLine(stream.Length)
+

          
+
      ' streamの長さをいったん0にして現在の内容を破棄する
+
      stream.SetLength(0)
+

          
+
      ' 書き込むデータが格納されているバイト配列
+
      Dim buffer() As Byte = New Byte(7) {&h41, &h42, &h43, &h44, &h45, &h46, &h47, &h48}
+

          
+
      ' bufferの8バイト分をstreamに書き込む
+
      stream.Write(buffer, 0, 8)
+

          
+
      Console.WriteLine(stream.Length)
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
なおFileStreamでは、コンストラクタに[[FileMode.CreateもしくはFileMode.Truncate>programming/netfx/stream/1_1_filestream#FileMode]]を指定してインスタンスを作成すれば、既存のファイルを開いた場合にはその内容は破棄され、ストリームの長さは0となります。 従って、次の例では上記の例と同等の動作となります。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    // FileMode.Createを指定してFileStreamを作成
+
    using (Stream stream = new FileStream("sample.dat", FileMode.Create, FileAccess.Write)) {
+
      // 現在のstreamの長さを表示
+
      Console.WriteLine(stream.Length);
+

          
+
      // 書き込むデータが格納されているバイト配列
+
      byte[] buffer = new byte[8] {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48};
+

          
+
      // bufferの8バイト分をstreamに書き込む
+
      stream.Write(buffer, 0, 8);
+

          
+
      Console.WriteLine(stream.Length);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub Main()
+
    ' FileMode.Createを指定してFileStreamを作成
+
    Using stream As Stream = New FileStream("sample.dat", FileMode.Create, FileAccess.Write)
+
      ' 現在のstreamの長さを表示
+
      Console.WriteLine(stream.Length)
+

          
+
      ' 書き込むデータが格納されているバイト配列
+
      Dim buffer() As Byte = New Byte(7) {&h41, &h42, &h43, &h44, &h45, &h46, &h47, &h48}
+

          
+
      ' bufferの8バイト分をstreamに書き込む
+
      stream.Write(buffer, 0, 8)
+

          
+
      Console.WriteLine(stream.Length)
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt{{
+
D:\test>type sample.dat
+
XXXXXXXXXXXXXXXX
+
D:\test>Sample.exe
+
0
+
8
+

          
+
D:\test>type sample.dat
+
ABCDEFGH
+

          
+
}}
+

          
+
**シーク (Seek) [#Stream.Seek]
+
&msdn(netfx,member,System.IO.Stream.Position){Positionプロパティ};はストリーム内における現在の読み込み・書き込み位置を取得するためのプロパティですが、ランダムアクセスをサポートするストリームではPositionプロパティに値を設定することでその位置にシークすることができます。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    using (Stream stream = File.OpenWrite("sample.dat")) {
+
      // ストリームの書き込み位置を4バイト目に移動する
+
      stream.Position = 4;
+

          
+
      // 書き込むデータが格納されているバイト配列
+
      byte[] buffer = new byte[8] {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48};
+

          
+
      // bufferの8バイト分をstreamに書き込む
+
      stream.Write(buffer, 0, 8);
+

          
+
      // ストリームの書き込み位置を0バイト目(ストリームの先頭)に移動する
+
      stream.Position = 0;
+

          
+
      // bufferの4バイト分をstreamに書き込む
+
      stream.Write(buffer, 0, 4);
+
    }
+
  }
+
}
+

          
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Using stream As Stream = File.OpenWrite("sample.dat")
+
      ' ストリームの書き込み位置を4バイト目に移動する
+
      stream.Position = 4
+

          
+
      ' 書き込むデータが格納されているバイト配列
+
      Dim buffer() As Byte = New Byte(7) {&h41, &h42, &h43, &h44, &h45, &h46, &h47, &h48}
+

          
+
      ' bufferの8バイト分をstreamに書き込む
+
      stream.Write(buffer, 0, 8)
+

          
+
      ' ストリームの書き込み位置を0バイト目(ストリームの先頭)に移動する
+
      stream.Position = 0
+

          
+
      ' bufferの4バイト分をstreamに書き込む
+
      stream.Write(buffer, 0, 4)
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
&msdn(netfx,member,System.IO.Stream.Seek){Seekメソッド};を使うことでもシークを行うことができます。 Seekメソッドでは、シーク先のオフセット&var{offset};とシークの原点&var{origin};の二つを指定します。 &var{origin};は&msdn(netfx,type,System.IO.SeekOrigin){SeekOrigin列挙体};で指定し、その値によって&var{offset};の意味が次のように変わります。 また、&var{offset};には負の値を指定することもできます。
+

          
+
|*SeekOriginとSeekメソッドの移動結果の違い
+
|~SeekOrigin|~意味|~指定例|h
+
|SeekOrigin.Begin|{{
+
ストリームの先頭から&var{offset};進めた位置にシークする
+
(Position = &var{offset};)
+
}}|{{
+
ストリームの先頭にシークする場合
+
Seek(0, SeekOrigin.Begin)
+

          
+
ストリームの先頭から4バイト目にシークする場合
+
Seek(4, SeekOrigin.Begin)
+

          
+
}}|
+
|SeekOrigin.Current|{{
+
ストリーム内の現在の読み込み・書き込み位置から&var{offset};進めた位置にシークする
+
(Position = Position + &var{offset};)
+
}}|{{
+
現在位置から8バイト後方にシークする場合
+
Seek(8, SeekOrigin.Current)
+

          
+
現在位置から8バイト前方にシークする場合
+
Seek(-8, SeekOrigin.Current)
+

          
+
}}|
+
|SeekOrigin.End|{{
+
ストリームの終端から&var{offset};進めた位置にシークする
+
(Position = Length + &var{offset};)
+
}}|{{
+
ストリームの末尾にシークする場合
+
Seek(0, SeekOrigin.End)
+

          
+
ストリームの末尾から4バイト手前にシークする場合
+
Seek(-4, SeekOrigin.End)
+

          
+
}}|
+

          
+
次の例は、ストリームの末尾に追記を行うものです。 ストリームを開き、ストリームの末尾にシークしてから書き込みを行うことで、既存の内容の後ろに新たな内容を追記しています。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    using (Stream stream = File.OpenWrite("sample.dat")) {
+
      // ストリームの末尾までシーク
+
      stream.Seek(0, SeekOrigin.End);
+

          
+
      // 書き込むデータが格納されているバイト配列
+
      byte[] buffer = new byte[8] {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48};
+

          
+
      // bufferの8バイト分をstreamに書き込む
+
      stream.Write(buffer, 0, 8);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Using stream As Stream = File.OpenWrite("sample.dat")
+
      ' ストリームの末尾までシーク
+
      stream.Seek(0, SeekOrigin.End)
+

          
+
      ' 書き込むデータが格納されているバイト配列
+
      Dim buffer() As Byte = New Byte(7) {&h41, &h42, &h43, &h44, &h45, &h46, &h47, &h48}
+

          
+
      ' bufferの8バイト分をstreamに書き込む
+
      stream.Write(buffer, 0, 8)
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
なおFileStreamでは、コンストラクタに[[FileMode.Append>programming/netfx/stream/1_1_filestream#FileMode]]を指定してインスタンスを作成すれば、ファイルを開いたあと自動的にストリームの末尾にシークされます。 従って、次の例では上記の例と同等の動作となります。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    // FileMode.Appendを指定してFileStreamを作成
+
    using (Stream stream = new FileStream("sample.dat", FileMode.Append, FileAccess.Write)) {
+
      // 書き込むデータが格納されているバイト配列
+
      byte[] buffer = new byte[8] {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48};
+

          
+
      // bufferの8バイト分をstreamに書き込む
+
      stream.Write(buffer, 0, 8);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub Main()
+
    ' FileMode.Appendを指定してFileStreamを作成
+
    Using stream As Stream = New FileStream("sample.dat", FileMode.Append, FileAccess.Write)
+
      ' 書き込むデータが格納されているバイト配列
+
      Dim buffer() As Byte = New Byte(7) {&h41, &h42, &h43, &h44, &h45, &h46, &h47, &h48}
+

          
+
      ' bufferの8バイト分をstreamに書き込む
+
      stream.Write(buffer, 0, 8)
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
シーケンシャルアクセスのみをサポートするストリームに対してSeekメソッドを呼び出したり、Positionプロパティに値を設定しようとした場合には、例外&msdn(netfx,type,System.NotSupportedException){NotSupportedException};がスローされます。 例えば、NetworkStreamや標準入出力のストリームはシークがサポートされないストリームです。
+

          
+
**ケーパビリティ (CanRead, CanWrite, CanSeek) [#Stream_CanReadCanWriteCanSeek]
+
Streamはその種類やコンストラクタでの設定によって書き込み可能か、読み込み可能か異なります。 Streamが書き込み可能かどうかといったケーパビリティを実行時に知るには、&msdn(netfx,member,System.IO.Stream.CanRead){CanRead};・&msdn(netfx,member,System.IO.Stream.CanWrite){CanWrite};・&msdn(netfx,member,System.IO.Stream.CanSeek){CanSeek};の各プロパティを参照します。
+

          
+
次の例は、様々なStreamに対してそのケーパビリティを調べた例です。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+

          
+
class Sample {
+
  static void PrintStreamCapability(Stream stream)
+
  {
+
    Console.WriteLine("CanRead  : {0}", stream.CanRead);
+
    Console.WriteLine("CanWrite : {0}", stream.CanWrite);
+
    Console.WriteLine("CanSeek  : {0}", stream.CanSeek);
+
  }
+

          
+
  static void Main()
+
  {
+
    // 読み込み用に開いたFileStream
+
    Console.WriteLine("[File.OpenRead]");
+
    using (Stream stream = File.OpenRead("sample.dat")) {
+
      PrintStreamCapability(stream);
+
    }
+

          
+
    // 書き込み用に開いたFileStream
+
    Console.WriteLine("[File.OpenWrite]");
+
    using (Stream stream = File.OpenWrite("sample.dat")) {
+
      PrintStreamCapability(stream);
+
    }
+

          
+
    // 書き込み可能なMemoryStream
+
    Console.WriteLine("[MemoryStream]");
+
    using (Stream stream = new MemoryStream()) {
+
      PrintStreamCapability(stream);
+
    }
+

          
+
    // 読み込み専用のMemoryStream
+
    Console.WriteLine("[MemoryStream (read only)]");
+
    using (Stream stream = new MemoryStream(new byte[8], false)) {
+
      PrintStreamCapability(stream);
+
    }
+

          
+
    // 標準入力のStream
+
    Console.WriteLine("[Console.OpenStandardInput]");
+
    using (Stream stream = Console.OpenStandardInput()) {
+
      PrintStreamCapability(stream);
+
    }
+

          
+
    // 標準出力のStream
+
    Console.WriteLine("[Console.OpenStandardOutput]");
+
    using (Stream stream = Console.OpenStandardOutput()) {
+
      PrintStreamCapability(stream);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub PrintStreamCapability(ByVal stream As Stream)
+
    Console.WriteLine("CanRead  : {0}", stream.CanRead)
+
    Console.WriteLine("CanWrite : {0}", stream.CanWrite)
+
    Console.WriteLine("CanSeek  : {0}", stream.CanSeek)
+
  End Sub
+

          
+
  Shared Sub Main()
+
    ' 読み込み用に開いたFileStream
+
    Console.WriteLine("[File.OpenRead]")
+
    Using stream As Stream = File.OpenRead("sample.dat")
+
      PrintStreamCapability(stream)
+
    End Using
+

          
+
    ' 書き込み用に開いたFileStream
+
    Console.WriteLine("[File.OpenWrite]")
+
    Using stream As Stream = File.OpenWrite("sample.dat")
+
      PrintStreamCapability(stream)
+
    End Using
+

          
+
    ' 書き込み可能なMemoryStream
+
    Console.WriteLine("[MemoryStream]")
+
    Using stream As Stream = New MemoryStream()
+
      PrintStreamCapability(stream)
+
    End Using
+

          
+
    ' 読み込み専用のMemoryStream
+
    Console.WriteLine("[MemoryStream (read only)]")
+
    Using stream As Stream = New MemoryStream(New Byte(7) {}, False)
+
      PrintStreamCapability(stream)
+
    End Using
+

          
+
    ' 標準入力のStream
+
    Console.WriteLine("[Console.OpenStandardInput]")
+
    Using stream As Stream = Console.OpenStandardInput()
+
      PrintStreamCapability(stream)
+
    End Using
+

          
+
    ' 標準出力のStream
+
    Console.WriteLine("[Console.OpenStandardOutput]")
+
    Using stream As Stream = Console.OpenStandardOutput()
+
      PrintStreamCapability(stream)
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
[File.OpenRead]
+
CanRead  : True
+
CanWrite : False
+
CanSeek  : True
+
[File.OpenWrite]
+
CanRead  : False
+
CanWrite : True
+
CanSeek  : True
+
[MemoryStream]
+
CanRead  : True
+
CanWrite : True
+
CanSeek  : True
+
[MemoryStream (read only)]
+
CanRead  : True
+
CanWrite : False
+
CanSeek  : True
+
[Console.OpenStandardInput]
+
CanRead  : True
+
CanWrite : False
+
CanSeek  : False
+
[Console.OpenStandardOutput]
+
CanRead  : False
+
CanWrite : True
+
CanSeek  : False
+
}}
+

          
+
各ケーパビリティと、該当する操作のメソッド・プロパティは次のとおりです。
+

          
+
|*各ケーパビリティと該当する操作
+
|~ケーパビリティのプロパティ|~該当するStreamの操作|h
+
|CanWrite|Write, WriteByte, Flush, SetLength|
+
|CanRead|Read, ReadByte|
+
|CanSeek|Seek, SetLength, Position(プロパティの設定)|
+

          
+
ケーパビリティがfalseになっている操作を行おうとすると、例外&msdn(netfx,type,System.NotSupportedException){NotSupportedException};がスローされます。 例えば、CanSeekがfalseのStreamに対してSeekメソッドやSetLengthメソッドを呼び出そうとすると例外エラーとなります。
+

          
+
**クローズ (Close, Dispose) [#Stream.Close]
+
Streamに対する読み書きが終了した後、&msdn(netfx,member,System.IO.Stream.Close){Closeメソッド};を呼び出すことでStreamを閉じることができます。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    Stream stream = null;
+

          
+
    try {
+
      stream = File.OpenWrite("sample.dat");
+

          
+
      byte[] buffer = new byte[8] {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48};
+

          
+
      // streamにデータを書き込む
+
      stream.Write(buffer, 0, 8);
+
    }
+
    finally {
+
      // すべての処理が終わったらstreamを閉じる
+
      if (stream != null)
+
        stream.Close();
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim stream As Stream = Nothing
+

          
+
    Try 
+
      stream = File.OpenWrite("sample.dat")
+

          
+
      Dim buffer() As Byte = New Byte(7) {&h41, &h42, &h43, &h44, &h45, &h46, &h47, &h48}
+

          
+
      ' streamにデータを書き込む
+
      stream.Write(buffer, 0, 8)
+
    Finally
+
      ' すべての処理が終わったらstreamを閉じる
+
      If stream IsNot Nothing Then stream.Close()
+
    End Try
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
Streamクラスは&msdn(netfx,type,System.IDisposable){IDisposableインターフェイス};を実装しているので、Streamをusingステートメント内で使うことが出来ます。 この場合、Closeメソッドを呼び出さなくてもusingステートメントから抜ける時点でそれに相当する処理が自動的に行われます。 そのため、上記のコードと次のコードは、同等のものとなります。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    using (Stream stream = File.OpenWrite("sample.dat")) {
+
      byte[] buffer = new byte[8] {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48};
+

          
+
      // streamにデータを書き込む
+
      stream.Write(buffer, 0, 8);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Using stream As Stream = File.OpenWrite("sample.dat")
+
      Dim buffer() As Byte = New Byte(7) {&h41, &h42, &h43, &h44, &h45, &h46, &h47, &h48}
+

          
+
      ' streamにデータを書き込む
+
      stream.Write(buffer, 0, 8)
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
usingステートメントとIDisposableについては[[programming/netfx/disposing#UsingStatement]]で詳しく解説しています。
+

          
+
Closeメソッドでストリームを閉じた後は、ほとんどのメソッドの呼び出しとプロパティの参照ができなくなります。 閉じたStreamに対してこれらの操作を行おうとすると例外&msdn(netfx,type,System.ObjectDisposedException){ObjectDisposedException};がスローされます。
+

          
+
**コピー (CopyTo) [#Stream.CopyTo]
+
ストリームの内容を別のストリームにコピーするには、&msdn(netfx,member,System.IO.Stream.CopyTo){CopyToメソッド};を使うことができます。 あるストリームの内容をコピーしてメモリ上(MemoryStream)に保持したり、ファイル(FileStream)に書き出したりしたい場合などに使えます。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    using (Stream fromStream = File.OpenRead("sample.dat")) {
+
      using (MemoryStream toStream = new MemoryStream()) {
+
        // ファイルの内容をMemoryStreamにコピー
+
        fromStream.CopyTo(toStream);
+

          
+
        // コピーした内容をバイト配列に変換して表示
+
        Console.WriteLine(BitConverter.ToString(toStream.ToArray()));
+
      }
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Using fromStream As Stream = File.OpenRead("sample.dat")
+
      Using toStream As New MemoryStream()
+
        ' ファイルの内容をMemoryStreamにコピー
+
        fromStream.CopyTo(toStream)
+

          
+
        ' コピーした内容をバイト配列に変換して表示
+
        Console.WriteLine(BitConverter.ToString(toStream.ToArray()))
+
      End Using
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
CopyToメソッドでは、コピー元のStreamからReadしたものをコピー先のStreamにWriteします。 この際、CopyToメソッド内でデータの読み書きに使用されるバッファが確保されますが、このバッファのサイズを指定することもできます。 なお、指定しなかった場合ではデフォルトで4096バイトのバッファが確保されます。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    using (Stream fromStream = File.OpenRead("sample.dat")) {
+
      using (MemoryStream toStream = new MemoryStream()) {
+
        // ファイルの内容をMemoryStreamにコピー (バッファサイズとして64[バイト]を指定)
+
        fromStream.CopyTo(toStream, 64);
+

          
+
        // コピーした内容をバイト配列に変換して表示
+
        Console.WriteLine(BitConverter.ToString(toStream.ToArray()));
+
      }
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Using fromStream As Stream = File.OpenRead("sample.dat")
+
      Using toStream As New MemoryStream()
+
        ' ファイルの内容をMemoryStreamにコピー (バッファサイズとして64[バイト]を指定)
+
        fromStream.CopyTo(toStream, 64)
+

          
+
        ' コピーした内容をバイト配列に変換して表示
+
        Console.WriteLine(BitConverter.ToString(toStream.ToArray()))
+
      End Using
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
CopyToメソッドは.NET Framework 4以降で使用可能なメソッドです。 .NET Framework 3.5以前の場合はCopyToメソッドを使うことは出来ないので、次のようにReadメソッド・Writeメソッドを使ってコピー処理を実装する必要があります。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+

          
+
class Sample {
+
  static void Copy(Stream fromStream, Stream toStream, int bufferSize)
+
  {
+
    // 読み込みに使用するバッファを確保
+
    byte[] buffer = new byte[bufferSize];
+

          
+
    for (;;) {
+
      // コピー元のStreamからバッファのサイズ分だけデータを読み込む
+
      int len = fromStream.Read(buffer, 0, bufferSize);
+

          
+
      if (len == 0)
+
        // コピー元のStreamの終端まで読み込んだらコピー終了
+
        break;
+

          
+
      // 読み込んだデータをコピー先のStreamに書き込む
+
      toStream.Write(buffer, 0, len);
+
    }
+
  }
+

          
+
  static void Main()
+
  {
+
    using (Stream fromStream = File.OpenRead("sample.dat")) {
+
      using (MemoryStream toStream = new MemoryStream()) {
+
        // ファイルの内容をMemoryStreamにコピー (バッファサイズとして64[バイト]を指定)
+
        Copy(fromStream, toStream, 64);
+

          
+
        // コピーした内容をバイト配列に変換して表示
+
        Console.WriteLine(BitConverter.ToString(toStream.ToArray()));
+
      }
+
    }
+
  }
+
}
+

          
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub Copy(ByVal fromStream As Stream, ByVal toStream As Stream, ByVal bufferSize As Integer)
+
    ' 読み込みに使用するバッファを確保
+
    Dim buffer(bufferSize - 1) As Byte
+

          
+
    Do
+
      ' コピー元のStreamからバッファのサイズ分だけデータを読み込む
+
      Dim len As Integer = fromStream.Read(buffer, 0, bufferSize)
+

          
+
      If len = 0 Then Exit Do ' コピー元のStreamの終端まで読み込んだらコピー終了
+

          
+
      ' 読み込んだデータをコピー先のStreamに書き込む
+
      toStream.Write(buffer, 0, len)
+
    Loop
+
  End Sub
+

          
+
  Shared Sub Main()
+
    Using fromStream As Stream = File.OpenRead("sample.dat")
+
      Using toStream As New MemoryStream()
+
        ' ファイルの内容をMemoryStreamにコピー (バッファサイズとして64[バイト]を指定)
+
        Copy(fromStream, toStream, 64)
+

          
+
        ' コピーした内容をバイト配列に変換して表示
+
        Console.WriteLine(BitConverter.ToString(toStream.ToArray()))
+
      End Using
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+

          
+

          
+

          
+
**非同期操作
+
(未整理)
+

          
+
&msdn(netfx,member,System.IO.Stream.BeginRead){BeginRead};・&msdn(netfx,member,System.IO.Stream.BeginWrite){BeginWrite};などのメソッドを使うことで、Streamを使って非同期の読み書きを行うことが出来ます。
+

          
+
ストリームの種類によっては操作のタイムアウトもサポートしています。 &msdn(netfx,member,System.IO.Stream.CanTimeout){CanTimeoutプロパティ};を参照することで操作がタイムアウト可能かどうかを知ることができます。 また、&msdn(netfx,member,System.IO.Stream.ReadTimeout){ReadTimeoutプロパティ};・&msdn(netfx,member,System.IO.Stream.WriteTimeout){WriteTimeoutプロパティ};でタイムアウト時間の取得・設定ができます。
+

          
+
複数のスレッドからStreamにアクセスする場合、&msdn(netfx,member,System.IO.Stream.Synchronized){Synchronizedメソッド};メソッドを使うとStreamに対する読み書き操作をスレッドセーフにすることができます。
+

          
+
.NET Framework 4.5からは、&msdn(netfx,member,System.IO.Stream.ReadAsync){ReadAsync};・&msdn(netfx,member,System.IO.Stream.WriteAsync){WriteAsync};といった非同期操作のメソッドも使えるようになっています。
+

          
+

          
+

          
+
**ヌルオブジェクト (Null) [#Stream.Null]
+
Streamクラスにはヌルオブジェクトを取得するプロパティ&msdn(netfx,member,System.IO.Stream.Null){Stream.Null};が用意されています。 Stream.Nullは、NULLデバイス(nul・/dev/null)の代わりとして使ったり、テスト時に具体的なStreamを用意する代わりにモックとして使用したりすることができます。
+

          
+
Stream.Nullは読み込み・書き込み・シークなど全ての機能をサポートしますが、実際にそれらの操作を行なっても何も起こりません。 Stream.Nullに対してWriteメソッドで書き込んだ内容はすべて破棄され、ReadメソッドでStream.Nullから読み込みを行った場合は0バイトのデータが読み出されます。 Stream.Nullの長さ(Length)は常に0です。
+

          
+
次の例では、出力先をStream.Nullに設定したStreamWriterを&msdn(netfx,member,System.Console.SetOut){Console.SetOutメソッド};渡すことによって標準出力の出力先をコンソールからStream.Nullに変更し、Console.WriteLineメソッドで出力される内容を破棄しています。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+

          
+
class Sample {
+
  static void Main(string[] args)
+
  {
+
    foreach (string arg in args) {
+
      // オプションスイッチ/quietが指定された場合は、標準出力へのメッセージ出力を抑止する
+
      if (arg == "/quiet") {
+
        // 標準出力の出力先をStream.Nullに設定したStreamWriterに変更する
+
        Console.SetOut(new StreamWriter(Stream.Null));
+
        // 次のようにTextWriter.Nullを使うことも可能
+
        // Console.SetOut(TextWriter.Null);
+
      }
+
    }
+

          
+
    // 警告メッセージを標準出力に出力
+
    Console.WriteLine("warning");
+

          
+
    // 致命的なエラーメッセージを標準エラーに出力
+
    Console.Error.WriteLine("FATAL ERROR");
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub Main(ByVal args() As String)
+
    For Each arg As String In args
+
      ' オプションスイッチ/quietが指定された場合は、標準出力へのメッセージ出力を抑止する
+
      If arg = "/quiet" Then
+
        ' 標準出力の出力先をStream.Nullに設定したStreamWriterに変更する
+
        Console.SetOut(New StreamWriter(Stream.Null))
+
        ' 次のようにTextWriter.Nullを使うことも可能
+
        ' Console.SetOut(TextWriter.Null)
+
      End If
+
    Next
+

          
+
    ' 警告メッセージを標準出力に出力
+
    Console.WriteLine("warning")
+

          
+
    ' 致命的なエラーメッセージを標準エラーに出力
+
    Console.Error.WriteLine("FATAL ERROR")
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
D:\test> Sample.exe
+
warning
+
FATAL ERROR
+

          
+
D:\test> Sample.exe /quiet
+
FATAL ERROR
+

          
+
}}
+

          
+

          
+
**構造体の読み書き
+
Streamクラスには任意の構造体を読み書きするメソッドは用意されていません。 ストリーム中のブロックを構造体として読み書きしたい場合、fread/fwrite関数のような読み書きを行いたい場合は、いったんバイト配列として読み書きし、さらにバイト配列から構造体に変換する必要があります。 具体的な実装例については[[programming/netfx/tips/convert_struct_and_bytearray]]で紹介しています。
+

          
+

          
+

          
+
#navi(..)
+

          

programming/netfx/stream/1_2_memorystream/index.wiki.txt

current previous
1,497 0,0
+
${smdncms:title,MemoryStreamクラス}
+
${smdncms:header_title,MemoryStreamクラス (System.IO)}
+
${smdncms:keywords,メモリ,バッファ,可変長,固定長,読み込み,書き込み,バイト配列,MemoryStream}
+
${smdncms:document_versions,codelang=cs,codelang=vb}
+

          
+
#navi(..)
+

          
+
&msdn(netfx,type,System.IO.MemoryStream){MemoryStreamクラス};はメモリ上に確保されたバイト配列に対して読み書きを行うためのStreamです。 Streamクラスから派生したクラスであるため、ほとんどの機能と操作方法は[[Streamクラス>programming/netfx/stream/0_abstract]]と同じですが、ここではMemoryStreamクラスに特有な箇所について解説します。
+

          
+
#googleadunit
+

          
+
*インスタンスの作成
+
MemoryStreamでは、読み書きに使用するバッファ(バイト配列)をMemoryStream自身に作成させるか、それとも別に存在する既存のバイト配列を使用するかを指定することができます。
+

          
+
MemoryStream自身にバッファを作成させるようにした場合、MemoryStreamに書き込む内容のサイズに応じて自動的にバッファサイズが拡張されます(可変長のバッファ)。 この場合、[[SetLengthメソッド>programming/netfx/stream/0_abstract#Stream.SetLength]]でストリームの長さ(サイズ)を変更することも可能となります。
+

          
+
一方、既存のバイト配列を使うように指定した場合、MemoryStreamでは指定されたバイト配列への読み書きのみを行います。 指定されたバイト配列のサイズを超えて書き込もうとした場合や、SetLengthメソッドで長さを変更しようとした場合には例外&msdn(netfx,type,System.NotSupportedException){NotSupportedException};がスローされます。 また、既存のバイト配列を指定する場合は、バイト配列の一部分のみを参照できるようにしたり、書き込みを禁止して読み込み専用にすることもできます。
+

          
+
使用するバッファや書き込みの許可などの指定は、次のようにMemoryStreamのインスタンスを作成する際にコンストラクタで指定します。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    // 書き込む内容に応じて自動的に拡張されるバッファを使用するMemoryStreamを作成
+
    using (MemoryStream stream = new MemoryStream()) {
+
      // BinaryWriterを使ってデータを書き込む
+
      BinaryWriter writer = new BinaryWriter(stream);
+

          
+
      writer.Write(0x12345678);
+

          
+
      // MemoryStreamに書き込んだ内容をバイト配列として取得して表示
+
      byte[] array = stream.ToArray();
+

          
+
      Console.WriteLine(BitConverter.ToString(array));
+
    }
+

          
+
    // 既存のバイト配列からデータを参照する読み込み専用のMemoryStreamを作成
+
    byte[] data = new byte[] {0x78, 0x56, 0x34, 0x12};
+

          
+
    using (MemoryStream stream = new MemoryStream(data, false)) {
+
      // BinaryReaderを使ってデータを読み込む
+
      BinaryReader reader = new BinaryReader(stream);
+

          
+
      Console.WriteLine("{0:x8}", reader.ReadInt32());
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub Main()
+
    ' 書き込む内容に応じて自動的に拡張されるバッファを使用するMemoryStreamを作成
+
    Using stream As New MemoryStream()
+
      ' BinaryWriterを使ってデータを書き込む
+
      Dim writer As New BinaryWriter(stream)
+

          
+
      writer.Write(&h12345678)
+

          
+
      ' MemoryStreamに書き込んだ内容をバイト配列として取得して表示
+
      Dim array() As Byte = stream.ToArray()
+

          
+
      Console.WriteLine(BitConverter.ToString(array))
+
    End Using
+

          
+
    ' 既存のバイト配列からデータを参照する読み込み専用のMemoryStreamを作成
+
    Dim data() As Byte = New Byte(3) {&h78, &h56, &h34, &h12}
+

          
+
    Using stream As New MemoryStream(data, False)
+
      ' BinaryReaderを使ってデータを読み込む
+
      Dim reader As New BinaryReader(stream)
+

          
+
      Console.WriteLine("{0:x8}", reader.ReadInt32())
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
MemoryStreamのコンストラクタにはいくつかの種類があります。 コンストラクタと作成されるMemoryStreamの動作・ケーパビリティをまとめると次のようになります。
+

          
+
|*MemoryStreamのコンストラクタとインスタンスの動作・ケーパビリティ
+
|~コンストラクタのオーバーロード|~コンストラクタの動作と作成されるMemoryStream|~書き込み|~サイズの変更|h
+
|new MemoryStream()|{{
+
可変長のバッファを使用して読み書きを行う
+
}}|可|可|
+
|new MemoryStream(&var{capacity};)|{{
+
可変長のバッファを使用して読み書きを行う&br;バッファの初期サイズを&var{capacity};で指定する
+
}}|可|可|
+
|new MemoryStream(&var{buffer};)|{{
+
既存のバイト配列&var{buffer};に対して読み書きを行う
+
}}|可|不可|
+
|new MemoryStream(&var{buffer};, &var{writable};)|{{
+
既存のバイト配列&var{buffer};に対して読み書きを行う
+
&var{buffer};への書き込みを許可するかどうかを&var{writable};で指定する
+
}}|&var{writable};の指定による|不可|
+
|new MemoryStream(&var{buffer};, &var{index};, &var{count};)|{{
+
既存のバイト配列&var{buffer};の[&var{index};]〜[&var{index}; + &var{count}; - 1]の範囲のみに対して読み書きを行う
+
}}|可|不可|
+
|new MemoryStream(&var{buffer};, &var{index};, &var{count};, &var{writable};)|{{
+
既存のバイト配列&var{buffer};の[&var{index};]〜[&var{index}; + &var{count}; - 1]の範囲のみに対して読み書きを行う
+
&var{buffer};への書き込みを許可するかどうかを&var{writable};で指定する
+
}}|&var{writable};の指定による|不可|
+

          
+
現在確保されているバッファのサイズを取得するには&msdn(netfx,member,System.IO.MemoryStream.Capacity){Capacityプロパティ};を参照します。 この値は、現在のストリームの長さ(&msdn(netfx,member,System.IO.MemoryStream.Length){Length};)とはことなるものです。
+

          
+
*バイト配列への変換 (ToArray) [#MemoryStream.ToArray]
+
MemoryStreamに書き込んだ内容をバイト配列に変換して取得するには、&msdn(netfx,member,System.IO.MemoryStream.ToArray){ToArrayメソッド};を呼び出します。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    using (MemoryStream stream = new MemoryStream()) {
+
      // BinaryWriterを使ってデータを書き込む
+
      BinaryWriter writer = new BinaryWriter(stream);
+

          
+
      writer.Write((uint)0x01234567);
+
      writer.Write((ushort)0x89AB);
+
      writer.Write((byte)0xCD);
+
      writer.Write((byte)0xEF);
+

          
+
      // MemoryStreamに書き込んだ内容をバイト配列として取得して表示
+
      byte[] array = stream.ToArray();
+

          
+
      Console.WriteLine("Length = {0}", array.Length);
+
      Console.WriteLine(BitConverter.ToString(array));
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Using stream As New MemoryStream()
+
      ' BinaryWriterを使ってデータを書き込む
+
      Dim writer As New BinaryWriter(stream)
+

          
+
      writer.Write(CInt(&h01234567))
+
      writer.Write(CUshort(&h89AB))
+
      writer.Write(CByte(&hCD))
+
      writer.Write(CByte(&hEF))
+

          
+
      ' MemoryStreamに書き込んだ内容をバイト配列として取得して表示
+
      Dim array() As Byte = stream.ToArray()
+

          
+
      Console.WriteLine("Length = {0}", array.Length)
+
      Console.WriteLine(BitConverter.ToString(array))
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
Length = 8
+
67-45-23-01-AB-89-CD-EF
+
}}
+

          
+
ToArrayメソッドは、常に''MemoryStreamの内容を新しく作成した配列にコピーして返します''。 既存のバイト配列を指定してMemoryStreamを作成した場合、ToArrayメソッドではその配列とは別のインスタンスが返されます。 また、既存のバイト配列の一部を指定したMemoryStreamでは、その範囲・長さの配列が返されます。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    byte[] data = new byte[] {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF};
+

          
+
    // dataを使ってMemoryStreamを作成
+
    using (MemoryStream stream = new MemoryStream(data)) {
+
      // streamをバイト配列に変換
+
      byte[] array = stream.ToArray();
+

          
+
      Console.WriteLine("data  : {0}", BitConverter.ToString(data));
+
      Console.WriteLine("array : {0}", BitConverter.ToString(array));
+
      Console.WriteLine("data == array : {0}", data == array);
+
      Console.WriteLine();
+
    }
+

          
+
    // dataの2バイト目から4バイト分を使ってMemoryStreamを作成
+
    using (MemoryStream stream = new MemoryStream(data, 2, 4)) {
+
      // streamをバイト配列に変換
+
      byte[] array = stream.ToArray();
+

          
+
      Console.WriteLine("data  : {0}", BitConverter.ToString(data));
+
      Console.WriteLine("array : {0}", BitConverter.ToString(array));
+
      Console.WriteLine("data == array : {0}", data == array);
+
      Console.WriteLine();
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim data() As Byte = New Byte() {&h01, &h23, &h45, &h67, &h89, &hAB, &hCD, &hEF}
+

          
+
    ' dataを使ってMemoryStreamを作成
+
    Using stream As New MemoryStream(data)
+
      ' streamをバイト配列に変換
+
      Dim array() As Byte = stream.ToArray()
+

          
+
      Console.WriteLine("data  : {0}", BitConverter.ToString(data))
+
      Console.WriteLine("array : {0}", BitConverter.ToString(array))
+
      Console.WriteLine("data Is array : {0}", data Is array)
+
      Console.WriteLine()
+
    End Using
+

          
+
    ' dataの2バイト目から4バイト分を使ってMemoryStreamを作成
+
    Using stream As New MemoryStream(data, 2, 4)
+
      ' streamをバイト配列に変換
+
      Dim array() As Byte = stream.ToArray()
+

          
+
      Console.WriteLine("data  : {0}", BitConverter.ToString(data))
+
      Console.WriteLine("array : {0}", BitConverter.ToString(array))
+
      Console.WriteLine("data Is array : {0}", data Is array)
+
      Console.WriteLine()
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
data  : 01-23-45-67-89-AB-CD-EF
+
array : 01-23-45-67-89-AB-CD-EF
+
data == array : False
+

          
+
data  : 01-23-45-67-89-AB-CD-EF
+
array : 45-67-89-AB
+
data == array : False
+
}}
+

          
+
*バッファの取得 (GetBuffer) [#MemoryStream.GetBuffer]
+
[[ToArrayメソッド>#MemoryStream.ToArray]]ではMemoryStreamのコピーが返されますが、MemoryStreamの内部で使用されるバッファを直接参照する必要がある場合には&msdn(netfx,member,System.IO.MemoryStream.GetBuffer){GetBufferメソッド};を使います。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    // 初期バッファサイズに32を指定したMemoryStreamを作成
+
    using (MemoryStream stream = new MemoryStream(32)) {
+
      // BinaryWriterを使ってデータを書き込む
+
      BinaryWriter writer = new BinaryWriter(stream);
+

          
+
      writer.Write((uint)0x01234567);
+
      writer.Write((ushort)0x89AB);
+
      writer.Write((byte)0xCD);
+
      writer.Write((byte)0xEF);
+

          
+
      Console.WriteLine("stream.Length = {0}", stream.Length);
+
      Console.WriteLine("stream.Capacity = {0}", stream.Capacity);
+

          
+
      // MemoryStreamの内部バッファを取得する
+
      byte[] buffer = stream.GetBuffer();
+

          
+
      Console.WriteLine("buffer.Length = {0}", buffer.Length);
+
      Console.WriteLine(BitConverter.ToString(buffer));
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub Main()
+
    ' 初期バッファサイズに32を指定したMemoryStreamを作成
+
    Using stream As New MemoryStream(32)
+
      ' BinaryWriterを使ってデータを書き込む
+
      Dim writer As New BinaryWriter(stream)
+

          
+
      writer.Write(CInt(&h01234567))
+
      writer.Write(CUshort(&h89AB))
+
      writer.Write(CByte(&hCD))
+
      writer.Write(CByte(&hEF))
+

          
+
      Console.WriteLine("stream.Length = {0}", stream.Length)
+
      Console.WriteLine("stream.Capacity = {0}", stream.Capacity)
+

          
+
      ' MemoryStreamの内部バッファを取得する
+
      Dim buffer() As Byte = stream.GetBuffer()
+

          
+
      Console.WriteLine("buffer.Length = {0}", buffer.Length)
+
      Console.WriteLine(BitConverter.ToString(buffer))
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
stream.Length = 8
+
stream.Capacity = 32
+
buffer.Length = 32
+
67-45-23-01-AB-89-CD-EF-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
+
}}
+

          
+
MemoryStreamのコンストラクタで既存のバイト配列を指定した場合は、GetBufferメソッドからはそのバイト配列(同じインスタンス)が返されます。 ただし、コンストラクタで引数&var{publiclyVisible};にtrueを指定しないとGetBufferメソッドでバッファを取得することは出来ません。 &var{publiclyVisible};にfalseを指定したMemoryStreamに対してGetBufferメソッドを呼び出した場合、例外&msdn(netfx,type,System.UnauthorizedAccessException){UnauthorizedAccessException};がスローされます。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    byte[] data = new byte[] {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF};
+

          
+
    // publiclyVisibleにtrueを指定してMemoryStreamを作成
+
    bool publiclyVisible = true;
+

          
+
    Console.WriteLine("publiclyVisible = {0}", publiclyVisible);
+

          
+
    using (MemoryStream stream = new MemoryStream(data, 0, data.Length, false, publiclyVisible)) {
+
      // 内部バッファを取得
+
      byte[] buffer = stream.GetBuffer();
+

          
+
      Console.WriteLine("Length = {0}", buffer.Length);
+
      Console.WriteLine(BitConverter.ToString(buffer));
+
      Console.WriteLine("buffer == data : {0}", buffer == data);
+
    }
+

          
+
    Console.WriteLine();
+

          
+
    // publiclyVisibleにfalseを指定してMemoryStreamを作成
+
    publiclyVisible = false;
+

          
+
    Console.WriteLine("publiclyVisible = {0}", publiclyVisible);
+

          
+
    using (MemoryStream stream = new MemoryStream(data, 0, data.Length, false, publiclyVisible)) {
+
      // 内部バッファを取得 (UnauthorizedAccessExceptionがスローされる)
+
      byte[] buffer = stream.GetBuffer();
+

          
+
      Console.WriteLine("Length = {0}", buffer.Length);
+
      Console.WriteLine(BitConverter.ToString(buffer));
+
      Console.WriteLine("buffer == data", buffer == data);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim data() As Byte = New Byte() {&h01, &h23, &h45, &h67, &h89, &hAB, &hCD, &hEF}
+

          
+
    ' publiclyVisibleにtrueを指定してMemoryStreamを作成
+
    Dim publiclyVisible As Boolean = True
+

          
+
    Console.WriteLine("publiclyVisible = {0}", publiclyVisible)
+

          
+
    Using stream As New MemoryStream(data, 0, data.Length, False, publiclyVisible)
+
      ' 内部バッファを取得
+
      Dim buffer() As Byte = stream.GetBuffer()
+

          
+
      Console.WriteLine("Length = {0}", buffer.Length)
+
      Console.WriteLine(BitConverter.ToString(buffer))
+
      Console.WriteLine("buffer Is data : {0}", buffer Is data)
+
    End Using
+

          
+
    Console.WriteLine()
+

          
+
    ' publiclyVisibleにfalseを指定してMemoryStreamを作成
+
    publiclyVisible = false
+

          
+
    Console.WriteLine("publiclyVisible = {0}", publiclyVisible)
+

          
+
    Using stream As New MemoryStream(data, 0, data.Length, false, publiclyVisible)
+
      ' 内部バッファを取得 (UnauthorizedAccessExceptionがスローされる)
+
      Dim buffer() As Byte = stream.GetBuffer()
+

          
+
      Console.WriteLine("Length = {0}", buffer.Length)
+
      Console.WriteLine(BitConverter.ToString(buffer))
+
      Console.WriteLine("buffer Is data", buffer Is data)
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
publiclyVisible = True
+
Length = 8
+
01-23-45-67-89-AB-CD-EF
+
buffer Is data : True
+

          
+
publiclyVisible = False
+

          
+
ハンドルされていない例外: System.UnauthorizedAccessException: MemoryStream の内部バッファーにアクセスできません。
+
   場所 System.IO.MemoryStream.GetBuffer()
+
   場所 Sample.Main()
+
}}
+

          
+
GetBufferメソッドは、常に''MemoryStreamが使用しているバッファと同一のインスタンスを返します''。 従って、GetBufferメソッドで得られるバイト配列の内容を変更すると、MemoryStreamで読み込まれる結果にも影響することになります。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    byte[] initialData = new byte[] {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF};
+

          
+
    // ストリームへの書き込みは許可しないが、バッファの取得は許可するMemoryStreamを作成
+
    using (MemoryStream stream = new MemoryStream(initialData, 0, initialData.Length, false, true)) {
+
      // 内部バッファを取得
+
      byte[] buffer = stream.GetBuffer();
+

          
+
      // 内部バッファの内容をクリアする
+
      Array.Clear(buffer, 0, buffer.Length);
+

          
+
      // Readメソッドで読み込む
+
      byte[] data = new byte[8];
+

          
+
      stream.Read(data, 0, data.Length);
+

          
+
      // 読み込んだ内容を表示する
+
      Console.WriteLine(BitConverter.ToString(data));
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim initialData() As Byte = New Byte() {&h01, &h23, &h45, &h67, &h89, &hAB, &hCD, &hEF}
+

          
+
    ' ストリームへの書き込みは許可しないが、バッファの取得は許可するMemoryStreamを作成
+
    Using stream As New MemoryStream(initialData, 0, initialData.Length, False, True)
+
      ' 内部バッファを取得
+
      Dim buffer() As Byte = stream.GetBuffer()
+

          
+
      ' 内部バッファの内容をクリアする
+
      Array.Clear(buffer, 0, buffer.Length)
+

          
+
      ' Readメソッドで読み込む
+
      Dim data(7) As Byte
+

          
+
      stream.Read(data, 0, data.Length)
+

          
+
      ' 読み込んだ内容を表示する
+
      Console.WriteLine(BitConverter.ToString(data))
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
00-00-00-00-00-00-00-00
+
}}
+

          
+

          
+

          
+

          
+
#navi(..)
+

          

programming/netfx/stream/index.wiki.txt~

current previous
1,11 0,0
+
${smdncms:title,ストリーム}
+
${smdncms:keywords,ストリーム,Stream}
+

          
+
ここでは.NET Frameworkにおけるストリームと、ストリームを扱うクラスである&msdn(netfx,type,System.IO.Stream){Stremクラス};と、Streamクラスを使ったデータの読み込み・書き込みについて解説します。 また、[[FileStream>programming/netfx/stream/1_1_filestream]]や[[MemoryStream>programming/netfx/stream/1_2_memorystream]]といったStreamの具象クラス、[[StreamReader・StreamWriter>programming/netfx/stream/2_streamreader_streamwriter]]や[[BinaryReader・BinaryWriter>programming/netfx/stream/3_binaryreader_binarywriter]]といったStreamに対する読み込み・書き込みを行うクラスとその使用方法についても解説します。
+

          
+
#googleadunit(banner)
+

          
+
-ページ一覧
+
#ls2_1(noroot,pathsort)
+

          
+

          

programming/netfx/stream/index.wiki.txt

current previous
1,11 0,0
+
${smdncms:title,ストリーム}
+
${smdncms:keywords,ストリーム,Stream}
+

          
+
ここでは.NET Frameworkにおけるストリームと、ストリームを扱うクラスである&msdn(netfx,type,System.IO.Stream){Stremクラス};と、Streamクラスを使ったデータの読み込み・書き込みについて解説します。 また、[[FileStream>programming/netfx/stream/1_1_filestream]]や[[MemoryStream>programming/netfx/stream/1_2_memorystream]]といったStreamの具象クラス、[[StreamReader・StreamWriter>programming/netfx/stream/2_streamreader_streamwriter]]や[[BinaryReader・BinaryWriter>programming/netfx/stream/3_binaryreader_binarywriter]]といったStreamに対する読み込み・書き込みを行うクラスとその使用方法についても解説します。
+

          
+
#googleadunit(banner)
+

          
+
-ページ一覧
+
#ls2_1(noroot,pathsort)
+

          
+

          

programming/netfx/stream/2_streamreader_streamwriter/index.wiki.txt

current previous
1,1812 0,0
+
${smdncms:title,StreamReaderクラス・StreamWriterクラス}
+
${smdncms:header_title,StreamReaderクラス・StreamWriterクラス (System.IO)}
+
${smdncms:keywords,テキスト,ファイル,読み込み,書き込み,エンコーディング,StreamReader,StreamWriter,ReadLine,ReadToEnd,WriteLine,Encoding,File.ReadAllText,File.ReadToEnd,File.WriteAllText,File.OpenText}
+
${smdncms:document_versions,codelang=cs,codelang=vb}
+

          
+
#navi(..)
+

          
+
-関連するページ
+
--[[programming/netfx/tips/determine_shiftjis_eucjp]]
+
--[[programming/netfx/tips/unicode_encoding_bom]]
+
--[[programming/netfx/fcl/Microsoft.VisualBasic.FileIO.TextFieldParser]]
+
--[[programming/netfx/string]]
+
---[[programming/netfx/string/4_stringbuilder]]
+
---[[programming/netfx/string/5_stringreaderwriter]]
+
--[[programming/netfx/environment]]
+
---[[programming/netfx/environment/0_platform#SystemAndPlatform_NewLine]]
+
---[[programming/netfx/environment/1_process#LocaleAndCulture_DefaultEncoding]]
+
--[[programming/netfx/conversion]]
+

          
+
#googleadunit
+

          
+
&msdn(netfx,type,System.IO.StreamReader){StreamReaderクラス};および&msdn(netfx,type,System.IO.StreamWriter){StreamWriterクラス};はStreamに対してテキストの読み書きを行うためのクラスです。 Stream単体ではバイナリレベルでの読み書きしか行えませんが、StreamとStreamReader・StreamWriterを組み合わせて使うことでテキストレベルの読み書きが可能になり、ファイルに対して1行ずつ読み書きするといったことができるようになります。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    // ファイルsample.txtを書き込み用に開く
+
    using (Stream stream = File.OpenWrite("sample.txt")) {
+
      // streamに書き込むためのStreamWriterを作成
+
      using (StreamWriter writer = new StreamWriter(stream)) {
+
        // 文字列を改行付きで書き込む
+
        writer.WriteLine("Hello, world!");
+
      }
+
    }
+

          
+
    // ファイルsample.txtを読み込み用に開く
+
    using (Stream stream = File.OpenRead("sample.txt")) {
+
      // streamから読み込むためのStreamReaderを作成
+
      using (StreamReader reader = new StreamReader(stream)) {
+
        // 文字列を一行読み込んで表示する
+
        Console.WriteLine(reader.ReadLine());
+
      }
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub Main()
+
    ' ファイルsample.txtを書き込み用に開く
+
    Using stream As Stream = File.OpenWrite("sample.txt")
+
      ' streamに書き込むためのStreamWriterを作成
+
      Using writer As New StreamWriter(stream)
+
        ' 文字列を改行付きで書き込む
+
        writer.WriteLine("Hello, world!")
+
      End Using
+
    End Using
+

          
+
    ' ファイルsample.txtを読み込み用に開く
+
    Using stream As Stream = File.OpenRead("sample.txt")
+
      ' streamから読み込むためのStreamReaderを作成
+
      Using reader As New StreamReader(stream)
+
        ' 文字列を一行読み込んで表示する
+
        Console.WriteLine(reader.ReadLine())
+
      End Using
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
なお、StreamReader・StreamWriterは&msdn(netfx,type,System.IO.TextReader){TextReader};・&msdn(netfx,type,System.IO.TextWriter){TextWriter};から派生したクラスです。 同じくTextReader・TextWriterから派生したクラスに[[StringReader・StringWriter>programming/netfx/string/5_stringreaderwriter]]が存在します。 こちらはStreamのかわりにString・[[StringBuilder>programming/netfx/string/4_stringbuilder]]に対してテキストの読み書きを行うためのクラスです。
+

          
+
[[StreamReaderのメソッド>#StreamReader]]および[[StreamWriterのメソッド>#StreamWriter]]はどれもTextReader・TextWriterを継承したもので、そのほとんどはStringReader・StringWriterでも同じように動作します。
+

          
+
*StreamReader・StreamWriterとエンコーディング [#StreamReaderStreamWriter_Encoding]
+
StreamReader・StreamWriterでは、&msdn(netfx,type,System.Text.Encoding){Encodingクラス};を使った文字列のデコード・エンコードを行う機能が組み込まれています。 コンストラクタに目的のEncodingインスタンスを指定するだけで、UTF-8を始め、Shift_JISやEUC-JPなどの文字コードを深く意識すること無く簡単に扱うことができます。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+
using System.Text;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    using (Stream stream = File.OpenWrite("sample-utf8.txt")) {
+
      // UTF-8でエンコードして書き込むためのStreamWriterを作成
+
      using (StreamWriter writer = new StreamWriter(stream, Encoding.UTF8)) {
+
        // 文字列はUTF-8にエンコードされた上でstreamに書き込まれる
+
        writer.WriteLine("こんにちは世界");
+
      }
+
    }
+

          
+
    using (Stream stream = File.OpenWrite("sample-shiftjis.txt")) {
+
      // Shift_JISでエンコードして書き込むためのStreamWriterを作成
+
      using (StreamWriter writer = new StreamWriter(stream, Encoding.GetEncoding("Shift_JIS"))) {
+
        // 文字列はShift_JISにエンコードされた上でstreamに書き込まれる
+
        writer.WriteLine("こんにちは世界");
+
      }
+
    }
+

          
+
    using (Stream stream = File.OpenRead("sample-utf8.txt")) {
+
      // UTF-8でデコードして読み込むためのStreamReaderを作成
+
      using (StreamReader reader = new StreamReader(stream, Encoding.UTF8)) {
+
        // streamから読み込んだ文字列はUTF-8でデコードされて返される
+
        Console.WriteLine(reader.ReadLine());
+
      }
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+
Imports System.Text
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Using stream As Stream = File.OpenWrite("sample-utf8.txt")
+
      ' UTF-8でエンコードして書き込むためのStreamWriterを作成
+
      Using writer As New StreamWriter(stream, Encoding.UTF8)
+
        ' 文字列はUTF-8にエンコードされた上でstreamに書き込まれる
+
        writer.WriteLine("こんにちは世界")
+
      End Using
+
    End Using
+

          
+
    Using stream As Stream = File.OpenWrite("sample-shiftjis.txt")
+
      ' Shift_JISでエンコードして書き込むためのStreamWriterを作成
+
      Using writer As New StreamWriter(stream, Encoding.GetEncoding("Shift_JIS"))
+
        ' 文字列はShift_JISにエンコードされた上でstreamに書き込まれる
+
        writer.WriteLine("こんにちは世界")
+
      End Using
+
    End Using
+

          
+
    Using stream As Stream = File.OpenRead("sample-utf8.txt")
+
      ' UTF-8でデコードして読み込むためのStreamReaderを作成
+
      Using reader As New StreamReader(stream, Encoding.UTF8)
+
        ' streamから読み込んだ文字列はUTF-8でデコードされて返される
+
        Console.WriteLine(reader.ReadLine())
+
      End Using
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
Shift_JIS以外にも、&msdn(netfx,member,System.Text.Encoding.GetEncoding){Encoding.GetEncodingメソッド};にコードページ番号やエンコーディング名を指定することで目的の文字コードに対応したEncodingを取得することができます。 Encodingを指定しなかった場合には、デフォルトでUTF-8が使用されます。 実行環境の[[デフォルトのエンコーディング>programming/netfx/environment/1_process#LocaleAndCulture_DefaultEncoding]]ではないので注意してください。 読み込もうとしているStreamのエンコーディングとStreamReaderに指定するエンコーディングが異なる場合は、当然文字化けが起こるので注意してください。
+

          
+
またStreamWriterでは、Encodingの指定の仕方によってはバイト順マーク(BOM)が書き込まれます。 BOMの扱いについては[[programming/netfx/tips/unicode_encoding_bom]]で詳しく解説していますので必要に応じて参照してください。
+

          
+
*ファイルからの読み込み・書き込み [#StreamReaderStreamWriter_ConstructWithFileName]
+
ファイルからの読み書きを行う場合、StreamReader・StreamWriterではFileStreamインスタンスの作成を省略することが出来ます。 StreamReader・StreamWriterでは、コンストラクタでStreamのかわりにファイル名を指定すると、そのファイルに対して読み書きを行うStreamReader・StreamWriterを作成することができます。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    // ファイルsample.txtに書き込むためのStreamWriterを作成
+
    using (StreamWriter writer = new StreamWriter("sample.txt")) {
+
      // 文字列を改行付きで書き込む
+
      writer.WriteLine("Hello, world!");
+
    }
+

          
+
    // ファイルsample.txtから読み込むためのStreamReaderを作成
+
    using (StreamReader reader = new StreamReader("sample.txt")) {
+
      // 文字列を一行読み込んで表示する
+
      Console.WriteLine(reader.ReadLine());
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub Main()
+
    ' ファイルsample.txtに書き込むためのStreamWriterを作成
+
    Using writer As New StreamWriter("sample.txt")
+
      ' 文字列を改行付きで書き込む
+
      writer.WriteLine("Hello, world!")
+
    End Using
+

          
+
    ' ファイルsample.txtから読み込むためのStreamReaderを作成
+
    Using reader As New StreamReader("sample.txt")
+
      ' 文字列を一行読み込んで表示する
+
      Console.WriteLine(reader.ReadLine())
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
[[Fileクラスのメソッド>#File_OpenTextCreateTextAppendText]]を使うことでもStreamReader・StreamWriterのインスタンスを作成することができます。
+

          
+

          
+

          
+
*StreamReader [#StreamReader]
+
ここではStreamReaderの使い方について解説します。 このセクションで紹介するサンプルコードでは、簡単化のため[[ファイル名を指定してStreamReaderを作成>#StreamReaderStreamWriter_ConstructWithFileName]]していますが、FileStreamやMemoryStreamなどのStreamを指定してStreamReaderのインスタンスを生成した場合も同じように動作します。 また、[[エンコーディングの指定>#StreamReaderStreamWriter_Encoding]]も省略しています。 サンプル中で使用されるファイルsample.txtは、UTF-8でエンコードされているテキストファイルを想定しています。
+

          
+
**1行ずつの読み込み (ReadLine) [#StreamReader.ReadLine]
+
&msdn(netfx,member,System.IO.StreamReader.ReadLine){ReadLineメソッド};は、ストリームから1行分の文字列を読み込みます。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    using (StreamReader reader = new StreamReader("sample.txt")) {
+
      // 一行分読み込む
+
      string line = reader.ReadLine();
+

          
+
      Console.WriteLine("line 1 : {0}", line);
+

          
+
      // 次の行を読み込む
+
      line = reader.ReadLine();
+

          
+
      Console.WriteLine("line 2 : {0}", line);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Using reader As New StreamReader("sample.txt")
+
      ' 一行分読み込む
+
      Dim line As String = reader.ReadLine()
+

          
+
      Console.WriteLine("line 1 : {0}", line)
+

          
+
      ' 次の行を読み込む
+
      line = reader.ReadLine()
+

          
+
      Console.WriteLine("line 2 : {0}", line)
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
&msdn(netfx,member,System.IO.StreamReader.EndOfStream){EndOfStreamプロパティ};を参照すると、ストリームの末尾まで読み込んだかどうかを調べることができます。 これらを組み合わせてストリームの末尾までを一行ずつ読み込むには次のようにします。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    using (StreamReader reader = new StreamReader("sample.txt")) {
+
      // 行番号
+
      int lineNumber = 1;
+

          
+
      // 無限ループ
+
      for (;;) {
+
        if (reader.EndOfStream)
+
          // ストリームの末尾(EOF)に達したので読み込みを終了する
+
          break;
+

          
+
        // 一行分読み込む
+
        string line = reader.ReadLine();
+

          
+
        // 読み込んだ行に行番号を付けて表示する
+
        Console.WriteLine("{0}: {1}", lineNumber, line);
+

          
+
        lineNumber++;
+
      }
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Using reader As New StreamReader("sample.txt")
+
      ' 行番号
+
      Dim lineNumber As Integer = 1
+

          
+
      ' 無限ループ
+
      Do
+
        If reader.EndOfStream Then
+
          ' ストリームの末尾(EOF)に達したので読み込みを終了する
+
         Exit Do
+
       End If
+

          
+
        ' 一行分読み込む
+
        Dim line As String = reader.ReadLine()
+

          
+
        ' 読み込んだ行に行番号を付けて表示する
+
        Console.WriteLine("{0}: {1}", lineNumber, line)
+

          
+
        lineNumber += 1
+
      Loop
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
ReadLineメソッドでは、ストリームの末尾に到達している場合にはnull/Nothingが返されます。 末尾以外の空行(改行文字のみの行)の場合は、null/Nothingではなく長さ0の文字列(String.Empty)が返されます。 ReadLineメソッドの戻り値がnull/Nothingかどうかを調べることでもEOFの判定が行えます。 そのため、上記の例は次のようにも書き換えられます。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    using (StreamReader reader = new StreamReader("sample.txt")) {
+
      // 行番号
+
      int lineNumber = 1;
+

          
+
      // 無限ループ
+
      for (;;) {
+
        // 一行分読み込む
+
        string line = reader.ReadLine();
+

          
+
        if (line == null)
+
          // ストリームの末尾(EOF)に達したので読み込みを終了する
+
          break;
+

          
+
        // 読み込んだ行に行番号を付けて表示する
+
        Console.WriteLine("{0}: {1}", lineNumber, line);
+

          
+
        lineNumber++;
+
      }
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Using reader As New StreamReader("sample.txt")
+
      ' 行番号
+
      Dim lineNumber As Integer = 1
+

          
+
      ' 無限ループ
+
      Do
+
        ' 一行分読み込む
+
        Dim line As String = reader.ReadLine()
+

          
+
        If line Is Nothing Then
+
          ' ストリームの末尾(EOF)に達したので読み込みを終了する
+
          Exit Do 
+
        End If
+

          
+
        ' 読み込んだ行に行番号を付けて表示する
+
        Console.WriteLine("{0}: {1}", lineNumber, line)
+

          
+
        lineNumber += 1
+
      Loop
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
ReadLineメソッドでは、CR+LF、CR(キャリッジリターン)、LF(ラインフィード)の各改行コードまでを1行として扱います。 StreamReaderでは、どの改行コードを行区切りとして扱うかを指定することは出来ません(StreamWriterでは[[StreamWriter.NewLineプロパティ>#StreamWriter.NewLine]]で変更可能です)。
+

          
+
また、ReadLineメソッドの戻り値には改行文字は含まれません。 したがって戻り値に対してchomp/chopなどの操作を行う必要はありませんが、一方、改行文字を維持して1行ずつ読み込むことはできません。 (参考までに、chompには[[String.TrimEndメソッド>programming/netfx/string/1_operations#String.Trim]]が使えます)
+

          
+
なお、読み込み元がファイルに限定される場合はFileクラスのメソッドを使うこともできます。 &msdn(netfx,member,System.IO.File.ReadAllLines){File.ReadAllLinesメソッド};を使うと、ファイルを読み込み行ごとに分割したものを文字列配列として取得できます。 次の例では、File.ReadAllLinesでファイルを読み込み行番号を付けて表示しています。 比較のためにStreamReaderを使って同等の処理を行う例も併記しています。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Collections.Generic;
+
using System.IO;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    // File.ReadAllLinesでファイル全体を読み込んだ後、行番号を付けて表示する
+
    string[] lineArray = File.ReadAllLines("sample.txt");
+

          
+
    for (int index = 0; index < lineArray.Length; index++) {
+
      Console.WriteLine("{0}: {1}", index + 1, lineArray[index]);
+
    }
+

          
+
    // StreamReaderでファイル全体を読み込んだ後、行番号を付けて表示する
+
    List<string> lineList = new List<string>();
+

          
+
    using (StreamReader reader = new StreamReader("sample.txt")) {
+
      for (string line = reader.ReadLine(); line != null; line = reader.ReadLine()) {
+
        lineList.Add(line);
+
      }
+
    }
+

          
+
    for (int index = 0; index < lineList.Count; index++) {
+
      Console.WriteLine("{0}: {1}", index + 1, lineList[index]);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections.Generic
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub Main()
+
    ' File.ReadAllLinesでファイル全体を読み込んだ後、行番号を付けて表示する
+
    Dim lineArray() As String = File.ReadAllLines("sample.txt")
+

          
+
    For index As Integer = 0 To lineArray.Length - 1
+
      Console.WriteLine("{0}: {1}", index + 1, lineArray(index))
+
    Next
+

          
+
    ' StreamReaderでファイル全体を読み込んだ後、行番号を付けて表示する
+
    Dim lineList As New List(Of String)()
+

          
+
    Using reader As New StreamReader("sample.txt")
+
      Dim line As String = reader.ReadLine()
+

          
+
      Do Until line Is Nothing
+
        lineList.Add(line)
+

          
+
        line = reader.ReadLine()
+
      Loop 
+
    End Using
+

          
+
    For index As Integer = 0 To lineList.Count - 1
+
      Console.WriteLine("{0}: {1}", index + 1, lineList(index))
+
    Next
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
.NET Framework 4からは&msdn(netfx,member,System.IO.File.ReadLines){File.ReadLinesメソッド};も使うことができるようになっています。 File.ReadAllLinesはファイル全体の読み込みが終わるまで結果が返されないのに対し、File.ReadLinesでは一行読み込むごとに結果が返されます。 巨大なファイルを読み込む場合や、ファイルの先頭部分のみを読み込みたい場合などではReadAllLinesメソッドを使うよりもReadLinesメソッドを使った方が効率的です。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Collections.Generic;
+
using System.IO;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    // File.ReadLinesでファイルを1行ずつ読み込み、行番号を付けて表示する
+
    int lineNumber = 1;
+

          
+
    foreach (string line in File.ReadLines("sample.txt")) {
+
      Console.WriteLine("{0}: {1}", lineNumber, line);
+

          
+
      lineNumber++;
+
    }
+

          
+
    // StreamReaderでファイルを1行ずつ読み込み、行番号を付けて表示する
+
    lineNumber = 1;
+

          
+
    using (StreamReader reader = new StreamReader("sample.txt")) {
+
      foreach (string line in ReadLines(reader)) {
+
        Console.WriteLine("{0}: {1}", lineNumber, line);
+

          
+
        lineNumber++;
+
      }
+
    }
+
  }
+

          
+
  // File.ReadLinesに相当する処理をStreamReaderに対して行えるようにするメソッド
+
  private static IEnumerable<string> ReadLines(StreamReader reader)
+
  {
+
    for (;;) {
+
      string line = reader.ReadLine();
+

          
+
      if (line == null)
+
        yield break;
+
      else
+
        yield return line;
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections.Generic
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub Main()
+
    ' File.ReadLinesでファイルを1行ずつ読み込み、行番号を付けて表示する
+
    Dim lineNumber As Integer = 1
+

          
+
    For Each line As String In File.ReadLines("sample.txt")
+
      Console.WriteLine("{0}: {1}", lineNumber, line)
+

          
+
      lineNumber += 1
+
    Next
+

          
+
    ' StreamReaderでファイルを1行ずつ読み込み、行番号を付けて表示する
+
    lineNumber = 1
+

          
+
    Using reader As New StreamReader("sample.txt")
+
      For Each line As String In ReadLines(reader)
+
        Console.WriteLine("{0}: {1}", lineNumber, line)
+

          
+
        lineNumber += 1
+
      Next
+
    End Using
+
  End Sub
+

          
+
  ' File.ReadLinesに相当する処理をStreamReaderに対して行えるようにするメソッド
+
  Private Shared Iterator Function ReadLines(ByVal reader As StreamReader) As IEnumerable(Of String)
+
    Do
+
      Dim line As String = reader.ReadLine()
+

          
+
      If line Is Nothing Then
+
        Exit Function
+
      Else
+
        Yield line
+
      End If
+
    Loop
+
  End Function
+
End Class
+
}}
+
#tabpage-end
+

          
+
**全テキストの読み込み (ReadToEnd) [#StreamReader.ReadToEnd]
+
&msdn(netfx,member,System.IO.StreamReader.ReadToEnd){ReadToEndメソッド};は、ストリームの現在位置から末尾までをひとつながりの文字列として読み込みます。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    using (StreamReader reader = new StreamReader("sample.txt")) {
+
      // ストリームの末尾まですべてを読み込む
+
      string content = reader.ReadToEnd();
+

          
+
      Console.WriteLine(content);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Using reader As New StreamReader("sample.txt")
+
      ' ストリームの末尾まですべてを読み込む
+
      Dim content As String = reader.ReadToEnd()
+

          
+
      Console.WriteLine(content)
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
なお、読み込み元がファイルに限定される場合はFileクラスのメソッドを使うこともできます。 &msdn(netfx,member,System.IO.File.ReadAllText){File.ReadAllTextメソッド};を使うと、StreamReaderを使わずにファイルの内容を文字列として読み込むことができます。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    // File.ReadAllTextでファイル全体を読み込む
+
    string content = File.ReadAllText("sample.txt");
+

          
+
    Console.WriteLine(content);
+

          
+
    // StreamReader.ReadToEndでファイル全体を読み込む
+
    using (StreamReader reader = new StreamReader("sample.txt")) {
+
      content = reader.ReadToEnd();
+

          
+
      Console.WriteLine(content);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub Main()
+
    ' File.ReadAllTextでファイル全体を読み込む
+
    Dim content As String = File.ReadAllText("sample.txt")
+

          
+
    Console.WriteLine(content)
+

          
+
    ' StreamReader.ReadToEndでファイル全体を読み込む
+
    Using reader As New StreamReader("sample.txt")
+
      content = reader.ReadToEnd()
+

          
+
      Console.WriteLine(content)
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
**文字単位での読み込み (Read, Peek) [#StreamReader.Read]
+
&msdn(netfx,member,System.IO.StreamReader.Read){Readメソッド};は、ストリームから''1文字''ずつ読み込みます。 Readメソッドで読み込まれるのは''1バイト''ずつではありません。 戻り値はint/Integerで、ストリームの末尾に達した場合は-1が返されます。 それ以外の場合は読み込めた文字(char)の値となります。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    using (StreamReader reader = new StreamReader("sample.txt")) {
+
      // 無限ループ
+
      for (;;) {
+
        // 一文字読み込む
+
        int ch = reader.Read();
+

          
+
        if (ch == -1)
+
          // ストリームの末尾(EOF)に達したので読み込みを終了する
+
          break;
+

          
+
        // 読み込んだ値をcharにキャストして表示する
+
        char c = (char)ch;
+

          
+
        Console.Write(c);
+
      }
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Using reader As New StreamReader("sample.txt")
+
      ' 無限ループ
+
      Do
+
        ' 一文字読み込む
+
        Dim ch As Integer = reader.Read()
+

          
+
        If ch = -1 Then
+
          ' ストリームの末尾(EOF)に達したので読み込みを終了する
+
          Exit Do
+
        End If
+

          
+
        ' 読み込んだ値をCharに変換して表示する
+
        Dim c As Char = ChrW(ch)
+

          
+
        Console.Write(c)
+
      Loop
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
&msdn(netfx,member,System.IO.StreamReader.Peek){Peekメソッド};を使うと、次の1文字を先読みすることができます。 Peekメソッドの戻り値はReadメソッドの戻り値と同様です。 次の例では、ReadメソッドとPeekメソッドを使って読み込みを行い、各行に行番号を付けて表示しています。 この例ではCR, LF, CR+LFを改行として扱い、それらの改行文字は変換せずそのまま表示しています。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    using (StreamReader reader = new StreamReader("sample.txt")) {
+
      int lineNumber = 1;
+

          
+
      Console.Write("{0}: ", lineNumber);
+

          
+
      // 無限ループ
+
      for (;;) {
+
        // 一文字読み込む
+
        int ch = reader.Read();
+

          
+
        if (ch == -1)
+
          // ストリームの末尾(EOF)に達したので読み込みを終了する
+
          break;
+

          
+
        // 値をcharにキャストして表示
+
        char c = (char)ch;
+

          
+
        Console.Write(c);
+

          
+
        // 読み込んだ文字がCRだった場合
+
        if (c == '\r') {
+
          // 次の一文字を読み込む
+
          if (reader.Peek() == (int)'\n')
+
            // 現在のCRにLFが後続するので、ここでは何もせず処理を続ける
+
            // (次のループでLFが読まれる)
+
            continue;
+
          else
+
            // CR単独の改行なので、行番号を表示する
+
            Console.Write("{0}: ", ++lineNumber);
+
        }
+
        // 読み込んだ文字がLFだった場合
+
        else if (c == '\n') {
+
          // LF単独もしくはCR+LFの改行なので、行番号を表示する
+
          Console.Write("{0}: ", ++lineNumber);
+
        }
+
      }
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Using reader As New StreamReader("sample.txt")
+
      Dim lineNumber As Integer = 1
+

          
+
      Console.Write("{0}: ", lineNumber)
+

          
+
      ' 無限ループ
+
      Do
+
        ' 一文字読み込む
+
        Dim ch As Integer = reader.Read()
+

          
+
        If ch = -1 Then
+
          ' ストリームの末尾(EOF)に達したので読み込みを終了する
+
          Exit Do
+
        End If
+

          
+
        ' 値をCharに変換して表示
+
        Dim c As Char = ChrW(ch)
+

          
+
        Console.Write(c)
+

          
+
        ' 読み込んだ文字がCRだった場合
+
        If ch = AscW(vbCr) Then
+
          ' 次の一文字を読み込む
+
          If reader.Peek() = AscW(vbLf)
+
            ' 現在のCRにLFが後続するので、ここでは何もせず処理を続ける
+
            ' (次のループでLFが読まれる)
+
          Else
+
            ' CR単独の改行なので、行番号を表示する
+
            lineNumber += 1
+

          
+
            Console.Write("{0}: ", lineNumber)
+
          End If
+
        ' 読み込んだ文字がLFだった場合
+
        Else If ch = AscW(vbLf)
+
          ' LF単独もしくはCR+LFの改行なので、行番号を表示する
+
          lineNumber += 1
+

          
+
          Console.Write("{0}: ", lineNumber)
+
        End If
+
      Loop
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
引数を指定せずにReadメソッドを呼び出した場合は1文字ずつの読み込みが行われますが、Readメソッドでは読み込み先のバッファと文字数を指定して読み込むこともできるようになっています。 文字を1文字ずつチェックする必要がある場合などでは、Readメソッドで1文字ずつ読み込んでチェックするよりも、バッファに複数文字読み込んでチェックした方がメソッド呼び出しの回数が少なくなり効率的です。 次の例では、Readメソッドで一旦バッファに読み込んでから1文字ずつチェックして全角英字を半角英字に置き換えています。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    using (StreamReader reader = new StreamReader("sample.txt")) {
+
      // 読み込んだ文字を格納しておくためのバッファ (32文字分)
+
      char[] buffer = new char[32];
+

          
+
      for (;;) {
+
        // StreamReaderから読み込んでバッファに格納する
+
        int len = reader.Read(buffer, 0, buffer.Length);
+

          
+
        if (len == 0)
+
          // ストリームの末尾(EOF)に達したので読み込みを終了する
+
          break;
+

          
+
        // 読み込んだ文字を1文字ずつ検査して全角英字を半角英字に変換する
+
        for (int i = 0; i < len; i++) {
+
          if ('A' <= buffer[i] && buffer[i] <= 'Z')
+
            buffer[i] = (char)((int)buffer[i] - (int)'A' + (int)'A');
+
          else if ('a' <= buffer[i] && buffer[i] <= 'z')
+
            buffer[i] = (char)((int)buffer[i] - (int)'a' + (int)'a');
+
        }
+

          
+
        // bufferを文字列に変換して表示
+
        Console.Write(new string(buffer, 0, len));
+
      }
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Using reader As New StreamReader("sample.txt")
+
      ' 読み込んだ文字を格納しておくためのバッファ (32文字分)
+
      Dim buffer(31) As Char
+

          
+
      Do
+
        ' StreamReaderから読み込んでバッファに格納する
+
        Dim len As Integer = reader.Read(buffer, 0, buffer.Length)
+

          
+
        If len = 0 Then
+
          ' ストリームの末尾(EOF)に達したので読み込みを終了する
+
          Exit Do
+
        End If
+

          
+
        ' 読み込んだ文字を1文字ずつ検査して全角英字を半角英字に変換する
+
        For i As Integer = 0 To len - 1
+
          If "A"c <= buffer(i) AndAlso buffer(i) <= "Z"c Then
+
            buffer(i) = ChrW(AscW(buffer(i)) - AscW("A") + AscW("A"))
+
          Else If "a"c <= buffer(i) AndAlso buffer(i) <= "z"c Then
+
            buffer(i) = ChrW(AscW(buffer(i)) - AscW("a") + AscW("a"))
+
          End If
+
        Next
+

          
+
        ' bufferを文字列に変換して表示
+
        Console.Write(New String(buffer, 0, len))
+
      Loop
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(sample.txtの内容){{
+
abcdefghijklmnopqrstuvwxyz
+
ABCDEFGHIJKLMNOPQRSTUVWXYZ
+
abcdefghijklmnopqrstuvwxyz
+
ABCDEFGHIJKLMNOPQRSTUVWXYZ
+
0123456789
+
0123456789
+
あいうアイウ漢字
+
}}
+

          
+
#prompt(出力結果){{
+
abcdefghijklmnopqrstuvwxyz
+
ABCDEFGHIJKLMNOPQRSTUVWXYZ
+
abcdefghijklmnopqrstuvwxyz
+
ABCDEFGHIJKLMNOPQRSTUVWXYZ
+
0123456789
+
0123456789
+
あいうアイウ漢字
+
}}
+

          
+

          
+
**ブロッキングを行う読み込み (ReadBlock) [#StreamReader.ReadBlock]
+
&msdn(netfx,member,System.IO.StreamReader.ReadBlock){ReadBlockメソッド};は、読み込み先のバッファと文字数を指定してReadメソッドを呼び出した場合と基本的には同じです。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    char[] buffer = new char[32];
+

          
+
    using (StreamReader reader = new StreamReader("sample.txt")) {
+
      // Readメソッドを使ってストリームの末尾に達するまで読み込みを行い、内容を表示する
+
      for (;;) {
+
        int len = reader.Read(buffer, 0, buffer.Length);
+

          
+
        if (len == 0)
+
          break;
+

          
+
        Console.Write(new string(buffer, 0, len));
+
      }
+
    }
+

          
+
    using (StreamReader reader = new StreamReader("sample.txt")) {
+
      // ReadBlockメソッドを使ってストリームの末尾に達するまで読み込みを行い、内容を表示する
+
      for (;;) {
+
        int len = reader.ReadBlock(buffer, 0, buffer.Length);
+
        
+
        if (len == 0)
+
          break;
+

          
+
        Console.Write(new string(buffer, 0, len));
+
      }
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim buffer(31) As Char
+

          
+
    Using reader As New StreamReader("sample.txt")
+
      ' Readメソッドを使ってストリームの末尾に達するまで読み込みを行い、内容を表示する
+
      Do
+
        Dim len As Integer = reader.Read(buffer, 0, buffer.Length)
+

          
+
        If len = 0 Then Exit Do
+

          
+
        Console.Write(New String(buffer, 0, len))
+
      Loop
+
    End Using
+

          
+
    Using reader As New StreamReader("sample.txt")
+
      ' ReadBlockメソッドを使ってストリームの末尾に達するまで読み込みを行い、内容を表示する
+
      Do
+
        Dim len As Integer = reader.ReadBlock(buffer, 0, buffer.Length)
+
        
+
        If len = 0 Then Exit Do
+

          
+
        Console.Write(New String(buffer, 0, len))
+
      Loop
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
ReadメソッドとReadBlockメソッドの違いは、読み込みに際して''ブロッキング''が行われるかどうかという点にあります。 Readメソッドではブロッキングされませんが、ReadBlockメソッドではブロッキングされます。
+

          
+
ReadBlockメソッドは、ストリームの末尾に到達するか、''指定された文字数の読み込みが終わるまで処理を返しません''。 一方Readメソッドは、ストリームの末尾に到達した場合のほか、''指定された文字数よりも少ない文字数しか読み込めなかった場合でも処理を返します''。 これはNetworkStreamを使った読み込み中にデータの途中までを受信した場合などに起こる可能性があります(FileStreamやMemoryStreamでは通常起こらないと思われます)。 従って、データの途中でも読み込みができた時点で結果を返させるようにしたければReadメソッド、指定した文字数を読み込めた時点で結果を返させるようにしたい場合にはReadBlockメソッドを使います。
+

          
+
こういった動作の違いについては、[[Stream.Readメソッドの動作>programming/netfx/stream/0_abstract#Stream.Read]]についてもあわせてご覧ください。
+

          
+

          
+

          
+

          
+
*StreamWriter [#StreamWriter]
+
ここではStreamWriterの使い方について解説します。 このセクションで紹介するサンプルコードでは、簡単化のため[[ファイル名を指定してStreamWriterを作成>#StreamReaderStreamWriter_ConstructWithFileName]]していますが、FileStreamやMemoryStreamなどのStreamを指定してStreamWriterのインスタンスを生成した場合も同じように動作します。 また、[[エンコーディングの指定>#StreamReaderStreamWriter_Encoding]]も省略しています。
+

          
+
**改行付きの書き込み (WriteLine) [#StreamWriter.WriteLine]
+
&msdn(netfx,member,System.IO.StreamWriter.WriteLine){WriteLineメソッド};は、ストリームに1行分の文字列を書き込みます。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    using (StreamWriter writer = new StreamWriter("sample.txt")) {
+
      // 1行目を書き込む
+
      writer.WriteLine("line 1");
+

          
+
      // 2行目を書き込む
+
      writer.WriteLine("line 2");
+

          
+
      // 3行目を書き込む
+
      writer.WriteLine("line 3");
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Using writer As New StreamWriter("sample.txt")
+
      ' 1行目を書き込む
+
      writer.WriteLine("line 1")
+

          
+
      ' 2行目を書き込む
+
      writer.WriteLine("line 2")
+

          
+
      ' 3行目を書き込む
+
      writer.WriteLine("line 3")
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
WriteLineメソッドでは、書き込みの際に改行文字が付け加えられます。 デフォルトでは改行文字として[[プラットフォームの改行文字>programming/netfx/environment/0_platform#SystemAndPlatform_NewLine]]が使われますが、[[NewLineプロパティ>#StreamWriter.NewLine]]に値を設定することで使用する改行文字を変更することができます。
+

          
+
また、WriteLineメソッドに文字列以外を引数に指定した場合は、文字列に変換した上で書き込まれます。 [[複合書式設定>programming/netfx/string_formatting/0_formatstrings#CompositeFormatting]]を使用することで書式を指定したり0埋め・右詰め・左詰めした上で書き込むこともできます。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    using (StreamWriter writer = new StreamWriter("sample.txt")) {
+
      // 数値を書き込む
+
      writer.WriteLine(16);
+
      writer.WriteLine(Math.PI);
+

          
+
      // 現在の日付を書き込む
+
      writer.WriteLine(DateTime.Now);
+

          
+
      // 複数の値を一行に書き込む
+
      writer.WriteLine("{0} {1} {2:hh:mm}", 42, 72, DateTime.Now);
+

          
+
      writer.WriteLine("|{0,10:D6}|", 12345);  // 数値を幅10・6桁に0埋めして右揃え
+
      writer.WriteLine("|{0,-10:D6}|", 12345); // 数値を幅10・6桁に0埋めして左揃え
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Using writer As New StreamWriter("sample.txt")
+
      ' 数値を書き込む
+
      writer.WriteLine(16)
+
      writer.WriteLine(Math.PI)
+

          
+
      ' 現在の日付を書き込む
+
      writer.WriteLine(DateTime.Now)
+

          
+
      ' 複数の値を一行に書き込む
+
      writer.WriteLine("{0} {1} {2:hh:mm}", 42, 72, DateTime.Now)
+

          
+
      writer.WriteLine("|{0,10:D6}|", 12345)  ' 数値を幅10・6桁に0埋めして右揃え
+
      writer.WriteLine("|{0,-10:D6}|", 12345) ' 数値を幅10・6桁に0埋めして左揃え
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
文字列への変換に際して、現在のスレッドのカルチャが書式プロバイダとして使用されます。 これは&msdn(netfx,member,System.IO.StreamWriter.FormatProvider){FormatProviderプロパティ};で参照可能です。 書式指定子や書式プロバイダについての詳細は以下のページをご覧ください。
+

          
+
-[[programming/netfx/string_formatting/0_formatstrings]]
+
-[[programming/netfx/locale/0_abstract]]
+
-[[programming/netfx/locale/1_infoes]]
+
-[[programming/netfx/datetime/2_formatting_parsing]]
+

          
+
**改行無しの書き込み (Write) [#StreamWriter.Write]
+
&msdn(netfx,member,System.IO.StreamWriter.Write){Writeメソッド};は、[[WriteLineメソッド>#StreamWriter.WriteLine]]とは異なり書き込みの際に改行文字が追記されません。 それ以外はWriteLineメソッドと同じです。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    using (StreamWriter writer = new StreamWriter("sample.txt")) {
+
      // 数値を書き込む
+
      writer.Write(16);
+
      writer.Write(" ");
+
      writer.Write(Math.PI);
+

          
+
      // 改行文字を書き込む
+
      writer.Write(Environment.NewLine);
+

          
+
      // 複数の値を一行に書き込む
+
      writer.Write("{0} {1} {2:hh:mm}", 42, 72, DateTime.Now);
+

          
+
      // 改行文字を書き込む
+
      writer.Write(Environment.NewLine);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Using writer As New StreamWriter("sample.txt")
+
      ' 数値を書き込む
+
      writer.Write(16)
+
      writer.Write(" ")
+
      writer.Write(Math.PI)
+

          
+
      ' 改行文字を書き込む
+
      writer.Write(Environment.NewLine)
+

          
+
      ' 複数の値を一行に書き込む
+
      writer.Write("{0} {1} {2:hh:mm}", 42, 72, DateTime.Now)
+

          
+
      ' 改行文字を書き込む
+
      writer.Write(Environment.NewLine)
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
書き込む改行文字や改行の位置を細かく指定したい場合にはWriteメソッドを使うことができます。
+

          
+
**改行文字 [#StreamWriter.NewLine]
+
StreamWriterのWriteLineメソッドは、デフォルトではプラットフォームの改行文字を使用します([[programming/netfx/environment/0_platform#SystemAndPlatform_NewLine]])。 &msdn(netfx,member,System.IO.StreamWriter.NewLine){NewLineプロパティ};に値を設定することでStreamWriterが使用する改行文字を変更することができます。 NewLineプロパティではCR(\r)やLF(\n)以外の文字を含めたり、長さ0の文字列を設定することもできます。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    using (StreamWriter writer = new StreamWriter("sample.txt")) {
+
      writer.WriteLine("line1");
+
      writer.WriteLine("line2");
+

          
+
      // 改行文字を変更する
+
      // 改行を表す記号にプラットフォームの改行文字を付けたものを指定する
+
      writer.NewLine = "↵" + Environment.NewLine;
+

          
+
      writer.WriteLine("line3");
+
      writer.WriteLine("line4");
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Using writer As New StreamWriter("sample.txt")
+
      writer.WriteLine("line1")
+
      writer.WriteLine("line2")
+

          
+
      ' 改行文字を変更する
+
      ' 改行を表す記号にプラットフォームの改行文字を付けたものを指定する
+
      writer.NewLine = "↵" + Environment.NewLine
+

          
+
      writer.WriteLine("line3")
+
      writer.WriteLine("line4")
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(出力されるsample.txtの内容){{
+
line1
+
line2
+
line3↵
+
line4↵
+
}}
+

          
+

          
+
**ファイルへの追記 [#StreamWriter_Append]
+
StreamWriterのコンストラクタでファイル名を指定する場合、同時にファイルを追記モードで開くかどうかを指定することができるようになっています。 コンストラクタの引数&var{append};にtrueを指定すれば、ファイルの末尾から書き込みを開始するようにしたStreamWriterインスタンスが作成されます。 省略した場合やfalseを指定した場合は上書きモードでファイルが開かれ、既存のファイルを開く場合にはその内容が破棄されます。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    // 上書きモードでsample.txtを開く
+
    using (StreamWriter writer = new StreamWriter("sample.txt", false)) {
+
      // 以下の内容はsample.txtに上書きされる
+
      writer.WriteLine("line1");
+
      writer.WriteLine("line2");
+
    }
+

          
+
    // 追記モードでsample.txtを開く
+
    using (StreamWriter writer = new StreamWriter("sample.txt", true)) {
+
      // 以下の内容はsample.txtに追記される
+
      writer.WriteLine("line3");
+
      writer.WriteLine("line4");
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+

          
+
Class Sample
+
  Shared Sub Main()
+
    ' 上書きモードでsample.txtを開く
+
    Using writer As New StreamWriter("sample.txt", False)
+
      ' 以下の内容はsample.txtに上書きされる
+
      writer.WriteLine("line1")
+
      writer.WriteLine("line2")
+
    End Using
+

          
+
    ' 追記モードでsample.txtを開く
+
    Using writer As New StreamWriter("sample.txt", True)
+
      ' 以下の内容はsample.txtに追記される
+
      writer.WriteLine("line3")
+
      writer.WriteLine("line4")
+
    End Using
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(出力されるsample.txtの内容){{
+
line1
+
line2
+
line3
+
line4
+
}}
+

          
+

          
+
**Fileクラスを使った書き込み [#File_WriteAllText]
+
書き込み先がファイルで、書き込む内容がすでに文字列として存在している場合は、Fileクラスのメソッドを使って書き込むこともできます。 &msdn(netfx,member,System.IO.File.WriteAllLines){File.WriteAllTextメソッド};を使うと、指定した文字列を指定したファイルに書き込むことができます。 このメソッドを使うことでStreamWriterを作成せずにファイルへの書き込みが行えるため、書き込み処理の記述を簡略化することができます。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+
using System.Text;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    // ファイルに書き込む内容
+
    string content = @"line1
+
line2
+
line3
+
line4
+
";
+

          
+
    // 文字列contentの内容をUTF-8でエンコードしてsample.txtに書き込む
+
    File.WriteAllText("sample.txt", content, Encoding.UTF8);
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+
Imports System.Text
+

          
+
Class Sample
+
  Shared Sub Main()
+
    ' ファイルに書き込む内容
+
    Dim content As String = _
+
      "line1" + vbNewLine + _
+
      "line2" + vbNewLine + _
+
      "line3" + vbNewLine + _
+
      "line4" + vbNewLine
+

          
+
    ' 文字列contentの内容をUTF-8でエンコードしてsample.txtに書き込む
+
    File.WriteAllText("sample.txt", content, Encoding.UTF8)
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(出力されるsample.txtの内容){{
+
line1
+
line2
+
line3
+
line4
+
}}
+

          
+
File.WriteAllTextメソッドでは既存のファイルに対する書き込みの場合、ファイルの内容は上書きされますが、&msdn(netfx,member,System.IO.File.AppendAllText){File.AppendAllTextメソッド};を使うと既存のファイルの内容に追記することができます。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+
using System.Text;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    // ファイルに上書きする内容
+
    string content = @"line1
+
line2
+
";
+

          
+
    // 文字列contentの内容をsample.txtに上書き
+
    File.WriteAllText("sample.txt", content, Encoding.UTF8);
+

          
+
    // ファイルに追記する内容
+
    content = @"line3
+
line4
+
";
+
    // 文字列contentの内容をsample.txtに追記
+
    File.AppendAllText("sample.txt", content, Encoding.UTF8);
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+
Imports System.Text
+

          
+
Class Sample
+
  Shared Sub Main()
+
    ' ファイルに上書きする内容
+
    Dim content As String = _
+
      "line1" + vbNewLine + _
+
      "line2" + vbNewLine
+

          
+
    ' 文字列contentの内容をsample.txtに上書き
+
    File.WriteAllText("sample.txt", content, Encoding.UTF8)
+

          
+
    ' ファイルに追記する内容
+
    content = _
+
      "line3" + vbNewLine + _
+
      "line4" + vbNewLine
+

          
+
    ' 文字列contentの内容をsample.txtに追記
+
    File.AppendAllText("sample.txt", content, Encoding.UTF8)
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(出力されるsample.txtの内容){{
+
line1
+
line2
+
line3
+
line4
+
}}
+

          
+
&msdn(netfx,member,System.IO.File.WriteAllLines){File.WriteAllLinesメソッド};を使うと、文字列配列の各要素を1行としてファイルに書き込むことができます。 File.WriteAllLinesメソッドでは、書き込みの際に自動的に改行文字が付加されます。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.IO;
+
using System.Text;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    // ファイルに書き込む内容
+
    string[] lines = new string[] {
+
      "line1",
+
      "line2",
+
      "line3",
+
      "line4",
+
    };
+

          
+
    // 配列linesの各要素を1行としてsample.txtに書き込む
+
    File.WriteAllLines("sample.txt", lines, Encoding.UTF8);
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.IO
+
Imports System.Text
+

          
+
Class Sample
+
  Shared Sub Main()
+
    ' ファイルに書き込む内容
+
    Dim lines() As String = New String() { _
+
      "line1", _
+
      "line2", _
+
      "line3", _
+
      "line4" _
+
    }
+

          
+
    ' 配列linesの各要素を1行としてsample.txtに書き込む
+
    File.WriteAllLines("sample.txt", lines, Encoding.UTF8)
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(出力されるsample.txtの内容){{
+
line1
+
line2
+
line3
+
line4
+
}}
+

          
+
.NET Framework 4からは文字列配列だけでなく任意のIEnumerable<string>を指定することもできるようになっています。 そのため、書き込みたい内容がList<string>に格納されている場合でも配列に変換する必要はなくなりました。 また、.NET Framework 4からは&msdn(netfx,member,System.IO.File.AppendAllLines){File.AppendAllLinesメソッド};も追加されていて、このメソッドを使うことで文字列配列をファイルに追記することができます。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Collections.Generic;
+
using System.IO;
+
using System.Text;
+

          
+
class Sample {
+
  static void Main()
+
  {
+
    // ファイルに上書きする内容
+
    List<string> lines = new List<string>();
+

          
+
    lines.Add("line1");
+
    lines.Add("line2");
+

          
+
    // linesの内容をsample.txtに上書き
+
    File.WriteAllLines("sample.txt", lines, Encoding.UTF8);
+

          
+
    // ファイルに追記する内容
+
    lines.Clear();
+
    lines.Add("line3");
+
    lines.Add("line4");
+

          
+
    // linesの内容をsample.txtに追記
+
    File.AppendAllLines("sample.txt", lines, Encoding.UTF8);
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections.Generic
+
Imports System.IO
+
Imports System.Text
+

          
+
Class Sample
+
  Shared Sub Main()
+
    ' ファイルに上書きする内容
+
    Dim lines As New List(Of String)()
+

          
+
    lines.Add("line1")
+
    lines.Add("line2")
+

          
+
    ' linesの内容をsample.txtに上書き
+
    File.WriteAllLines("sample.txt", lines, Encoding.UTF8)
+

          
+
    ' ファイルに追記する内容
+
    lines.Clear()
+
    lines.Add("line3")
+
    lines.Add("line4")
+

          
+
    ' linesの内容をsample.txtに追記
+
    File.AppendAllLines("sample.txt", lines, Encoding.UTF8)
+
  End Sub
+
End Class
+