本文へスキップ

                                     風と翼 Windandwing は、c++の数値計算から風と翼の計算へ を目的とした数値計算を行っています。

Addres http://www5.synapse.ne.jp/windandwing/
c++ 文字、フォルダ生成、csvデータ読み込み・書き込み、    多量データ処理

第0章 "c++ 文字(Single/Double)フォルダ生成csvデータの読込み・書き多量データ"の説明

いうまでもなく、最初に言葉ありきである。
・c++ 文字
 入力データの半角(single)/全角(double)の区別が入力データを扱う時に必要となる。
 また、コンパイラーによっては出力文字が文字化けする事がある。(この文字化けが動機になった。)

・フォルダ生成
 計算結果を指定のフォルダに格納しないと、検索機能があるとは言え、ハードディスク内を探す必要がある。

・csvデータの読み書き
 多くの測定計器がデジタル化され、出力はcsvデータでメディアに記録されている。このデータをパソコンで
 処理する場合に、カンマ区切りの識別が重要となる。

・多量データ
 一年間を通して測定される風況データのような膨大な量のデータもある。

従い、始めに、文字とフォルダ(dir)に関する事を自分のためにも最初に取り上げた。
      

1、文字数算出による文字判別

概要

1、記載事項の背景
 (1)動機:VC6++で作成したコードをVisual Studio 2008 下で実行時、生成フォルダの文字化けの発生のため
 (2)コンパイラー:VS2008、VS2010
 (3)対象:c++ の文字 string 型の扱い

2、結論
 "#include<mbstring.h>"と "setlocale( LC_ALL, "japanese" )" の記述で、フォルダ名の文字化けはない。
 
 なお、VS2008、VS2010のプロジェクトのプロパティで構成プロパティの全般の個所中の文字セットを
 "マルチ バイト文字セット"を使用するを選択する必要がある。

3、文字の判別について
 (1)c++での文字列の区別
  ・Single Byte(8bit=1byte)=SBCS 、Double Byte(16bite=2byte)=DBCS
  
  ・Single Byte=SBCS、Multi Byte(8and16bit以上、1byte以上)=MBCS
  
  ・Multi Byte Charcter、Wide Character=wchar_t
  
  ・Ascii文字コード=char、Unicode
  
  ・TCHAR (マイクロソフトのVisual Studioの専用の typedef 文字列体系で、
         _UNICODEあるいは_MBCSのオプションでcharやwcharに変換する。)

   上記は、多くの web page、および Wikipedia 等を参照している。

 (2)コードの説明 (コード1)
  文字列に あいうえおのような平仮名、全角カタカナの日本語が含まれているかの識別方法を示す。
  識別方法は、文字列の文字数を上記の SBCS、MBCS 、終端にNULL(char型) のない string 型で、算出し、
  これらの文字数の比較で、日本語が含まれているかいなかの判定を行う方法である。

  他の方法も検討したが、文字列が SBCS か MBCS かは、全体の文字数で判断するこの方法が判り易い。

  1)文字数の算出
   c++ の文字に関する ST Lの一つであるstring 型の文字数を、以下の関数で求めた。

    関数 char型 strlen()、Multibyte型 _mbstrlen()、string型 x.size()

   例えば、上記の型に応じて、入力された文字 string型 indata の文字数を以下のように求める。

   int strlen_indata=strlen(indata.c_str());    //string 型を char 型とし、single換算の文字数

   int mbs_indata=_mbstrlen(indata.c_str());  //string 型を char 型とし、実際の文字数

   nt sizetyp_indata=indata.size();       //string 型の single換算時のサイズ(文字数)

  2)数の判定
   ・これらの数を比較し、同数の文字数であれば single とし、同数でなければ Multibyte の文字が含まれてい
   るとした。更に、 _MBC_SINGLE と照合し、文字分類を行う。

  3)Codeのヘッダーについて
   #include <clocale> は地域設定を示すが、日本向け VS2010 では既に内部設定されているようである。
   #include <Mbctype.h>はマルチバイト文字の  _MBC_SINGLの表示に必要である。 
   #include <mbstring.h>はmbstype(マルチバイト文字列)の文字型判定に必要である。

4、使用した関数とSTL
  strlen()、mbstrlen()、indata.size()、
  indata.c_str()  補足:x.c_str() は string 型である indata あるいは x を char 型に変える。
  indata.substr(0,1) と indata.substr(0,1).c_str()
    補足1:substr(0,1) は indata の文字列から0番目(最初)の文字を 1 文字分取り出す。
        取り出した文字は、string 型のために、indata.substr(0,1).c_str() で char 化。
    補足2:substr() は、single byte 文字を前提し、切り出す関数である。従い、ひらがな等の全角文字
        double byte(Multi byte) の文字を探索あるいは切り出す場合は、substr(i,2)のように 2の倍数
       で、行う必要がある。この事は、次節でも説明する。
  _mbsbtype(char*,0) char文字の0番目(最初)の文字のtype(singleかmultiか)が判る。Singleは容易に判る。 


2、フォルダ生成とファイルの格納

概要
1、記載事項の背景
 (1)目的:string型データからフォルダ生成し、各フォルダにファイルを区別して格納する事。
 (2)コンパイラー:VS2008、VS2010
 (3)目標:数値計算での各出力ファイルをフォルダに格納する事

2、結論
 ・string型データからフォルダを生成し、そのフォルダに生成fileを格納する方法の記述。
 ・meta文字(\\)位置をdirectoryの文字列から探し、その位置からdirの上方位置にホルダを生成する方法の記述。
 ・VC++ の関数からフォルダやファイルを生成する方法の記述。

3、フォルダ生成およびファイル格納につい
 (1)フォルダ生成とファイル格納の方法
   以下3つの方法で行った。

  ・_getcwdから得た dir に \\ 付きのファイル名を足す方法。

  ・VC++の splitpath と makepath を使用する方法。

  ・VC++の CreateDirectory() による方法。

 (2)コードの説明(コード2)
  現在の dir(directory) 下に、フォルダを生成する場合には、"\\" をフォルダ名の最初に付け加える。
  この\マークは、単なる\記号と区別するために\\と二つ記述する。(過去の調査でevidenceは忘却の彼方)

  1)関数 _getcwdから得た dir に \\ 付きのファイル名を足す方法。
   ・新たに作るフォルダ名を string 型 indata とする。

   ・_getcwd で、その場所の tree での位置 dir(directory) を得る。

    "\\"+indata は、string 型のために .c_str() で char 型にし、

    strcat_s で結合し、
 
    _mkdir()で indata 名のフォルダを生成する。

    次に、このフォルダに格納するファイル(今回は拡張子.csv)をこのフォルダと結合する。

    更に、新たなファイル名(folder1)を ofstram out1()の第一項にいれて、文字等を書き込む。

    次に、そのコードのおかれた dir から、上位の dir に フォルダを生成し、 file を格納する事を行う。

    その方法として、コードあるいは実行形式の exe のおかれた dictory のフルパスを

     c++の string 型にcast化する。

    ひらがな等の全角文字が含まれても、single byte 文字換算の文字数で示す size() 関数を使い、

    "\\" の位置を string のメンバー関数である single byte文字が前提である substr() で、探す。

    コード2でのこの部分を下記に示す。

    char folder3[BUFFSIZE];   //current directory を得る _getcwd は char 型を許容

    _getcwd(folder3,BUFFSIZE);

    string up_dir3=(string)folder3; // string 型文字列を扱う substr() に適用するので、stringにcast化

    vector<int> position; //current directory で "\\" の位置を書き込む。下記のsubstr(x,1)の1に注意

    for(int i=0;i<(int)up_dir3.size();i++) if(up_dir3.substr(i,1)=="\\") position.push_back(i);
    position.resize(position.size());//push_backでは、resize() する方が安全サイド

   ・directory を示す "\¥" の位置のある vector のデータ列から一つ上位の "\\" 位置を得る。

    上位位置までのデータを string 型の初期化の手法を利用し、新たな記号に新たな文字列を代入する。

    新位置に新たにフォルダを生成する。コード2でのこの部分を下記に示す。ファイルの格納は上に同じ。

    string up_dir4(up_dir3,0,position[position.size()-1]);//string up_dir4 の初期化。下記の関数で説明。

    string newfolder2="\\カウント法_"+indata; //string型故に、\\カウント_ に indata をプラスする。

    string newdir1=up_dir4+newfolder2; // dir情報のある up_dir4 に 上記の newfolder2 をプラス。

    _mkdir(newdir1.c_str()); // string型を char 化し、新たに、dir を生成する。


  2)VC++の splitpath と makepath を使用する方法。
    ・splitpathは、_getcwd で得た directory 情報を drive、dir、filename、ext(拡張子)に分解する方法。

    ・makepath は、drive、dir、filename、ext の入力情報から path (指定した位置にfile)を作成。

    ・_splitpath_s や _makepath_s は、前もって、drive 等の数値を決めてから使用する必要がある。

    ・コード
    char dirdata2[BUFFSIZE];

    _getcwd(dirdata2,BUFFSIZE);

    char drive[3]; //drive 名の大きさは、c や d、e であるから 3 byte あれば十分。

    char detect_dir[256];

    char fname[_MAX_FNAME]; // stdlib.h で決めている _MAX_FNAME の大きさは判らないが。

    char ext[256]; // 拡張子の大きさは、256 byte 以下だろう。

    上記の定義の下で、以下のように、記載すると、
    _splitpath_s(dirdata2, drive, 3, detect_dir,256, fname,_MAX_FNAME, ext,256 );

    dirdata2 等々にデータが記入される。これらのデータから新たにフォルダ、ファイルを作る。

   ・コード
    char path_buffer1[_MAX_PATH];

    char path_buffer2[_MAX_PATH];

    char drive1[_MAX_DRIVE];//splitpathのdriveのままでよいが、体裁をつくろうため。 

    char dir_new1[_MAX_DIR];//detect_dirでよいが、体裁のために設けた

    char newfname[_MAX_FNAME];

    char ext1[_MAX_EXT];

    string newfolder3="\\Splitpath_"+indata; //string 同士故に + 記号のみで合算

    strcpy_s(newfname,newfolder3.c_str());/strcpy_s は char 文字列専用のために、.c_str() を適用

    strcpy_s(drive1,drive);

    strcpy_s(dir_new1,detect_dir);//Splitpathで得た情報内容のまま上記の体裁のため。

    strcat_s(dir_new1,newfolder3.c_str());

    strcpy_s(newfname,"結果121");//newfnameを使用するために敢えて設けた。

    strcpy_s(ext1,"csv");//ext1を使用するために敢えて設けた。

    _mkdir(dir_new1) ;//このdir_new1のdirがないとpath先がないので、この文が必要である。
    
    _makepath_s(path_buffer1, _MAX_PATH,drive1,dir_new1,newfname,ext1);

    _makepath_s(path_buffer2, _MAX_PATH,drive1,dir_new1,"結果122""csv" );//file名と拡張子の記載

  3)VC++の CreateDirectory() による方法。
   この方法は、
   System::IO::Directory::CreateDirectory("CreatDirectry_method_folder" );

   のように、("folder-name")部の folder-name に生成するフォルダ名を記載すると、directoryが出来る。

   次に、 folder 名を冠した "\\” 付きのファイル名(拡張子有)を sprin tf_s でbuffer部に作るとfileが出来る。

  4)その他
   ・コード2の実行形式 exe では、置いた場所に2つのフォルダと3つのファイル、

    "exe"の格納フォルダと同じ位置に2つのフォルダが生成される。

   ・ directory を移動させる方法として、UNIXやDosでは "chdir" が準備されている。

   ・ここでのFile生成の手法 1)数値計算 5 直交関数 Legendre多項式 の直交性確認の計算に用いた。

   ・注意事項としてdirname=_getcwd(dirdata,256)で、dirnameに、"\\xxx"を付加し、新たにディクトリを
    作ると、dirdataが新たなディクトリ名に変更される。

4、使用した関数とSTL
   string str2(str1,2,3); // string str1="123abc" の時に、str1の0番目が1、1番目が2で、2番目が3である。
               str2(str1,2,3) は、str1の2番目の3から3つの文字で初期化され、"3ab"と表示。
   _getcwd()、 _mkdir()、
   strcpy_s、strcat_s、
    _splitpath_s()、 _makepath_s()、 CreateDirectory()、
   int xx.size()、
   string xy=(string)yyのcast、// yyは char 型
   zz.push_back()、
   zz.resize(zz.size()) //データを push_back() で取入れた際、最後にデータのsize()を確定した方が安全。



3、csv データの読み込みと書き込み

概要
1、記載事項の説明
  ・テキストファイルの一種であるcsvファイルからデータを読む方法を2通り示す。

  ・csvデータには、数値間に comma 記号(ASCII の十進数では 44 番)があり、MSのExcelや三四郎では、

   拡張子に csv 形式を選択できて、このデータ形式は広く使用されている。

   しかし、この " , " 記号は、ファイルでは表示されない。

  ・csv形式のデータファイルを作る方法

   c++の <fstream> の ofstream による csv ファイルへの書き込みでは、

   変数 a,b,c の値を out1<<a<<","<<b<<","<<c<<endl; と記述して、

   "," 記号をファイルに記述している。

   しかし、a と b の間に記述した "," は csv ファイルでは、前述のように表示されない記号となる。

   c++での "," の記述は、手間を要するが、c言語では、変数 a,b,c の値をprintf文でa,b,c として、comma を
   
   コードに打つので、記述は容易である。c言語は、複素数操作が難しいので数値計算上は不利である。

  ここでは、
  1)数値を直接に、int あるいは、float、double で読む方法と、

  2)string で読み、数値に変換していく方法

  について、記述する。

2、結論
  csvファイルからデータの読み込みは、1)数値を直接に読み込む方法が容易である。

3、csvデータの読み込みと書き込み
 1)数値の直接読込み法(コード3)
  csvファイルは、一行内の数値は、","のカンマで区切られている。このカンマは、csvファイルには表示されて
  いない。例えば、以下のようになっている。
  csvfile内  123 (,) 456 (,) 789 

  また、カンマ記号はアスキ−の16進法では、0x2cの文字(char)でもある。

  従い、カンマ記号が char 文字である事を利用し、このカンマをchar記号で読む事で、

  ファイルの数値を数値として直接に読む事が可能になる。

   コード
    char conma; //string conmaでは読めない。また、","をconmaの表現でなくて、 char aでも良い。

    ifstream input0("sample_data0.csv", ios::in | ios::binary);

    input0>>indata1>>conma>>indata2>>conma>>indata3;
    csvfile内 123 (,) 456 (,) 789

  読み込む際、while文を使用している。このwhile文の3通りの使用方法を記述した。また、読み込んだcsvファイ
  ルで、2つのファイルについては、remove 関数で、削除した。


 2)文字列stringから数値に変換する方法(コード4)
  コードの順序
  (1)csvファイルの数値をstringの文字列で読み、文字列数字を数値に変換し、ファイルに出力する。

  (2)string ::iterator xxx=find_first_of()と","を使用し、文字を切り出す。

  (3)文字列数字を、strtod()で数値に変換する。

  (4) 多数の出力ファイルを、ホルダに格納する。

   コード
    // STLのfind_first_ofによる文字の切り出し(csvファイルの持つ","区切りを利用)
    string conma=",";// 下記 find_first_of は#include<algorithm>が必要
    string::iterator place31=find_first_of(line3.begin(),line3.end(),conma.begin(),conma.end());
    string s3;
    for(int i=0;i<(place31-line3.begin());i++) s3.insert(s3.end(),line3[i]);
    char *stopstring;
    double x= strtod(char_s3, &stopstring);//&stopstringを NULL と記載しても問題ない。
    basic_string <char>::iterator line3_Iter;

    //s3に読み込んだ文字列をeraseにより削除
    basic_string <char>::iterator line3_Iter;
    line3_Iter = line3.erase (line3.begin(),line3.begin()+(place31-line3.begin())+1 );

  3)その他、
   ・注意事項
    xxx=find_first_of()のxxxは場所を示すのみであるので、for文では、xxx-yyy.begin()で場所間の差を
     を得る事。

    file.csvの各行の末尾には","がないので、コードの作り方で付け加える必要がある時がある。

4、使用した関数とSTL
  int、float、double、char、
  ofstream、ios::out、ios::in、ios::binary、|、input.is_open()、while()、input.eof()
  string ::iterator place0=find_first_of()
  string_x.insert()、string_x.begin()、string_x.end()、string_x.erase()、
  string_x.c_str()、strtod()、remove()、
  getline()、



4、多量データの読み込み


1、記載事項の説明
  多量データを読み込むために、

  (1)c言語の malloc & realloc を使用した計算、

  (2)allocatorによるデータ確保、
  
  メモリー操作のために、(3)auto_ptr & new、delete について記載した。
  
  また、メモとして、MSのエクセルやvectorの容量の上限、整数や実数の Byte 数を残した。

2、結論
  メモリー操作は、確保領域の解放の手法が重要である。

3、多量データの読み込み
 1)c言語のmalloc&reallocによる多数データ読込(コード5)
  csv形式のデータファイルを読込む場合、c言語ではmallocによりメモリ確保が出来る。
  しかし、初期化失敗の不安もある。このために、mallocとreallocを併用したデータ読み込みの例を示した。
  malloc で、初期化し、realloc で領域を確保した。

  mallocとreallocの使用法は、以下の順序で行った。
   ・ヘッダー  <malloc.h>
   ・例   int *testNum;

   ・mallocの定義
    初期容量 num1=10;
    項目 // testNum
    mallocの使用
    if((testNum=(int*)malloc(num1*sizeof(int)))==NULL)exit(1);
    size=_msize(testNum);

    ・reallocの定義(上記のmallocの定義群に続けて)
    再定義の容量 kyy=28900; num2=kyy;
    項目 // testNum
    reallocの定義
    if((testNum=(int*)realloc(testNum, size+(num2*sizeof(int))))==NULL)exit(1);
    size=_msize(testNum);

   ・freeの定義(使用後に適用、ここではreturn文の前)
    free(testNum);

   ・test用のファイルサイズ 5.4MB で、csv の行数30000、列数30


 2)c++言語のallocatorによるデータ確保(コード6)
  (1)allocator
   データ確保の方法としてallocatorがある。独自allocatorについて、スコット・メイヤーズ著のEffective STL
   では、最後には、webで公開されているコードを利用する事を推奨している。
   この事は、独自allocator使用に注意を必要とする事を意味し、使いにくい事になる。
   
   このために、ハーバート・シルト著のSTL標準講座に記載している方法、すなわち、vectorに標準的に定義さ
   れているallocator_typeを利用して、1048576*3行、10列 のデータを扱ったコードを作成した。
  
   このallocator_type法は、上記の1)と類似で、扱いやすい。順序を以下に示す。

   ・ベクトルの定義 vector<int>::allocator_type vin0;

   ・ポインターの定義 allocator<int>::pointer vin0ptr;

   ・ベクトルの要素数の決定 int k=1048576*3;

   ・ベクトル/ポインターの関係の定義 vin0ptr=vin0.allocate(k);

   ・ポインターへの数値代入  vin0ptr[i]=i;

   ・メモリー域の解放 vin0.deallocate(vin0ptr,k);

  (2)コードの説明
   Excel 2007では最大1,048,576 行、16,384 列を記入出来る。

   行数が、1048576行を超えるような1048576*3行のデータvin0ptr[i]をcsvファイルで表示するために、
   1048576行毎に新たにファイルを作成した。結果として、1048576行、10列のcsvファイルサイズは約
   110,000KB/ファイルである。

   なお、vector<int>の最大サイズは、1073741823であり、そこまでのデータ数は確保できる事になる。
   1秒毎にデータをvectorで保持した時サイズ1073741823は、約12430日分である。また、Excel 2007 の
   1,048,576 行は、12日分に対応する事になる。

  (3) コードに関する説明
   通常のvectorでも1048576*3行以上のデータは確保できる。
   vector<int>::allocator_typeは、数値計算の分野の調査を行いたい。
   
   getlineのVS2008のサンプルコードgetline(cin1,s1,' ')では、csvファイルの1行を完全に読み取る事が出来な
   い時がある。
   しかし、getline(cin1,s1)にすると、1行を完全に読み取る事が出来る。


 3)auto_ptr&new、delete (コード7)
  VS2008sp1では、メモリ操作に<memory>(TR1)が採用された。
  これには、auto_ptrの改良が図られたshared_ptrがあるとweb上では説明されている。vectorを主にしたコン
  テナを用いて来たので、自動的にメモリが解放されて来た。 このために今までに、auto_ptrを使用した事が無
  かったので、調査した。
  
  結論
  auto_ptrでは、ポインタの代入を行えば、所有権が移動する。

 4)その他
  メモとして下記に、データ型とサイズの関係を示す。
   1Byte は 8bit である。1MB = 1024KB、日本語は 2Byte である。
   整数: int 4Byte、short 2Byte、long 4Byte
   実数: float 4Byte、double 8Byte(64bit)、long double 9Byte(72bit) (VC++6 の時)
   文字: char 1Byte

4、使用した関数とSTL
  malloc、realloc、free、exit(1)、printf()、wprintf、fopen_s、fprintf()、FILE
  getline()
  



  

Information

2012年
この章全体の履歴
1)2012年1月:2011年の文字、フォルダ、データ読込み、多量データの統合  
2012年
この章の変更追加履歴
1)多くの写真の追記 2012/7/3

ナビゲーション

もっと、明るい感じの日でしたおお、観覧車
春かな夏だったかな、横浜 みなとみらい
いつかの山下公園
横浜 環状2号線 ラーメン街道側
箱根 紅葉 二題
箱根 紅葉 二題
箱根 曽我兄弟の遺跡
磯子Prince Hotelから海
今は昔、磯子Prince Hotel植物園
目黒雅叙園 花
古代文字のある石
走るホンダのホンダ
草木盛ん、夏の日
花は、花
お台場 東京テレポート
2011年4月初旬桜満開
東京 本門寺通り
みなと横浜 ランドマークタワーより
横浜 上大岡駅より鎌倉街道
恋人はスナイパー撮影 上永谷
ガーナ Volta 橋 より VOLTA BRIDGEから下流側 Mainzかも
線路は続く
紀元前から世界を知っている Moses stone
詩人テニスンも
Big Ben
富士山の肩を吹き抜ける 風と雲
富士 山中湖
夏の夕刻の空と海の間
夏の夜 横浜みなとみらい
2010年夏の夜 湾内から 決断の星空と汽車道
 横浜みなとみらい 汽車道
冬の日のオペラ座
パリ オペラ座