C#

2005年04月14日

C# メモリが足りなくなったら?

以前 マシンに積んでいるメモリや使用できるメモリの大きさを調べる方法を載せましたが、カンのいい方ならおわかりでしょうが市販されているメモリをデフラグ(?)ソフトとしても利用できます。

市販・フリーソフトでWindowsを起動した直後の状態並にメモリをきれいにする!みたいな事をうたっているソフトのことですが、メモリをきれいにしているとき何をしているかというと、メモリをガンガン確保しています。

Cなんかやっていると問題になる、参照しているメモリがあちこち散らばってしまう現象が多々起きてるので、メモリをめいっぱい使ってそれらをきちんと並べ替えてやります。
そして、隙間なく詰める。
ま、これらは作ったプログラムでやるのではなくOSの尻を叩いて、メモリの掃除をやってもらう。といった感じでしょうか。

で、C#のメモリを確保とメモリ量を表示するようなプログラムを作ってやれば、市販のそういったプログラムと同じものができちゃいます。
とは言っても、私の環境では771MB積んでいると表示され、50MB程メモリを確保したらそれだけでメモリいっぱいになってしまいました。
いったい裏で何をしているんだか。(^ ^ ;ゞ

で、100MB確保すると不具合が出てくるアプリが出てきました。
50MBだと不具合は出ることはありませんが、3回ほど確保してやらないとあまり効果がないようです。

いつかサンプル載せます。(^ ^ ;ゞ

続きを読む
campanella_77 at 23:32|この記事のURLComments(0)TrackBack(0)

2005年04月13日

C# マシンに積まれたメモリ情報を得る

メモリ情報を得るには、まず、

using System.Runtime.InteropServices;

を using します。

次に、以下の構造体を用意します。

  public struct MEMORY_STATUS{
    public int MemLength;
    public int nowMemoryLoad;
    public int onMemSize;        //搭載実メモリサイズ
    public int nowActiMem;       //使用可能メモリサイズ
    public int TotalPageFile;    //最大ページファイルサイズ
    public int nowActiPageFile;  //使用可能ページファイル
    public int TotalVirtual;     //最大仮想メモリサイズ
    public int nowActiVirtual;   //使用可能仮想メモリサイズ
  }

構造体の名前や各メンバは好きな識別子かまいません。

次にDLLファイルを扱えるように

  [DllImport("kernel32.dll")]

扱うDLLファイルをインクルードし、
さらに、外部ファイルメソッド GlobalMemoryStatus
を使えるように、 extern 宣言をします。
先ほどの構造体を参照渡しとして引数で渡します。
具体的には、DllImport の下あたりに、

  private static extern void GlobalMemoryStatus(
    ref MEMORY_STATUS lpBuffer);

と、記述します。
引数の部分に ref が付いているので参照渡しだと
いうことがわかると思います。
  

これらをクラス内部どこかに記述します。

で、Mainメソッドなり、ユーザー定義メソッドなりで、
これらを呼び出してやれば使える参照できるようになります。

呼び出し方は、


/* メモリ情報を格納する構造体 */
MEMORY_STATUS ms = new MEMORY_STATUS( );      
ms.MemLemgth     = Marshal.SizeOf( ms );

/* メモリ情報を得る */
GlobalMemoryStatus( ref ms );

/* 搭載実メモリサイズを見たいときは構造体にアクセス */
Console.WriteLine("搭載メモリ:" + ms.onMemSize + "byte");

/* 使用可能メモリサイズ */
Console.WriteLine("使用可能メモリサイズ:" + 
  ms.nowActiMem + "byte");


これらの値はプログラム動作中にも変化していくので、
参照したい場合はまたインスタンス化からはじめないといけません。



続きを読む
campanella_77 at 00:37|この記事のURLComments(1)TrackBack(0)

2005年04月12日

C# 2バイト文字を含む文字列のバイト数

ブログでプログラムないし、なにかしらの講座を始めるのは、
管理者としては非常に楽。思いついたことを書き込んでは保存して
いけば良いからです。
デザインやCGIの知識が無くても誰でも使用することができますし。

が、それを見る・調べたい側からすると、管理者と思惑が違ってくる。
まず、ページがない。
たとえば私のブログの場合は、各カテゴリー分けと最近記述した記事に
関してはぱっと何が書かれているか、どんな記事があるかがわかりますが、
仮に C# に関して100個ほどの記事になってしまったら100個記事があるのは
わかるが、調べたい記事が果たしてここにあるのか。がわかりにくい。
検索機能を付けたけれども、意外と
検索ってめんどくさい。= 使ってくれない。
のであります。

いつかはページリンクのページを作成しないとなぁ。(ま、メモだから
いらないっちゃいらないんだけれど)

そんなわけで今回は1記事にしてしまっていいのかってなぐらい
小さい発見です。

JAVAやC# ではC言語の弱点(?)克服のためか文字列に関して多少強く
なっています。
2バイト文字を含む文字列が何バイトあるかを調べる方法は、JAVAなんかでは、

int len = str.getBytes( "Shift_JIS").length;

でしたが、C#では、

using System.Text.Encoding;

int len = GetEncoding("Shift_JIS").GetByteCount(str);

と、なります。
JAVAでは例外処理をしてあげないと、コンパイルエラーになります。
よって、例外処理を施してやると以下のようになると思います。

using System.Text.Encoding;

    String Str = "あいうえお";
    int len       = 0;
    try{
      len = GetEncoding("Shift_JIS").GetByteCount(Str);
    }catch(System.NotSupportedException e){
      Console.WriteLine(e);
      System.Environment.Exit(1);
    }

    Console.WriteLine("バイト数:" + len + "バイト");

一応、
int len = 0;
と、宣言と初期化を同時にしていますが、例外処理をしているので
最初に値を入れるのが例外処理内なのでコンパイル時に、警告される
ので、一応スコープ外で 0 を入れています。

campanella_77 at 14:48|この記事のURLComments(0)TrackBack(0)

2005年04月10日

C# 自作クラスを取り込む(自信無し)

プログラムも少し規模が大きくなってきて、扱いにくくなってきたというのと、私の作成したライブラリを配布出来るように、別ファイルにクラスを定義し、メインのクラスには必要最小限の記述にしようと思っていたのだけれど、はて、その別ファイルに定義したクラスをどうやって取り込めばいいのだろうか。

悩んだ!C# やってて一番悩んだ!
それでもC言語の悩みよりずっと規模が小さい。でもぉおお悩んだっ!

何せ検索しようにも、どんな単語をキーワードにしていいのかがわからない。
C# 入門は数あれどさっぱり載っていない。
いや、載っているかもしれないけど見過ごしたかも?
否っ!
そんなはずはないと。

とりあえず思いついた単語をキーワードに検索。
「C#」ははずせない。
「別ファイルに」「自作クラス」「ライブラリ」「外部ファイル」「import」「名前空間」・・・・といったありがち(?)なものから「他人が作った」「配布」等々。
もうここまで来ると全然見当違いなものがヒットし出す始末。

どのサンプルもすべて1つのファイルに記述することが前提のようです。(まぁ、サンプルだからシンプルでしょうしわざわざ別ファイルにする必要もないのでしょうが)
その割りに、同じメソッド名になるのを防ぐために、名前空間が・・なんたらかんたら。
そんな短いサンプルじゃ名前空間もなにもない気がする。

結局わからずじまいで、もうこうなりゃJAVAで出来たんだからC# だって簡単にできるはず。と、別ファイルに記述したクラスを名前空間で囲ったり、メインクラスの方で using で色々ファイル名やら名前空間を記述したり・・・。

それでもダメ。
はぁ。。。なんてため息をつくことしばしば。

とあるQ&Aのページでコンパイルするサンプルが。
おや。拡張子が「cs」ファイルをスペースを挟んで2つ渡している・・・。

そっか!鍵はコンパイル時にあったんだ!

さっそく試してみる。

> csc mainClass.cs myOrigClass.cs

出来た〜〜〜〜〜〜〜!!!
なるほど〜。あ。そうだ。コンパイルのヘルプ見てみるか。

> csc /?


なになに・・・。
/target:library ライブラリをビルドします。

これ、それっぽいな。

> csc /target:library myOrigClass.cs

おぉ。エラーがでないぞ。
ディレクトリを覗いてみると
myOrigClass.dll
ってなファイルが出来てる。続きを読む
campanella_77 at 01:44|この記事のURLComments(0)TrackBack(0)

2005年04月09日

C# 指定された文字列がある行全部を読み込む(メソッド化)

前回の修正 を改良して読み込んだデータから指定された文字列を含む行
すべて取り込む処理をメソッド化しました。

どれくらい遅くなるかどぎまぎしましたが、なんと!
続きを読む
campanella_77 at 23:30|この記事のURLComments(1)TrackBack(0)

C# 指定された文字列がある行全部を読み込む(修正)

『C# 指定された文字列がある行全部を読み込む』 で
発表したプログラムの場合、「指定文字列」が行頭にないと、
その「指定文字列」以降から改行までしか取り込めないので、
行の途中に「指定文字列」が見つかった場合でも、行頭から
丸々取り込めるように改良しました。
が、当然の事ながら遅くなります。

改良点は、
★1バイトずつカウントしていき、改行が見つかったらカウントを0にする。
(行頭から何文字目に指定した文字列が見つかったかカウントするため)
★指定された文字列が見つかった場合、行頭までポインタを戻らせて
行頭から1文字ずつ取り込むようにする。

うーん。なんかもっといい方法がありそう・・・。

ソースと結果は「続きを読む」で。
続きを読む
campanella_77 at 17:34|この記事のURLComments(0)TrackBack(0)

C# StreamReaderでファイルをを読み込む

速度対決の項で、C#では Readメソッド を使いましたが、
C言語の fgets の様な動作を期待したのが理由です。
が、fgets が

改行を検出してくれる。
指定したバイト数 - 1 を読み込み残りの1バイトを「\0」で
埋めてくれる。

のに対して、Read は、

指定したバイト数丸々読み込む。
改行も何もお構いなし。

と、どっちかというと gets と fgets の中間の様な
動作をするようです。

さて、このReadメソッド を使っていく前に、もう少し詳しく
このメソッドについて実験してみました。

まず、このメソッドは
StreamReaderクラスFileStreamクラス のどちらも
所有(?)していますが、FileStreamクラスの Readメソッドが
byte型の配列に読み込んでいくのに対して、StreamReaderクラスReadメソッドは、char型の配列に読み込んでいくようです。
このことが何を示すかというと、読み込んだ後加工しやすいのが
StreamReaderクラスのReadメソッドだということです。

たとえば、
srObj.Read(cBuff , 0 , 256);
System.Console.Write(cBuff);

とすると読み込んだデータを出力できますが、

fsObj.Read(bBuff , 0 , 256);
System.Console.Write(bBuff);

とすると、うまくいきません。
また、 Stringクラスのオブジェに変えるのもめんどくさそうです。

どちらが速いか。ですが、あんまり変わらなかった気がします。
(※ 測定してみたら、こちら のプログラムを FileStream から
StreamReader に変更したら、なんと!
3秒 ⇒ 5秒
遅くなってる・・・・)

今後、StreamReadクラスを使っていくこととして、
Readメソッドに確保した char型のバッファサイズ以上のデータを
読み込ませたらどうなるのでしょうか。

char[] cBuff = new char[16];
int recByte  = 0;

recByte      = srObj.Read(cBuff , 0 , 17 );

16バイト確保した領域に、17バイト読み込ませてみました。

結果をいってしまうと、例外が発生します。
あと、Readメソッドは読み込んだバイト数を int型の数値で返してきます。
よって、ファイルの最後まで読み込むには、この帰ってきた値、
つまり recByte が、読み込ませる16バイト以下になったらファイルの
末尾に到着したということになります。

具体的に書くとこうなるでしょう。

int BuffSize = 16;
char[] cBuff = new char[BuffSize];
int recByte;

while(BuffSize == (recByte = srObj.Read(cBuff , 0 , BuffSize))){
  Console.Write(cBuff);
}
//最後の読み込み分を表示
Console.Write(cBuff);

これを実行すると、ファイル内容をコンソール上に表示してくれます。
が、最後の読み込みはうまく表示されません。

読み込むファイルの末尾が以下のようだった場合、

abcdef1234567890

BuffSie が 10 だとすると、コンソール上に
Console.WriteLine(cBuff);
で出力すると、

abcdef1234
5678901234

と、表示される。つまり abcdefg123 に、4567890 が上書きされ、
それ以後の 1234 はそのまま残される。

C言語なんかだと「ここまでが文字列だよ」としたい場所の次のバイトに
「ヌル文字」を入れると、コンピュータがそれに従って処理してくれるが
ではC#の場合は・・・。

int BuffSize = 16;
char[] cBuff = new char[BuffSize];
int recByte;

while(BuffSize == (recByte = srObj.Read(cBuff , 0 , BuffSize))){
  Console.WriteLine(cBuff);
}
cBuff[recByte] = '\0';
//最後の読み込み分を表示
Console.Write(cBuff);

とすると

abcdef1234
567890 234

先ほど「1」と表示されていたとこが「 」と空白になっている。
で、ちゃんとその後の文字列も表示されている・・。



campanella_77 at 11:29|この記事のURLComments(0)TrackBack(0)

2005年04月05日

C言語 VS C# 指定された文字列がある行を読み込む...

テキストファイルから指定された文字列がある行を探しだし、その行すべて読み込んだ場合、C言語とC# でどちらが速いか実験してみました。
ソースは前回と前々回のものを利用し、同じ2MBのテキストファイルを使用します。
また、100回ループさせてより差がわかるようにさせました。

結果をいってしまうと、C言語が5秒かかったのに対してC# は3秒と圧勝でした。

C# が速かったのは、

●ファイルを一気にメモリに読み込んでしまった為
●ポインタで操作した為

だと思われます。
よって、C言語や他の言語でも一気にメモリに読み込んでしまう方法を用いれば速いと思われます。
2番目のポインタですが、これに関してはポインタを操れる言語でないと難しいですね。あいにくC# はJAVAと違ってポインタを操れるので、ちょっと速く処理できます。
ポインタと配列はほぼ同じようなものなので、ポインタが使えなければ配列で操作する事になりますが、ポインタの方が速いと思われます。

オブジェクト指向言語でよくやってしまう事(いけないというのではなく)として、読み込んだ値を Stringクラスに変換してから色々操作する方法があります。
Stringクラスにある豊富なメソッドを使うことが出来るようになりますが、かなり遅くなります。

JAVAやC# には1行丸々一度で読み込む ReadLine といったメソッドがあります。
これらのメソッドにより、安全にそして初心者にも簡単にファイルを扱えますが、当然内部では改行を探してメモリ空間を随時調節しながら実行していると思われるのでやはり遅くなります。
たぶん、最終的に String クラスのオブジェに変換していると思われるので、
PHPの2倍の処理がかかっています。


campanella_77 at 04:40|この記事のURLComments(0)TrackBack(0)

C# 指定された文字列がある行全部を読み込む

前回C言語でやったこと(「指定された文字列が
ある行全部を読み込む」)をC# でやってみた。
例によって長い。


using System;
using System.IO;
using System.Text;

unsafe class file
{
  public static void Main( ){
    
    String filePath    = "./aaa.txt";
    FileStream fp;
    FileInfo fInfo     = new FileInfo( filePath );
    byte[] cbuf        = new byte[ (int)fInfo.Length ];
    StringBuilder line = null;
    
    for(int j = 0; j < 100; j++){

      fp = new FileStream(filePath, FileMode.Open,
        FileAccess.Read );
      
      try{
        fp.Read(cbuf , 0 , (int)fInfo.Length);
      }catch(System.ArgumentException e){
        System.Console.Write("引数がおかしいです");
        Environment.Exit(1);
      }catch(System.Exception ex){
        System.Console.Write("ファイルエラー");
        Environment.Exit(1);
      }finally {
        fp.Close( );
      }
      //検索
      //検索したい文字列の前に「\n」を付けると
      //行頭にある文字列という感じになる
      String str    = "\ncool";
      char[] str_cp = str.ToCharArray( );
      bool ma       = false;
      fixed( byte* pArray = &cbuf[0] ){
        int max = (int)fInfo.Length;
        for( int k = 0; k < max; k++){
          //マッチしたら
          ma = true;
          if (*(pArray + k) == str_cp[0]){
            for( int m = 1; m < str_cp.Length; m++){
              k++;
              if ((char)*(pArray + k) != str_cp[m]){
                ma = false;
                break;
              }
            }
            if ( ma ){
              line = new StringBuilder( );
              line.Append(str , 1 , str.Length - 1);
              while('\n' != (char)*(pArray + k)){
                line.Append((char)*(pArray + k));
                k++;
              }
            }
          }
        }
      }
    }
    Console.WriteLine(line);
  }
}

campanella_77 at 04:29|この記事のURLComments(0)TrackBack(0)

2005年04月04日

C# JAVAでいうStringBufferは?

な〜んか微妙に違うクラス名にしていますね。JAVAのクラス名と。
しかも、C# も JAVA も、大文字小文字を区別されるんだけれどJAVAと同じメソッド名だったとしても、C# はメソッドの始まりが大文字。JAVA は小文字・・・。

JAVAのように、StringBufferクラスを使いたいと思い、プログラムをコンパイルしたらエラー。
調べてみたら C# では、StringBuilder というクラスを使うようだ。
文字列や文字を追加していくには、Append を使う。
第一引数に追加したい文字列、
第二引数に追加したい文字列の始まりIndex、
第三引数に追加させたい文字数を指定する。と、いった使い方も出来る。

このとき、第二引数が1以上の場合は追加したい文字列全体のバイト数から第二引数で与えられた数字分のバイト数を引いた値が追加されるようにメモリ空間が用意されるらしく、第三引数の値がその用意されたバイト数より大きいと例外が起きて強制終了する。

例)
//以下はコンパイルが出来るが、実行時強制終了する
str.Append( addStr , 4 , addStr.Length - 3);
//正しくは以下
str.Append( addStr , 4 , addStr.Length - 4);

campanella_77 at 16:58|この記事のURLComments(0)TrackBack(0)

C言語 名誉挽回?

前回の競争後、C# で書かれたプログラムをチューニングしたら
C言語以上の速度が出た。
名誉挽回というわけではないけれど、前回のC言語の処理は文字列を 
strstr関数に任せてしまっていたので、C# でやっていたときと同じ
ポインタで操作してみた。以下その処理。
これがベストか自信ない・・・。
#include 
#include 
#include 

int main(void){
 
 char* filePath   = "./aaa.txt";
 FILE* fp         = NULL;
 char* ch         = "SkyBlue";
 int cnt          = 0;
 int i , j , k , max;
 char* s          = (char*)malloc(256 * sizeof(char));
 
 max              = strlen(ch);
 for(j = 0; j < 100; j++){
   if ((fp = fopen(filePath , "r")) == NULL){
    printf("ファイルを開けませんでした\n");
    exit(1);
   }
   cnt = 0;
   while(fgets(s , 256 , fp) != NULL){
     for (i = 0; '\0' != *(s + i); i++){
       if (*(ch) == *(s + i)){
         cnt++;
         for (k = 1; k < max; k++){
           i++;
           if (*(ch + k) != *(s + i)){
             cnt--;
             break;
           }
         }
       }
     }
   }
   fclose(fp);
 }
 printf("%d\n",cnt);
 return 0;
}

結果は、3.5秒と strstr関数の時と変わりなかった。
ポインタでなくて配列でやったら逆に遅くなるんだろうなぁ。

campanella_77 at 15:48|この記事のURLComments(0)TrackBack(0)

C# 最高速説

もっとC#をチューニングできないかな。と思って、前回の対決では
読み込むテキストデータの文字コードを指定していた。
ここをなくせば速くなりそう。で、以下のように修正。

using System;
using System.IO;
using System.Text;

unsafe class file
{
  public static void Main( ){
    
    String filePath  = "./aaa.txt";
    FileStream fp;
    FileInfo fInfo   = new FileInfo( filePath );
    byte[] cbuf      = new byte[ (int)fInfo.Length ];
    int count        = 0;
    
    for(int j = 0; j < 100; j++){

      fp = new FileStream(filePath, FileMode.Open,
        FileAccess.Read );
      count = 0;
      
      try{
        fp.Read(cbuf , 0 , (int)fInfo.Length);
      }catch(System.ArgumentException e){
        System.Console.Write("引数がおかしいです");
        Environment.Exit(1);
      }catch(System.Exception ex){
        System.Console.Write("ファイルエラー");
        Environment.Exit(1);
      }finally {
        fp.Close( );
      }
      //検索
      String str = "cool";
      char[] str_cp = str.ToCharArray( );
      fixed( byte* pArray = &cbuf[0] ){
        int max = (int)fInfo.Length;
        for( int k = 0; k < max; k++){
          if (*(pArray + k) == str_cp[0]){
            count++;
            for( int m = 1; m < str_cp.Length; m++){
              k++;
              if ((char)*(pArray + k) != str_cp[m]){
                count--;
                break;
              }
            }
          }
        }
      }
    }
    Console.WriteLine(count);
  }
}

結果、2.5秒。
はやい!

campanella_77 at 12:39|この記事のURLComments(5)TrackBack(1)

C言語 vs C#言語 vs C#言語ノーマル vs PHP

色々な言語で、2MB程のテキストファイルを読み込んでいき、
指定された文字列がそのテキストファイルにいくつあったか調べる
プログラムを作り、どの言語が一番速いか試してみた。

C言語とPHPは(この処理に関しては)非常に似ているので、
割と言語の処理速度の差が明確に出ますがC#の場合はまったく
(といってもいいほど)考え方が違うので厳密な意味で
同じような処理が出来ない。
ので、どのような処理をしたら速いのか2パターン計測。
どの言語も最も処理が速くなるように処理させたつもりだけれど、
C#に関してはあまり自信がない。
ただ、どの言語も一番オーソドックスな方法であることは確かだとは思う。
################### C言語 ##############################
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void){
 
 char filePath[] = "./aaa.txt";
 FILE *fp = NULL;
 char s[256]; 
 char ch[] = "cool";
 char *tmp;
 int cnt = 0;
 int j = 0;
 
 for(; j < 100; j++){
   cnt = 0;
   if ((fp = fopen(filePath , "r")) == NULL){
    printf("ファイルを開けませんでした\n");
    exit(1);
   }
   while(fgets(s , 256 , fp) != NULL){
     tmp = s;
     while((tmp = strstr(tmp  , ch)) != NULL){
       tmp += strlen(ch);
       cnt++;
     }
   }
   fclose(fp);
 }
 printf("%d\n",cnt);
 return 0;
}

################### C# ポインタで ##############################

using System;
using System.IO;
using System.Text;

unsafe class file
{
  public static void Main( ){
    
    String filePath = "./aaa.txt";
    FileStream fp;

    FileInfo fInfo = new FileInfo( filePath );
    char[] cbuf = new char[ (int)fInfo.Length ];

    StreamReader sr_sjis;
    
    int count = 0;
    
    for(int j = 0; j < 100; j++){

      fp = new FileStream(filePath, FileMode.Open,
        FileAccess.Read );
      sr_sjis = new StreamReader(fp ,
        Encoding.GetEncoding(932));
      count = 0;
      
      try{
        sr_sjis.Read(cbuf , 0 , (int)fInfo.Length);
      }catch(System.ArgumentException e){
        System.Console.Write("引数がおかしいです");
        Environment.Exit(1);
      }catch(System.Exception ex){
        System.Console.Write("ファイルエラー");
        Environment.Exit(1);
      }finally {
        sr_sjis.Close( );
      }
      //検索
      String str = "cool";
      char[] str_cp = str.ToCharArray( );
      fixed( char* pArray = &cbuf[0] ){
        int max = (int)fInfo.Length;
        for( int k = 0; k < max; k++){
          if (*(pArray + k) == str_cp[0]){
            count++;
            for( int m = 1; m < str_cp.Length; m++){
              k++;
              if ((char)*(pArray + k) != str_cp[m]){
                count--;
                break;
              }
            }
          }
        }
      }
    }
    Console.WriteLine(count);
  }
}

################### C# ノーマル ##############################

using System;
using System.IO;
using System.Text;

unsafe class fileTest2{
  public static void Main( ){
    String filePath = "./aaa.txt";
    FileStream fp;
    StreamReader srSjis;
    String tmp;
    int cnt;
    int count = 0;
    String str = "cool";
    
    for(int j = 0; j < 100; j++){
      count = 0;
      fp = new FileStream(filePath, FileMode.Open, FileAccess.Read );
      srSjis = new StreamReader(fp , Encoding.GetEncoding(932));
      
      while(null != (tmp = srSjis.ReadLine( ))){
        cnt = 0;
        while(-1 != (cnt = tmp.IndexOf(str , cnt ))){
          cnt = cnt + str.Length;
          if (cnt > tmp.Length)
            break;
          count++;
        }
      }

    }
    Console.WriteLine(count);
  }
}

################### PHP ##############################

<?
$filePath = "./aaa.txt";
$tmp = null;
$str = "cool";
$count = 0;
for($i = 0; $i < 100; $i++){
  if (!$fp = fopen($filePath , "r")){
    print "ファイルを開けません";
    exit(1);
  }
  $count = 0;
  while( $tmp = fgets($fp , 256) ){
    $cnt = 0;
    while($cnt = strpos($tmp , $str , $cnt)){
      $cnt = $cnt + strlen($str);
      $count++;
    }
  }
}
print $count;
?>

###################   結 果   ##############################

C言語   :3.5秒
C#ポインタ:5秒弱
C#ノーマル:19秒
PHP      :10.5秒

いや〜。C#ノーマル遅かった遅かった。
意外とPHPが検討している。
C#はCと比べて遜色のない速度ではないだろうか。
ただ、プログラムが長くなる・・・。

PHPなんかはたいていがファイルを読み込んで、文字列を検索したりする
処理が多いので、開発期間と安全性も含めてWebアプリとして
最も向いている言語かもしれない。
アクセラレータを入れればレスポンスの早さも考えると十分C言語CGIに
匹敵する速度じゃないかなとは思う。
あくまでWebアプリの場合だけれど。

campanella_77 at 08:35|この記事のURLComments(0)TrackBack(0)

C# 苦手を克服?ファイルから「cool」がいくつ含まれてるか

色々やっていたら・・・・。ん?なんかこの私のブログにポイントが
入ってる・・・。なんだ?これは。
ポイント:1pt
入れた覚えはなし。

なんだろう・・・。これ・・・。

ま、いいや。

えっと、ファイルを以下に速く読み込むかを色々試行錯誤した結果、
ガバッとまずメモリに読み込む。
で、ぱっぱっとポインタを使って検索なり加工なりしてさっさと出力する。

単純だが一番速いとは思う。

よけいな手間はかかるが、これでも色々なことが出来るだろうし、
クラスにまとめておけばそれなりに使い道もあるだろう。
以下やってみた実験のソース。


String filePath = "./aaa.txt";

FileInfo fInfo        = new FileInfo(filePath);
int fileSize          = (int)fInfo.Length;
char[] cBuf           = new char[fileSize];
FileStream fp         = new FileStream(filePath,
   FileMode.Open, FileAccess.Read );
StreamReader sr_sjis  = new StreamReader( fp );

try{
  sr_sjis.Read(cBuf , 0 , fileSize);
}catch(System.ArgumentException e){
  System.Console.Write("引数がおかしいです");
  Environment.Exit(1);
}catch(System.Exception ex){
  System.Console.Write("ファイルエラー");
  Environment.Exit(1);
}finally {
  sr_sjis.Close( );
}

////////////// ここから検索作業 ///////////////////

//検索文字列
String match      = "cool";
//検索しやすいように char型の配列に
char[] charMatch  = str.ToCharArray( );
//検索文字列がいくつあったかをカウント
int count         = 0;
//検索文字列用ポインタカウント
int cnt           = 0;

//ポインタを使うときのおまじない
fixed( char* pBuf = &cBuf[0] ){
  for( int i = 0; i < fileSize; i++){
    if (*(pBuf + i) == charMatch[0]){
      count++; //とりあえず1個増やす
      for( int j = 1; j < charMatch.length; j++){
        i++;
        if (*(pBuf + i) != charMatch[j]){
          count--;
          break;
        }
      }
    }
  }
}
//出力
System.Console.WriteLine(count);

campanella_77 at 03:10|この記事のURLComments(0)TrackBack(0)

2005年04月03日

C# ものすごい勢いでファイルを読み込むには

結局スマートな、それでいて速いファイルの読み込みの方法は
わからずじまい。
Readメソッドは読み込むバイト数を指定できるものの、
改行もお構いなしで文字1文字。として読み込んでしまう。
C言語の fgets ならば「指定バイト数か、改行まで」で都合よく
CVSファイルを扱えるのだが・・・。

で、発想の転換ではないけれど、逆に改行も何もお構いなしに
読み込んでその後煮るなり焼くなりしてはどうか。と思い実験してみた。

まず、ファイルと同じサイズのバッファを用意する。
ファイルのサイズを調べるには、FileInfoクラスの Length プロパティで
取得できる。
FileInfoのコンストラクタにはファイルへのパス。

さて、実際にやってみる。

  //ファイルへのパス
  String filePath = "./aaa.txt";
  //サイズを求めるために FileInfoクラスを使用
  FileInfo fInfo = new FileInfo( filePath );
  //ファイルの中身をすべて入れるバッファを用意
  //byte型の配列
  byte[] fbuf = new byte[ (int)fInfo.Length ];
  //ファイルをオープン
  FileStream fp = new FileStream(filePath, FileMode.Open,
   FileAccess.Read );
  //バッファストリームに変換
  BufferedStream bs = new BufferedStream(fp);
  //ファイルの末まで全部読み込む
  bs.Read(fbuf , 0 , (int)fInfo.Length); 
    //さらに速度をあげるためにポインタを使う
    //普通にやっていてはポインタは使えない
    fixed( byte* pArray = &fbuf[0] ){
      //たとえばファイルの末尾から200文字前までを表示
      for (int k = 0; k < 200; k++){
        //char型にキャスト
        Console.Write((char)*(pArray +
          (int)fInfo.Length - 200 + k));
      }
      //全部表示するなら以下のように
      /*for(int k = 0; k < fbuf.Length; k++){ 
        Console.Write((char)*(pArray + k));
      }*/
    }

※注意
ポインタを使う場合は、ポインタを使う自作クラス、
もしくは自作メソッドに
unsafe
を付ける。
さらに、コンパイルするときも
> csc /unsafe pointerTest.cs

ファイルの読み込みの方は今までと同じループとファイルで試したら、1秒ちょい。
ループを10倍にしたら8秒という結果だった。


campanella_77 at 23:40|この記事のURLComments(0)TrackBack(0)

C# ファイルをなるべく早く読み込む

ファイルをなるべく早く読み込む挑戦はまだ続く・・・。
条件として、
行単位かバイト単位で読み込む。
読み込んだ後、文字列として色々加工・検索できる状態にする。
で、ま、CVS形式のファイルを読み込んでいってデータを検索。
みたいな使い方を考えているわけで、これはスピードが要と。
C言語がもっとも得意としそうな分野だけれど、PHPでもそう差が付く
処理でもない。
がっ!!JAVAやC#では遅い。

なんか読み込むとき、色々安全対策処理をしていそうでそれが
足を引っ張っていると思われる。
なるべく低レベルで処理をしたいのだが、はてC#でできるか。

今回は、以下を試した。

    for(int j = 0; j < 100; j++){
      fp = new FileStream(filePath, FileMode.Open, 
        FileAccess.Read );
      sr_sjis = new StreamReader(fp ,
        Encoding.GetEncoding(932));      
      while(null != (tmp = sr_sjis.ReadLine( ))){
      }
    }

テキストファイル filePath を読み込みモードで開き、
Shift_JIS 文字コードとして1行ずつ読み出す。

10秒ほど・・・。

campanella_77 at 15:43|この記事のURLComments(0)TrackBack(0)

C# もっと速くファイルを読む方法は?

前回の方法だと、実はファイル全部を読むことは出来ない。
Readメソッドが256バイト読み込めずにファイルの終端にくると
 0 を返すらしい。

ま、それでもいいのだけれど、な〜〜んかもっとスマートで
美しい処理の仕方ってないのかなぁ。

とりあえず何も考えずに一発でファイル全部読み込んだ場合の
処理速度ってどうなんだろう。
C#では、ファイル全部読み込むというPHPでいう file 関数に
似た動作をするメソッドを持ち合わせている。

以下実験。

TextReader tr;
for (int i = 0; i < 100; i++){
  tr = File.OpenText(fipePath);
  tmp = tr.ReadToEnd( );
}


これだけで100回ファイルを全部読み込む。

で、スピードはというと・・・

11秒・・・・。


さて・・・違う方法考えるか・・・。

campanella_77 at 12:44|この記事のURLComments(2)TrackBack(0)

C# テキストファイルを読み込む -1-

似てるようで似てない。
と、小言を言った所で実験。
いったいC#ではテキストファイルを読み込むにはどうすればいいのだろうか。
ガバッと全部読み込むのは簡単らしい。が、最低やって頂きたい処理は
 ・1回当たりに読み込む量は、1行ずつ、もしくは指定したバイト単位で
 読み込む。
です。

以前、C言語、JAVA、PHPでどれがどれだけ早いか競争選手権を実施した所、
ファイルを1行、もしくは256バイトずつ読み込む、どちらでもいいから
とにかくどれが速いかを開催した所、2MBのテキストファイルを読み込むのに

C言語:3秒
PHP:7秒
で、JAVAは・・・・


24秒。


え・・・・。汁

おかしいなぁ。やり方が悪いのかなぁ。

色々試してみて、それでも10秒程度。
う〜ん。
JAVAで fgets の代わりになるものって何だろう。

で、C#で実験してみた。
今のところ以下のやり方が一番はやい(と思う)。

FileStream fs;
StreamReader fp;
for (int i = 0; i < 100 ; i++){
  fs= new FileStream(filePath , FileMode.Open ,
    FileAccess.Read);
  fp = new StreamReader(fs);
  while( 0 != fp.Read(charBuf , 0 , 256)){
  }
}

こんな感じだと、6秒くらい。
何とか4秒にならないかなぁぁぁぁぁぁあああ。


さっぷありわからんっ!
続きを読む
campanella_77 at 11:42|この記事のURLComments(0)TrackBack(0)

C# メモリアドレスを表示?

JAVAやPHPやPerlなんかでは絶対無理なんだろうな。な、事がC#では出来そう。
using System;
namespace PointerTest{
unsafe class Pointer{
    static void Main( ){
      int i = 12345;
      Console.Write("i:");
      Console.WriteLine(i);
      Console.Write("メモリアドレス:");
      Console.WriteLine((int)&i);
    }
  }
}
出力結果

i:12345
メモリアドレス:124278

おぉ。Cみたい〜♪

campanella_77 at 04:38|この記事のURL

C# Console.Writeとポインタの型変換

以下のプログラムを見てみる。
using System;
namespace PointerTest{
  
unsafe class Pointer{
    static void Main( ){
      int i = 0x41;
      Console.Write("i:");
      Console.WriteLine(i);
      char* c = (char*)&i;
      Console.Write("c:");
      Console.WriteLine(*c);
    }
  }
}
ここで i は「int」型の変数。そこに「 0x41 」つまり、10進数で「65」を入れる。
そのまま出力すると「 65 」が表示される。
次に「char」型のポインタ変数「 c 」を用意。そこに今使ってきた 変数i のアドレス(ポインタ)を入れてやる。
それを Console.Write を使って出力すると A と、表示される。

・C#でもポインタは使える。
・ただしポインタを使う場合は、クラスの定義時に
unsafe
を付け加える。(Windowsでいうセーフモードってとこかな)
・System.Console.WriteLine は、与えられた変数の型によって表示の仕方を使い分ける。
campanella_77 at 04:13|この記事のURLTrackBack(0)
最近撮った写真
campanella
What's campanella
ライブカメラ公開中
kao.gif
訪問者数