valgrind

c言語で開発を行っているときにちょいちょいお世話になるフリーのツール
valgrindの使い方のまとめです。

valgrindはlinuxベースで動作する、メモリーリーク・メモリ不正アクセス・プロファイルなどのチェックができる開発支援のツールです。

WindowsだとVisualStudioとかでいろいろやってくれちゃうんですが、gdbとかじゃここまでやってくれないのでこのツールを使ってます。

とりあえずインストール
http://valgrind.org/downloads/current.html
からソースをダウンロードします。
以下のコマンドでインストール完了です。
良くあるパターンですね。

$ tar xvf valgrind-3.9.0.tar.bz2
$ cd valgrind-3.9.0
$ ./configure
$ make
$ su
# make install

valgrindには以下のサブツールが含まれています。

  • memcheck メモリチェックツール(メインのツール)
  • cachegrind キャッシュプロファイラ
  • exp-bbv 基本ブロックベクター生成ツール
  • helgrind スレッドエラーの検出
  • callgrind コールグラフ生成。
  • exp-dhat 動的ヒープ解析
  • lackey ツールのサンプルコード
  • none 何もしないツール
  • drd スレッドエラーの検出
  • exp-sgcheck スタック配列とグローバル配列のオーバーラン検出
  • massif ヒーププロファイラ

wikipedia参照しただけなので良くわからないツールが満載…

とりあえず次回はメインのmemcheckの使い方です。

viの文字コード指定

いつも忘れてしまう、viで文字コード指定して開く方法
自動判別とかしてくれないのだろうか…

開くときに指定する場合は

vi -c ":e ++enc=euc-jp" xxxx.txt

開いた後に指定する場合は、viのコマンドで

:e ++enc=euc-jp

でOK

指定できる文字コード

iso-2022-jp
cp932
sjis
euc-jp
utf-8

があるみたい。


てか自動判別もできるみたい
~/.vimrcに以下を追加するらしい

set encoding=utf-8     <--OSのデフォルト文字コード
set fileencodings=iso-2022-jp,cp932,sjis,euc-jp,utf-8 <--左から順に当てていくらしい

CVSパーサー

業務でCSVの読み込みが必要だったのでクラス作成。
いつも適当に作っていたのですが、今回ある程度ちゃんと作ってみたので公開します。

動きとしては、

  • セパレータはカンマ
  • ダブルクオートで囲まれている中の改行は、1データの終わりではない
  • ダブルクオートが続いていた場合、1つのダブルクオートの文字として扱う

こんな感じ

んでソース

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;


/**
*
* CSV1行の情報保持クラス
*
* @author xxxxx
*
*/
final class RowInfo{
     /**
     * 読み込み元ファイルの行番号
     */
     int lineNum;
     /**
     * 1分のトークン
     */
     String[] csv;
     /**
     * コンストラクタ
     * @param lineNum
     * @param csv
     */
     public RowInfo(int lineNum,String[] csv){
          this.lineNum = lineNum;
          this.csv = csv;
     }
}
/**
*
* CSV解析クラス
*
* @author xxxx
*
*/
public class CSVParser {
     /**
     *
     * コンストラクタ
     *
     * @param colomSize
     */
     public CSVParser(int colomSize) {
          this.colomSize = colomSize;
     }
     public CSVParser() {
     }
     /**
     * 1ファイル分のCSV情報
     */
     ArrayList<RowInfo> csvList = new ArrayList<RowInfo>();
     /**
     * CSVのカラムサイズ
     */
     public int colomSize = -1;

    public int getCSVSize(){
         return csvList.size();
    }
    public String[] getCSV(int index){
         return csvList.get(index).csv;

    }
    public int getLineNum(int index){
         return csvList.get(index).lineNum;
    }
    /**
     * 1ファイル分のCSV文字列設定
     * @param str
     */
    public void setSource(String[] str){
         source = str;
    }
    /**
     * パース前のオリジナル文字列
     */
    private String[] source = null;
    /**
     * CSVファイルのパース<br>
     * パースのルールは<br>
     * ダブルクオートがあったら、それ以降のカンマ、改行はデータとして取り込む<br>
     * ダブルクート中の連続したダブルクオートは一つのダブルクオートとして取り込む<br>
     * 先頭行が#の場合コメントとして読み飛ばす<br>
     *
     */
    public void parse(){

         boolean inDoubleQuote = false;
         StringBuilder token = new StringBuilder();
          ArrayList<String> rowCsv = new ArrayList<String>();
          int lineNum = 0;


          boolean isEof = false;
         for(int i = 0;i < source.length;i++){
              // ファイルの最終行か?
              if(source.length - 1 == i){
                   isEof = true;
              }

              String lineStr = source[i];
              if(lineStr == null){
                   lineStr = "";
              }

              // ダブルクオート中ではない場合(新規行の解析開始)
              if(!inDoubleQuote){
                   lineNum = i + 1;     // 行番号を保持
                  // 空行の場合、スキップ
                  if(lineStr.length() == 0){
                       continue;
                  }
                  // コメントの場合スキップ
                  char comment = lineStr.charAt(0);
                  if(comment == '#'){
                       continue;
                  }
              }

              // 一行分のCSVをパース
              for(int j = 0;j < lineStr.length();j++){
                   char curChar = lineStr.charAt(j);
                   char nextChar = '\0';
                   boolean isEndLine = false;
                   // 一つ先の文字も取得する
                   if(j + 1 < lineStr.length()){
                        nextChar = lineStr.charAt(j + 1);
                        isEndLine = false;
                   }else{
                        isEndLine = true;
                   }

                   // クオートじゃないときの処理
                   if(!inDoubleQuote){
                        // クオート処理開始
                        if(curChar == '"'){
                             inDoubleQuote = true;
                        }
                        // カンマの場合1トークン終了
                        else if(curChar == ','){
                             rowCsv.add(token.toString());
                             token = new StringBuilder();
                       }
                        // 上記以外はトークンに追加
                        else{
                            token.append(curChar);
                       }
                   }
                   // クオート中の処理
                   else{
                        // クオートが続いてたら一つだけトークンに追加(エスケープ)
                       if(curChar == '"' && nextChar == '"'){
                                j += 1;
                                token.append(curChar);
                       }
                       // クオートの場合クオート処理終了
                       else if(curChar == '"'){
                            inDoubleQuote = false;
                       }
                       // 上記以外はトークンに追加
                       else{
                            token.append(curChar);
                       }
                   }

                   // 行の末尾の場合1トークン終了(しかし、クオート中の場合は次の行も継続)
                   if(isEndLine && !inDoubleQuote){
                         rowCsv.add(token.toString());
                         token = new StringBuilder();
                   }
              }

              // クオート中でないか、最終行の場合
              // 1行解析終了なので配列に取り込む
              if(!inDoubleQuote || isEof){
                   // カラム数が足りない場合、nullでカラム数を追加する
                   if(colomSize > 0){
                        int addNum = colomSize - rowCsv.size();
                        for(int j = 0;j < addNum;j++){
                             rowCsv.add(null);
                        }
                   }
                   RowInfo rowInfo = new RowInfo(lineNum, rowCsv.toArray(new String[rowCsv.size()]));
                   csvList.add(rowInfo);
                   rowCsv = new ArrayList<String>();
              }
              // クオート内の場合、次の行もパースを継続
              else{
                   token.append("\n");
              }

         }
    }
}

んで、使い方

void main(String[] args){
         String filePath = "xxx.csv";
         FileInputStream is = null;
         InputStreamReader in = null;
         BufferedReader br = null;

         try{
              // CSVファイル読み込み
              File file = new File(filePath);
              is = new FileInputStream(file);
              in = new InputStreamReader(is);
              br = new BufferedReader(in);

              // 一行づつ読み出し配列に格納
              String line;
              ArrayList<String> lines = new ArrayList<String>() ;
              while( (line=br.readLine())!=null ){
                   lines.add(line);
              }
       // CSV解析
              CSVParser csvParser = new CSVParser ();
              csvParser.setSource(new String[lines.size()]);
              csvParser.parse();
              String[] csv = csvParser.getCSV(0);

         }finally{
              if(is != null){
                   is.close();
              }
              if(in != null){
                   in.close();
              }
              if(br != null){
                   br.close();
              }
         }
    }
}

リサイクルBin

Oracleで作業してる際に、ふとテーブル一覧を確認したらBIN$xxxxxとかいうテーブルが大量に・・・
なんだ?これと調べてみたらリサイクルBinというらしい。
テーブルをドロップしてもこのBINというテーブル名で残るらしい、
Windowsのごみ箱みたいなもの、んでそれを削除するSQL

Purge RecycleBin;

すっきり☆

ちなみにリサイクルBinを確認する方法

show recyc;

リサイクルBinを復元する方法

flashback table 復元対象のテーブル名 to before drop;
flashback table BINxxxxx to before drop;

あとリサイクルBinを使用しないで削除する方法

drop table テーブル名 purge;

起動引数解析

JavaCUIプログラムを作成する際に、毎度起動引数解析処理をコーディングしてたので一つの汎用クラスを作ってみました。

ライブラリを使っても良いんだけど、基本自前で作成します。(ライセンスとか面倒だし…)

import java.util.ArrayList;
import java.util.Iterator;

/**
*
* 起動引数のオプション情報クラス
*
* @author xx
*
*/
final class OptionInfo{
     /**
     * オプション名
     */
     String optionName = null;
     /**
     * このオプションに値があるかの有無
     */
     boolean isValue = false;
     /**
     * ヘルプのコメント
     */
     String comment = null;
     /**
     * このオプションの値
     */
     String value = null;
     /**
     * このオプションが起動引数に存在しているか
     */
     boolean isExist = false;

     /**
     *
     * コンストラクタ
     *
     * @param optionName オプション名
     * @param isValue オプションの後に値が設定されるかの有無
     * @param comment ヘルプ表示時の説明文
     */
     public OptionInfo(String optionName,boolean isValue,String comment){
          this.optionName = optionName;
          this.isValue = isValue;
          this.comment = comment;
     }

}
/**
*
* 起動引数解析クラス
*
* @author xxxx
*
*/
public class ArgsParser {

     /**
     * オプション情報
     */
     ArrayList<OptionInfo> optionInfo = new ArrayList<OptionInfo>();
     /**
     * オプション以外の引数格納配列
     */
     ArrayList<String> values = new ArrayList<String>();
     /**
     *
     * オプション設定の追加
     *
     * @param optionName オプション名
     * @param isValue オプションの後に値が設定されるかの有無
     * @param comment ヘルプ表示時の説明文
     */
     public void addOption(String optionName,boolean isValue,String comment){
          optionInfo.add(new OptionInfo(optionName,isValue,comment));
     }
     /**
     *
     * 指定オプションが起動引数に存在しているか
     *
     * @param optionName オプション名
     * @return オプションがあった場合true
     */
     public boolean isExist(String optionName){
          for (Iterator<OptionInfo> i = optionInfo.iterator(); i.hasNext();) {
               OptionInfo o = i.next();
               if(o.optionName.equals(optionName)){
                    return o.isExist;
               }
          }
          return false;
     }
     /**
     *
     * 指定オプションの値を取得
     *
     * @param optionName オプション名
     * @return オプションの値
     */
     public String getOptionValue(String optionName){
          for (Iterator<OptionInfo> i = optionInfo.iterator(); i.hasNext();) {
               OptionInfo o = i.next();
               if(o.optionName.equals(optionName)){
                    return o.value;
               }
          }
          return null;
     }
     /**
     * 起動引数の値を取得(先頭)
     * @return 起動引数の値
     */
     public String getValue(){
          if(values.size() == 0){
               return null;
          }
          return values.get(0);
     }
     /**
     * 指定位置の起動引数の値を取得
     * @param idx
     * @return 起動引数の値
     */
     public String getValue(int idx){
          if(values.size() <= idx){
               return null;
          }
          return values.get(idx);
     }
     /**
     * 起動引数の数(オプション以外の)
     * @return
     */
     public int getValueNum(){
          return values.size();
     }
     /**
     * 解析処理
     * @param args
     */
     public void parse(String[] args){

          for (int i = 0; i < args.length; i++) {
               String arg = args[i];

               boolean isOption = false;
               // オプションの取得処理(同一オプションがあった場合後方優先)
               for (int j = 0;j < optionInfo.size();j++){
                    OptionInfo o = optionInfo.get(j);
                    if(arg.equals(o.optionName)){
                         o.isExist = true;
                         if(o.isValue){
                              if(i < args.length){
                                   i += 1;
                                   o.value = args[i];
                              }else{
                                   // 値が存在していない場合はエラー
                                   throw new IllegalArgumentException(String.format("オプション[%s]に値がありません", o.optionName));
                              }
                         }
                         isOption = true;
                    }
               }
               // オプションでなければ値を保持
               if(!isOption){
                    values.add(arg);
               }
          }
     }
     /**
     * ヘルプ表示
     * 引数は説明文、オプションは自動生成
     */
     public void printHelp(String message){
          System.out.println(message);
          for (Iterator<OptionInfo> i = optionInfo.iterator(); i.hasNext();) {
               OptionInfo o = i.next();
               System.out.println(String.format("    %s : %s", o.optionName,o.comment));
          }
     }


}



んで、使い方サンプル

void main(String[] args){
          ArgsParser arqgsParser = new ArgsParser();
          // オプション設定
          arqgsParser.addOption("-c", true, "-cの説明");
          arqgsParser.addOption("-d", true, "-dの説明");

          try{
               arqgsParser.parse(args);
          }catch(Exception e){
               arqgsParser.printHelp("使い方 xxx ");
               return;
          }

          // オプション取得
          String cStr = "";
          if(arqgsParser.isExist("-c")){
               cStr = arqgsParser.getOptionValue("-c");
          }
          String dStr = "";
          if(arqgsParser.isExist("-d")){
               dStr = arqgsParser.getOptionValue("-d");
          }
          // 起動引数取得
          String value= arqgsParser.getValue();
}

いろいろ突っ込みどころはあると思いますが、ざっくりとこんな感じ