カテゴリー
C#

C# で HTTP GET を行う場合の例外処理

C# でHTTPを使ってサーバーからコンテンツを取得する際に起こり得る例外処理を調べて、catch で処理できるようコードを書いてみました。

HTTP ステータスコードの 401(未認証), 403(アクセス拒否) やネットワークケーブルを抜いた場合などは WebException でキャッチできるようです。

参考:
https://msdn.microsoft.com/ja-jp/library/system.net.webrequest(v=vs.80).aspx
https://msdn.microsoft.com/ja-jp/library/system.net.httpwebrequest.getresponse(v=vs.80).aspx
https://www.java2s.com/Code/CSharp/Network/Handlenetworkexceptions.htm
https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html

using System;
using System.Net;
using System.IO;

namespace webget
{
    class WebGet
    {
        static void Main(string[] args)
        {
            if (args.Length < 1)
            {
                Console.WriteLine("URL を指定してください。");
                return;
            }

            WebGet w = new WebGet();

            string s = w.HttpGet(args[0], "");
        }

        public string HttpGet(string URI, string Parameters)
        {
            string res = "";
            Stream dataStream = null;
            StreamReader reader = null;
            HttpWebResponse response = null;

            try
            {
                // URLの HTTP リクエストを作成. 		
                WebRequest request = WebRequest.Create(URI);

                // デフォルトのクレデンシャルを設定.
                request.Credentials = CredentialCache.DefaultCredentials;
                
                // HTTP レスポンスを取得.
                response = (HttpWebResponse)request.GetResponse();

                // ステータスの表示.
                Console.WriteLine(response.StatusDescription);
                
                // サーバーからコンテンツを含むストリームを取得.
                dataStream = response.GetResponseStream();
                
                // ストリームを開く
                reader = new StreamReader(dataStream);

                // コンテンツの読み込み.
                string responseFromServer = reader.ReadToEnd();

                // コンテンツの表示.
                Console.WriteLine(responseFromServer);
            }
            catch (WebException e)
            {
                // ネットワークが切断されているような場合 etc...
                Console.WriteLine("Web 例外 - " + e.Status + " : " + e.Message);
            }
            catch (UriFormatException e)
            {
                // https:///www.northwind.mydns.jp/samples のような場合
                //      ^^^
                Console.WriteLine("URI フォーマット不正: " + e.Message);
            }
            catch (System.Security.Authentication.AuthenticationException e)
            {
                Console.WriteLine("セキュリティ認証エラー: " + e.Message);
            }
            catch (InvalidOperationException e)
            {
                Console.WriteLine("無効な操作: " + e.Message);
            }
            catch (NotSupportedException e)
            {
                // htt:///www.northwind.mydns.jp/samples のような場合
                // ^^^
                Console.WriteLine("未サポートのプロトコル: " + e.Message);
            }
            catch (Exception e)
            {
                Console.WriteLine("予期しないエラー: " + e.ToString());
            }
            finally
            {
                // Cleanup the streams and the response.
                if (reader != null)
                    reader.Close();
                if (dataStream != null)
                    dataStream.Close();
                if (response != null)
                    response.Close();
            }
            
            return res;
        }
    }
}
カテゴリー
C#

C# データテーブルの内容をCSV出力

C#/ASP.NET でデータテーブルの内容を CSV 出力するサンプルを作成しました。
VisualStudio 2008 で動作確認しています。

using System;
using System.Data;
using System.IO;

namespace WebApplication1
{
    public class DT : System.Data.DataTable
    {
        private string lastError = string.Empty;

        public string LastError
        {
            get { return lastError; }
            set { lastError = value; }
        }

        ///
        /// CSV形式で出力
        ///
        public bool SaveToStream(MemoryStream ms, string rowDelim,
                                 char colDelim, char celDelim, int codepage)
        {
            bool result = true;

            try
            {
                // ヘッダ部
                string line = string.Empty;

                foreach (DataColumn col in this.Columns)
                {
                    line += celDelim;

                    line += col.Caption;

                    line += celDelim;

                    line += colDelim;
                }
                // 末尾の ',' 取り除く
                line = line.TrimEnd(colDelim);
                // 改行の付加
                line += rowDelim;

                // ストリームへ出力
                byte[] byteArray = System.Text.Encoding.GetEncoding(codepage).GetBytes(line);
                ms.Write(byteArray, 0, byteArray.Length);

                // データ部
                int colCount = this.Columns.Count;

                foreach (DataRow row in this.Rows)
                {
                    line = string.Empty;

                    for (int i = 0; i < colCount; i++)
                    {
                        // フィールドの取得
                        string field = row[i].ToString();

                        line += celDelim;

                        line += field;

                        line += celDelim;

                        line += colDelim;
                    }
                    // 末尾の ',' 取り除く
                    line = line.TrimEnd(colDelim);
                    // 改行の付加
                    line += rowDelim;

                    // ストリームへ出力
                    byteArray = System.Text.Encoding.GetEncoding(codepage).GetBytes(line);
                    ms.Write(byteArray, 0, byteArray.Length);
                }
            }
            catch (Exception e)
            {
                LastError = e.ToString();
                result = false;
            }

            return result;
        }
        ///
        /// サンプル データ作成
        ///
        public void MakeSampleTable()
        {
            DataColumn column;
            DataRow row;

            // DataColumn の作成
            // 1列目を作成
            column = new DataColumn();
            column.DataType = System.Type.GetType("System.Int32");
            column.ColumnName = "ID";
            column.ReadOnly = true;
            column.Unique = true;
            this.Columns.Add(column);

            // 2列目を作成.
            column = new DataColumn();
            column.DataType = System.Type.GetType("System.String");
            column.ColumnName = "データ";
            column.AutoIncrement = false;
            column.Caption = "データ";
            column.ReadOnly = false;
            column.Unique = false;
            this.Columns.Add(column);

            // ID列を主キーに設定
            DataColumn[] PrimaryKeyColumns = new DataColumn[1];
            PrimaryKeyColumns[0] = this.Columns["ID"];
            this.PrimaryKey = PrimaryKeyColumns;

            // データセットを作成してデータを作成
            DataSet dataSet = new DataSet();
            dataSet.Tables.Add(this);
            // データを10件追加
            for (int i = 0; i <= 10; i++)
            {
                row = this.NewRow();
                row["ID"] = i;
                row["データ"] = "データ " + i;
                this.Rows.Add(row);
            }
        }
    }

    public partial class _Default : System.Web.UI.Page
    {
        const string rowDelim = "rn";
        const char colDelim = ',';
        const char celDelim = '"';
        const int codepage = 932;
        const string csvname = "sample.csv";

        protected void Page_Load(object sender, EventArgs e)
        {

        }

        ///
        /// クライアントへCSV出力
        ///
        protected void Button1_Click(object sender, EventArgs e)
        {
            DT dt = new DT();
            dt.MakeSampleTable();

            // サンプル データを MemoryStream にへ出力
            System.IO.MemoryStream ms = new System.IO.MemoryStream();

            if (!dt.SaveToStream(ms, rowDelim, colDelim, celDelim, codepage))
            {
                System.Diagnostics.Debug.Print(dt.LastError);
            }

            // MemoryStream をクライアント側へ送信
             Response.Clear();
            Response.ContentType = "application/octet-stream";
            Response.AddHeader("Content-Disposition", "attachment;filename=" + Server.UrlEncode(csvname));
            Response.BinaryWrite(ms.ToArray());

            ms.Close();
            Response.Close();
        }
    }
}
カテゴリー
C#

Fortran からC#への移行

Fortran で書かれたプログラムをC#へ移行なんてあまりないかもしれませんが、以前に経験したことをまとめてみました。

既存の FORTRAN アプリケーションがファイルや標準入出力から入出力(READ/WRITE)を行う部分がもっとも工数がかかると思われます。C# へ移行する際に入出力を見直すか、READ/WRITE ステートメントを補完する同等の機能を C# で実装する必要があります。

全体的なデザイン

  • C#で一つのクラスを作成しメインアプリケーションとする。Fortran プログラムのメイン部分を main 関数にて実装する
  • Fortran の各SUBROUTINEを クラスのPublic な関数として実装する。
  • Fortran のPARAMETER はクラス内のconst で変数で定義する
  • Fortran のCOMMON はクラス内の 変数で定義する
  • 算術 IF 文 「IF (式) 文番号, 文番号, 文番号」「GOTO (文番号, 文番号, …) 整数式」は if 文もしくは switch文にする
  • ENTRY はできる限り関数化する
  • Fortran アプリケーションの標準入出力へ出力している部分は、C#アプリケーションで別途関数を用意する。
  • (処理系によるが)浮動小数点型数値の扱いについて有効桁数がFORTRAN と C# で異なる場合、丸め誤差が発生する可能性があるので、C# 側で丸め処理を行い極力 FORTRAN と同程度の精度を確保する

Fortran データ型とC#のデータ型の対比

Fortran C#
REAL(4) float
REAL(8) double
REAL(16)
CHARACTER(1) byte
CHARACTER(*) string
INTEGER(1) sbyte
INTEGER(2) short
INTEGER(4) int
INTEGER(8) long

FORTRAN とC# のライブラリ関数

Fortran C#
ATAN2 Math.Atan2
NINT Math.Round 
*1 MidpointRounding.AwayFromZero
MIN0 Math.Min
MOD % 演算子
COS Math.Cos
CMPLX Complex クラス *2
AMIN1 Math.Min
AMAX1 Math.Max
ABS Math.Abs
SIGN — *3
SQRT Math.Sqrt
DCOS Math.Cos
DSIN Math.Sin
DSQRT Math.Sqrt
DATAN2 Math.Atan2
べき乗 Math.Pow
*1 : Roundメソッドで四捨五入
    MidpointRounding.AwayFromZero
*2 : Complexクラス
    .NET Framework 4.0 (Visual Studio 2010)より利用可能
*3 : シグモイド関数
    ex)  SIGN(x, y)

    y >= 0の場合 |x|
    y < 0の場合 -|x|

    float Sign(float x, float y)
    {
        if (y < 0)
            x = -x;
        return x;
    }

参考:
Fortran Reference: https://homepage2.nifty.com/nimu/docs/fortran_references.html
Equivalent Data Types between Fortran and C#: https://software.intel.com/en-us/articles/equivalent-data-types-between-fortran-and-c_sharp/
Using C/C++ and Fortran together: https://www.yolinux.com/TUTORIALS/LinuxTutorialMixingFortranAndC.html
Fortran ResQ: https://fortran.hiroshism.com/index.html

カテゴリー
C#

C# でファイル検索

C# でファイルを検索する簡単なプログラムを作成してみました。
Visual Studio 2010 で作成したので .NET Framework 4.0 で動作確認はしています。 MSDN のサンプルにあった、LINQ を使っていますので Visual Studio 2008/.NET Framework 3.5 以上です。

using System;
using System.Linq;
using System.Text;
using System.Collections;
using System.Collections.Generic;
using System.IO;

namespace FindFiles
{
    class FindFiles
    {
        private int depthLevel = -1;

        public int DepthLevel
        {
            get { return depthLevel; }
            set { depthLevel = value; }
        }

        /// <summary>
        /// ファイル・フォルダの探索
        /// <param name="curFolder">ファイルを検索するフォルダ</param>
        /// <param name="curDepth">現探索レベル</param>
        /// </summary>
        void FindFilesRecurse(string curFolder, int curDepth)
        {
            // まず、現フォルダ内のファイルを検索
            try
            {
                IEnumerable<string> files = from file in 
                    Directory.EnumerateFiles(curFolder, "*")
// メモ: LINQ ここで WHERE 句で絞り込める
//                  where file.ToLower().StartsWith("something")
//  または、            where file.ToLower().Contains("something")
                    select file;

                foreach (string file in files)
                {
                    // 検索したファイルに対して何かする
                    Console.WriteLine(file);
                }
            }
            catch (Exception e)
            {
            }

            // 次に、探索のレベル指定により
            if (DepthLevel == -1 || DepthLevel > curDepth)
            {
                try
                {
                    // 現フォルダ内のサブフォルダを検索
                    IEnumerable<string> folders = from folder in 
                            Directory.EnumerateDirectories(curFolder, "*", SearchOption.TopDirectoryOnly)
                            select folder;

                    foreach (string f in folders)
                    {
                        // フォルダ再帰探索
                        FindFilesRecurse(f, curDepth + 1);
                    }
                }
                catch (Exception e)
                {
                }
            }
        }

        /// <summary>
        /// メイン
        /// </summary>
        static void Main(string[] args)
        {
            if (args.Length >= 2)
            {
                FindFiles ff = new FindFiles();

                // 検索開始フォルダ
                string folder = args[0];

                // 探索するフォルダの深さ
                int depth = int.Parse(args[1]);
                if (depth < 0)
                    depth = -1;
                ff.DepthLevel = depth;

                // 指定のフォルダが存在すれば探索開始
                string fullpath = System.IO.Path.GetFullPath(folder);

                if (System.IO.Directory.Exists(fullpath))
                {
                    ff.FindFilesRecurse(fullpath, 0);
                }
            }
            else
            {
                Console.WriteLine("使い方: FindFiles <"folder"> <level>");
                Console.WriteLine("        folder: 検索するフォルダ");
                Console.WriteLine("         level: 検索するフォルダの深さ");
                Console.WriteLine("    例: FindFiles c:Temp -1  --- すべてのサブフォルダを検索");
                Console.WriteLine("    例: FindFiles c:Temp 0   --- 指定のフォルダのみ検索");
                Console.WriteLine("    例: FindFiles c:Temp 3   --- 3階層までのフォルダ検索");
            }
        }        
    }
}