月: 2022年3月

StringBuilderってどうよ?

StringBuilderの効果ってどうなのか?というところに疑問を持ったので、調べてみることにした。

Javaの文字列結合はStringBuilderでいいのか

結論的には、

・複数ステートメントで
・結合される側の文字列を複数スレッドで共有しない場合は
メモリアロケーションの回数が少ないStringBuilderが一番高速で文字列結合できる

なのだが、どのような処理になっているのでこうなる!というのが書かれていて、非常に参考になった。

スレッドを使ったときは不具合が起きるというのは、以下のページに書いてある。

【Java】+演算子、StringBuilder、StringBufferの違い(実際に測ってみた。)

StringBuilderとStringBufferの使い分けについても書いてあるので、これも参考に。

以下はVB(.NET)のStringBuilderについての記載。

Visual Basic で StringBuilder を使うべき場合とその利点

こちらもJavaと同じような話。(SE2年目でこの記載は凄いなぁ。うちの社員にもこういう人欲しい。)

使い方については、

意外と知られてないStringBuilderに関する初歩的なTips【Java・C#】

なんか、どうでしょう。
インスタンスをコロコロ変えたくないなぁと思っているので、こういうのはありがたい。

が、少し待て!

男(かどうか知らんが)がすなる時間計測といふものを女もしてみむとてするなり・・・

VC#(.NET Framework4.8)でやってみた。
<1> Length=0でクリアする
<2> 新たなインスタンスを作る
<3> Clearを使う(C#はClearメソッドがある)

        static void Main(string[] args) {
            var sw = new System.Diagnostics.Stopwatch();

            // <1>
            for (int j = 0; j < 10; j++) {
                sw.Start();
                StringBuilder sb1 = new StringBuilder("");
                for (int i = 0; i < 999999; i++) {
                    sb1.Length = 0;
                    sb1.Append(i.ToString());
                }
                sw.Stop();
                Console.WriteLine($"1) {sw.ElapsedMilliseconds}ms");
            }

            // <2>
            for (int j=0;j<10;j++) {
                sw.Restart();
                for (int i = 0; i < 999999; i++) {
                    StringBuilder sb2 = new StringBuilder("");
                    sb2.Append(i.ToString());
                }
                sw.Stop();
                Console.WriteLine($"2) {sw.ElapsedMilliseconds}ms");
            }

            // <3>
            StringBuilder sb3 = new StringBuilder("");
            for (int j = 0; j < 10; j++) {
                sw.Restart();
                for (int i = 0; i < 999999; i++) {
                    sb3.Clear();
                    sb3.Append(i.ToString());
                }
                sw.Stop();
                Console.WriteLine($"3) {sw.ElapsedMilliseconds}ms");
            }
        }

結果発表!

<1> Length=0でクリアする <2> 新たなインスタンスを作る <3> Clearを使う
1) 693ms 2) 1440ms 3) 583ms
1) 1303ms 2) 1495ms 3) 503ms
1) 2398ms 2) 1455ms 3) 472ms
1) 3421ms 2) 1401ms 3) 514ms
1) 4656ms 2) 784ms 3) 520ms
1) 5780ms 2) 692ms 3) 500ms
1) 6798ms 2) 580ms 3) 498ms
1) 7786ms 2) 599ms 3) 519ms
1) 8868ms 2) 553ms 3) 485ms
1) 9937ms 2) 643ms 3) 469ms

<1> Length=0でクリアだと、処理速度がどんどん上がっていくので、嫌な感じ。
<2> 新たなインスタンスを作るは、<1>より速くて<3>と同等かもしくは遅いレベル。
<3> Clearを使うのが一番コンスタントに速い。

Javaは試していないので申し訳ないのだが、VC#ならば、用意されているClearメソッドを利用したほうがインスタンスを毎度作るよりは速いということになる。

色々調べてみるものだ、うん。
「無知の知」というのは大事だなぁと思う午後のひと時であった・・・

AccessVBA覚書 Public変数が変わらない

Accessは嫌いです。
理由はわかんないから。

オイオイ・・・

って、そんな理由かい!って思う人もいるのだろうけど、わからないというのは
・想定通り動いてくれない
・Debugしながら動かしたときと、Debugしないで動かしたときで動作が変わる
という2点からだ。

この間VB6のソースを見ていた時も実は同じようなことがあって、
・Debugしながら動かしたときと、Debugしないで動かしたときで動作が変わる
というのは、どうしたらいいのかさっぱりわからないのだ。

そして、VBAをDebug.Printを使って変数値を見ながら実行させてみたらば、Public変数に値を入れているのに値が置き換わっていないことが判明。

で、調べてみたらこんな記事があった。

Public宣言された変数の有効期間 [VBA]

なるへそ。
ってかさ、別に参照設定とかPublic変数を変えたとか、致命的なエラーが出たとかなら、リセットされるのはわかりますよ。
でもね、実行中にリセットする必要ありますか?

何のためのPublic変数なんですか!!!!

と。

で、上述の記事でテーブルに入れるのがいいと書いてあったので、結局その通りいたしました。
Excelでこんなこと起きたことはないんですけどね。
でも起きたことがないだけで、起きることがあるんだと思うとExcelのマクロも作れませんな・・・

大丈夫かMicrosoft。

さようなら Engadget日本版

Engadget日本版のサイトが閉まるそうだ。

はじめてEngadget日本版の記事を見たときは楽しかった。
特にスキだったのはITTOSAIだったかITTOHSAIだったか、とにかくイットウサイというライターさんの記事だった。

だけど、世の中の風潮か、だんだん広告が増えていき、だんだん別サイトへのリンクが並び、はっきり言ってエンガジェットでなくってもいいんだよね~と思うようになった。
もう、Amazonのレビューで良くない?、他のブログでよくない?みたいな。

となると、足は遠のく。
フロントページが広告だらけになったとき、私のエンガジェット愛は終わった。
でも、それでも捨てきれず、Facebookのリンクだけはつけてたけど。

*GBまで***円、だけど低速でだったら上限ないよ!とか、家の光回線だと上限はないこととかで、私たちはほぼ通信料の上限のない世界に生きているといってよい。
そこで本来気にしなければいけないことを気にしなさ過ぎているのではないかということをここで書いておく。

私たちは広告を見るために通信料をはらっているわけではない!

行くページ行くページ、広告がいくつも表示されていて、記事より広告のほうがボリュームがあることのほうが多いのではないだろうか。
しかし、私は広告を見るためにそのページにアクセスするわけではないので、広告の表示に自分の通信料が使われていることに対してはちょっと腹が立つ。
民放テレビであればCMが出るのは当たり前で、当然それを見ようとも思わなくても電気代は払っているので、サイトだって当然といえば当然なのだ。だが、テレビCMは番組より出しゃばったりしない。(たまに出しゃばった通販会社とかあるけど)見ている人間をがっくりさせることは少ない。(動画サイトなぞは、見ようと思った動画のサムネイルをクリックしていきなりCMに入るのでがっくりくる。)
それに、
ネットは災害が起きたときにも、こんな広告を載せ続けて通信を逼迫させつづけるのであろうか。
という疑問もある。

こういうことを思うのは私がネットの記事のほとんどが私と同じように自己満足、自己肯定、備忘録といった自分中心的な、自分発のものだと考えているからなのだが、

自己満足して、さらに広告収入まで欲しいとは、少し欲しがりすぎではありませんか???

と思いながら、さようなら~と軽く手を振ってEngadgetとお別れすることにした。(5月に閉まるらしいからまだ先だけど)
まぁ、結局記事の中身だよね。
(って私が広告収入得てたら、お前もか~って言ってもらっていいですよ)

ExcelVBA覚書 CSV読込とSchema.ini

CSVファイルを読み込むときに、ADODBを使って読み込むやり方というのがあって、これには
1,ADODB.Streamを使う
2,ADODB.CommandとADODB.RecordSetのGetStringを使う(SELECT * FROM [{ファイル名}])
という2種類の方法があるというので、サンプルを実行してみたら、
1より2のほうが若干処理が速い。
ただ、2には落とし穴があって、それは
★勝手に型を変えてしまう
★読み込み方によっては正しくすべてのデータが取り込めない
ということだと分かった。

前0がついていようが数値にしよるし、日付は勝手に日付型でシートに出力されてしまうは、設定の仕方によっては思い通りのデータ取込ができなくなってしまう。

ってかさ、こんないい加減なサンプル送ってくんなよ!!
(他のところで実行時エラー起きてるし・・・)

ってなことであったが、どうすれば改善できるのか知らない私。
いろいろやってみて途方に暮れたところでGoogle先生の厄介になってみたら、

Schema.ini使うんです!

みたいな記事発見。で、「ADODB Schema.ini」で検索をかける。
ふむふむ、取り込む列の型とか、文字エンコードとか、このファイルの中で指定してあげればよいのだね!
————-
[{ファイル名}]
ColNameHeader=False
CharacterSet=65001
Format=CSVDelimited
Col1=列1 Text
Col2=列2 Text
Col3=列3 Text
Col4=列4 Text
Col5=列5 Text
—————
{ファイル名}は実際に読み込むファイル名(パスはなしで、ファイル名だけでいい)
ColNameHeader は、ヘッダー有無。(Trueはあり)
Format=CSVDelimited は、CSV形式(カンマ区切り)
CharacterSet=65001 は文字エンコードがUTF-8である。(S-JISなら932)
下に読み取り用のサンプルソースをつけているが、そこでCharacterSetを指定しているので,iniには必要ない。
(どちらかに設定があればOK)
Col1=*** の *** は、列のタイトル、その右のTextが型

【VBA】ADOを使用してテキストファイル(CSV)をDB操作する方法のまとめ

を参照したところ、型は整数はShortやLong、日付はDateと記載されている。
Char型で50文字なら、「Char Width 50」といったように記載されているので、固定長であればこういう記載になるのかと思う。
(試してはいない)

で、このSchema.iniをcsvファイルのあるフォルダパスと同じところに入れておくのだが、

チョイ待ち!!

読み込むcsvファイルが常に同じところに置かれているとは限らんではないか!
ということになった。
そう、読み込むCSVは、ダイアログで選ばせるのだ・・・
となると、csvと同じところにschema.iniを配置させねばファイルの意味がないし、いや、そもそもダイアログで選ぶファイル名もSchema.iniで定義したファイル名と異なっていたら読み込んでくれへんやん!!!

と、また1つ問題が生じてしまった。
ということで、最終的には、

a) 一時保存用のフォルダを作る
b) a)で作ったフォルダにSchema.iniを入れる
c) ダイアログで選択されたCSVファイルを a)で作成したフォルダに固定のファイル名にコピーする
  (固定のファイル名というのが、Schema.iniに定義する{ファイル名}と同じになるように)
d) c)のコピーされたほうのファイルをADODBでSELECTして読み込む
e) 読込が終わったら、c)のコピーされたほうのファイルを削除

として、どの場所にあっても、同じフォーマットで取り込まれるようにしたのだった。
ってなると、ADODB.Streamを使うより時間がかかってしまったので、結局Streamのほうが速い!という結論に至った。

とはいえ、CSVファイルの全データが取得できなかった点も、Schema.ini、Properties(“Extended Properties”)や、GetStringメソッドを見直して何とかとりあえずうまく行くようにはなった。
Officeは2016。

    Dim con As ADODB.Connection
    Dim cmd As ADODB.Command
    Dim rs  As ADODB.Recordset

    Set con = New ADODB.Connection
    With con
        .Provider = "Microsoft.ACE.OLEDB.12.0"
        .Properties("Extended Properties") = "Text;CharacterSet=65001;"    '65001=UTF-8 ,932=SJIS
        .Open {csvファイルのあるフォルダパス}
    End With
    Set cmd = New ADODB.Command
    Set cmd.ActiveConnection = con
    cmd.CommandText = "SELECT * FROM [{CSVファイル名}] "
    Set rs = New ADODB.Recordset
    rs.CursorType = adOpenStatic
    rs.Open cmd
    
    Dim dmp As String
    dmp = rs.GetString(adClipString, , ",", vbCrLf, "")  '行はCRLF, 列はカンマで区分するという設定に
    rs.MoveFirst
    Do Until rs.EOF
        '****** 1行分の処理を記載 ***********  
        rs.MoveNext
    Loop
   
  ’どばっとExcelに貼りつけるなら、Range.CopyFromRecordsetメソッドで 
    ' Activesheet.Cells(1,1).CopyFromRecordset rs            みたいな感じ

   rs.Close
    Set rs = Nothing
    Set cmd = Nothing
    con.Close
    Set con = Nothing

GetString メソッド (ADO)

中途半端なサンプルを送りつけられたせいで悩んだが、かえっていい勉強になったわぃ!
ということにしておこう。