出会いセンター C#からマルチストリームを扱う方法

C#からマルチストリームを扱う方法

ファイルに関する概要情報の取得」で紹介した、マルチストリームをC#から扱う方法について解説します。 マルチストリームに関しては「ファイルに関する概要情報の取得」のほうで簡単に解説しているのでそちらを 参考にしてください。

ファイルハンドルはCreateFile()で取得する

通常C#からファイルを扱う場合にはFileStreamクラスを使用します。しかし、このFileStreamクラスは マルチストリームをサポートしていません。従って、下記に示すような書式を用いてマルチストリームを 扱うことはできないようです。

[ファイル名]:[ストリーム名]
(例 test.txtというファイルのInformationというストリームの場合)
test.txt:Information

そこでCreateFileというAPI関数を用いてファイルハンドルを取得し、そのハンドルを元にFileStreamを 生成する方法が考えられます。実は、FileSystemObjectをはじめとするマルチストリームをサポートする クラス等は内部でCreateFileを使用しています。では、簡単なサンプルプログラムを以下に示します。 (C:\test.txtが存在することを前提としています。)

using System;
using System.Runtime.InteropServices;
using System.IO;

namespace MultiStreamSample
{
    class Class1
    {
        #region Win32 API宣言

        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        private static extern IntPtr CreateFile(
            string lpFileName, // ファイル名
            DesiredAccess dwDesiredAccess, // アクセスモード
            ShareMode dwShareMode, // 共有モード
            int lpSecurityAttributes, // セキュリティ記述子
            CreationDisposition dwCreationDisposition, // 作成方法
            FlagsAndAttributes dwFlagsAndAttributes, // ファイル属性
            IntPtr hTemplateFile // テンプレートファイルのハンドル
            );

        #region 列挙体

        private enum DesiredAccess : uint
        {
            GENERIC_READ = 0x80000000,
            GENERIC_WRITE = 0x40000000,
            GENERIC_EXECUTE = 0x20000000
        }

        private enum ShareMode : uint
        {
            FILE_SHARE_READ = 0x00000001,
            FILE_SHARE_WRITE = 0x00000002,
            FILE_SHARE_DELETE = 0x00000004
        }

        private enum CreationDisposition : uint
        {
            CREATE_NEW = 1,
            CREATE_ALWAYS = 2,
            OPEN_EXISTING = 3,
            OPEN_ALWAYS = 4,
            TRUNCATE_EXISTING = 5
        }

        private enum FlagsAndAttributes : uint
        {
            FILE_ATTRIBUTE_ARCHIVE = 0x00000020,
            FILE_ATTRIBUTE_ENCRYPTED = 0x00004000,
            FILE_ATTRIBUTE_HIDDEN = 0x00000002,
            FILE_ATTRIBUTE_NORMAL = 0x00000080,
            FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x00002000,
            FILE_ATTRIBUTE_OFFLINE = 0x00001000,
            FILE_ATTRIBUTE_READONLY = 0x00000001,
            FILE_ATTRIBUTE_SYSTEM = 0x00000004,
            FILE_ATTRIBUTE_TEMPORARY = 0x00000100
        }

        #endregion

        #endregion

        [STAThread]
        static void Main(string[] args)
        {
            Console.WriteLine("書き込みの開始");
            IntPtr fileHandle = CreateFile(@"C:\test.txt:config",
                                            DesiredAccess.GENERIC_WRITE,
                                            ShareMode.FILE_SHARE_READ, 0,
                                            CreationDisposition.OPEN_ALWAYS,
                                            FlagsAndAttributes.FILE_ATTRIBUTE_NORMAL,
                                            IntPtr.Zero);
            using(StreamWriter sw = new StreamWriter(new FileStream(fileHandle,
                                                         FileAccess.Write)))
            {
                sw.WriteLine("書き込みテスト用文字列");
            }
            Console.WriteLine("書き込み完了" + Environment.NewLine);
            Console.WriteLine("読み込み開始");
            fileHandle = CreateFile(@"C:\test.txt:config",
                                    DesiredAccess.GENERIC_READ,
                                    ShareMode.FILE_SHARE_READ, 0,
                                    CreationDisposition.OPEN_ALWAYS,
                                    FlagsAndAttributes.FILE_ATTRIBUTE_NORMAL, IntPtr.Zero);
            using(StreamReader sr = new StreamReader(new FileStream(fileHandle,
                                                         FileAccess.Read)))
            {
                Console.WriteLine("---------------------");
                Console.WriteLine(sr.ReadToEnd());
                Console.WriteLine("---------------------");
            }
            Console.WriteLine("読み込み終了");
        }
    }
}

さて、これを利用してアプリケーションの設定をストリームに保存してみようと思います。 この方法はNTFSをサポートするOSでしか機能しませんが、初期化ファイルのように 誤って削除、改変される等の心配がなくなります。また、実行ファイルと一体なので移動やコピー のときにも便利でしょう。では、簡単なサンプルです。

#region using

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

#endregion

namespace SerializeOnNTFSStream
{
    /// <summary>
    /// Form1
    /// </summary>
    public class Form1 : System.Windows.Forms.Form
    {
        /// <summary>
        /// 保存するデータを格納しておく
        /// </summary>
        [Serializable]
        public class SettingData
        {
            public Point FormLocation;
            public Size FormSize;
            public SettingData(Point location, Size size)
            {
                FormLocation = location;
                FormSize = size;
            }
        }

        private System.ComponentModel.Container components = null;

        #region Win32 API宣言

        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        private static extern IntPtr CreateFile(
            string lpFileName, // ファイル名
            DesiredAccess dwDesiredAccess, // アクセスモード
            ShareMode dwShareMode, // 共有モード
            int lpSecurityAttributes, // セキュリティ記述子
            CreationDisposition dwCreationDisposition, // 作成方法
            FlagsAndAttributes dwFlagsAndAttributes, // ファイル属性
            IntPtr hTemplateFile // テンプレートファイルのハンドル
            );

        #region 列挙体

        private enum DesiredAccess : uint
        {
            GENERIC_READ = 0x80000000,
            GENERIC_WRITE = 0x40000000,
            GENERIC_EXECUTE = 0x20000000
        }

        private enum ShareMode : uint
        {
            FILE_SHARE_READ = 0x00000001,
            FILE_SHARE_WRITE = 0x00000002,
            FILE_SHARE_DELETE = 0x00000004
        }

        private enum CreationDisposition : uint
        {
            CREATE_NEW = 1,
            CREATE_ALWAYS = 2,
            OPEN_EXISTING = 3,
            OPEN_ALWAYS = 4,
            TRUNCATE_EXISTING = 5
        }

        private enum FlagsAndAttributes : uint
        {
            FILE_ATTRIBUTE_ARCHIVE = 0x00000020,
            FILE_ATTRIBUTE_ENCRYPTED = 0x00004000,
            FILE_ATTRIBUTE_HIDDEN = 0x00000002,
            FILE_ATTRIBUTE_NORMAL = 0x00000080,
            FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x00002000,
            FILE_ATTRIBUTE_OFFLINE = 0x00001000,
            FILE_ATTRIBUTE_READONLY = 0x00000001,
            FILE_ATTRIBUTE_SYSTEM = 0x00000004,
            FILE_ATTRIBUTE_TEMPORARY = 0x00000100
        }

        #endregion

        #endregion


        #region コンストラクタ

        public Form1()
        {
            InitializeComponent();
        }

        #endregion

        #region Dispose 処理

        /// <summary>
        /// 使用されているリソースに後処理を実行します。
        /// </summary>
        protected override void Dispose( bool disposing )
        {
            if( disposing )
            {
                if (components != null)
                {
                    components.Dispose();
                }
            }
            base.Dispose( disposing );
        }

        #endregion

        #region Windows フォーム デザイナで生成されたコード

        /// <summary>
        /// デザイナ サポートに必要なメソッドです。このメソッドの内容を
        /// コード エディタで変更しないでください。
        /// </summary>
        private void InitializeComponent()
        {
            //
            // Form1
            //
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 12);
            this.ClientSize = new System.Drawing.Size(292, 273);
            this.Name = "Form1";
            this.Text = "Form1";
            this.Load += new System.EventHandler(this.Form1_Load);
            this.Closed += new System.EventHandler(this.Form1_Closed);

        }

        #endregion

        #region メインエントリポイント

        /// <summary>
        /// アプリケーションのメイン エントリ ポイントです。
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.Run(new Form1());
        }

        #endregion

        private void Form1_Load(object sender, System.EventArgs e)
        {
            IFormatter formatter = new BinaryFormatter();
            IntPtr fileHandle = CreateFile(Application.ExecutablePath + ":setting",
                DesiredAccess.GENERIC_READ,
                ShareMode.FILE_SHARE_READ, 0,
                CreationDisposition.OPEN_EXISTING,
                FlagsAndAttributes.FILE_ATTRIBUTE_NORMAL, IntPtr.Zero);
            if(fileHandle.ToInt32() != -1)
            {
                using(Stream s = new FileStream(fileHandle, FileAccess.Read))
                {
                    SettingData setting = (SettingData)formatter.Deserialize(s);
                    this.Location = setting.FormLocation;
                    this.Size = setting.FormSize;
                }
            }

        }

        private void Form1_Closed(object sender, System.EventArgs e)
        {
            IFormatter formatter = new BinaryFormatter();
            IntPtr fileHandle = CreateFile(Application.ExecutablePath + ":setting",
                DesiredAccess.GENERIC_WRITE,
                ShareMode.FILE_SHARE_READ, 0,
                CreationDisposition.OPEN_ALWAYS,
                FlagsAndAttributes.FILE_ATTRIBUTE_NORMAL, IntPtr.Zero);
            if(fileHandle.ToInt32() != -1)
            {
                using(Stream s = new FileStream(fileHandle, FileAccess.Write))
                {
                    SettingData setting = new SettingData(this.Location, this.Size);
                    formatter.Serialize(s, setting);
                }
            }
        }
    }
}

フォームの位置とサイズをシリアル化を使用して保存しています。動作を確認するときは、Visual Studio等のIDEから 開始(実行)してはいけません。これは自分のファイル自身に書き込んでいるためです。従って、実行ファイルを 単独で実行してください。(エクスプローラー等からアイコンをダブルクリック)

出会い 出会い 出会い系 出会い 出会い 出会い 出会い 出会い 出会い オオクワガタ 出会い 出会い 出会い 出会い アクセスカウンター 出会い 出会い 出会い系 出会い 出会い 出会い 出会い 出会い 出会い