2009/05/31

PDFCreator日本語問題まとめ

いろいろありましたが、まとめ、いきましょう。とりあえずPDFCreatorのverは0.9.8になります。

PDFCreator0.9.8 (日本語対応バイナリ配布)

コンパイル環境のない方の為に、やすさんからいただいたバイナリとソースをUPしておきますね。やすさん、ありがとう!

配布
  1. PDFCreator0.9.8 (日本語対応exeファイル)
    PDFCreator_0516.zip
    (MD5 : 91ae1b27a964be1cfdbd111b286e445f)
  2. 参考 PDFCreator0.9.8(上記ソース)
    Version 0.9.8_090516.zip
    (MD5 : db8944afaa2e672b31d9f66a8a473060)
使い方
  1. 本家からPDFCreator0.9.8をDLしていただき、一旦インストールします。
  2. その後、PDFCreator.exeを上記1.の日本語版exeファイルと差し替えます。
動作環境の報告

当バイナリは、W2K(SP4)/XP(SP3)での動作が確認されています。

Vista(32bit SP2)環境では、"VB6JP.DLL"をインストールする必要があるようです(これはVisual Basic 6.0 SP6あたりのランタイムを入れれば入ると思われ…)。

Ω Ω Ω

以下は上記ソースにいたるまでの解説・経緯のまとめになります。本家でバージョンアップがされたときのために…。

メニュー画面の日本語化について。

  1. PDFCreatorの文字化けをなおす…必須
  2. PDFCreatorの文字化けをなおす2…小手先
  3. PDFCreatorの文字化け問題-修正箇所発見…Vb6.0でコンパイルできるヒト向け(これで完璧に)

PDF情報の日本語入力について(※すべて、VB6.0でコンパイルできるヒト向け)

  1. PDFCreatorの日本語問題-PDF情報編2
  2. PDFCreatorの日本語問題-PDF情報編…(2)EncodeCharsについての部分のみ利用してください

2.の記事にある「(1)ReplaceEncodingCharsについて」は不完全だということがわかりましたので、以下がやすさんの差し替えソースです。

[Common]-[modPDF.bas]

  1. Public Function ReplaceEncodingChars(Str1 As StringAs String  
  2. '---ErrPtnr-OnError-START--- DO NOT MODIFY ! ---  
  3. On Error GoTo ErrPtnr_OnError  
  4. '---ErrPtnr-OnError-END--- DO NOT MODIFY ! ---  
  5. 50010  Dim i As Integer, tStr As String  
  6. '---2009/05/16-START--- by yasu  
  7.        Dim bStr() As Byte  
  8.        Dim j, k As Integer  
  9. '---2009/05/16-End--- by yasu  
  10. 50020  tStr = ""  
  11. 50030  ' First we look for oct encoding chars  
  12. '---2009/05/16-START--- by yasu  
  13. '50040  For i = 127 To 255  
  14. '50050   Str1 = Replace$(Str1, "\" & Oct$(i), Chr$(i))  
  15. '50060  Next i  
  16. 50070  ReplaceEncodingChars = Str1  
  17.   
  18.         j = 0  
  19.         ReDim bStr(Len(Str1))  
  20.         For i = 1 To Len(Str1)  
  21.         Do  
  22.             If Mid$(Str1, i, 1) <> "\" Then  
  23.                 bStr(j) = AscB(Mid$(Str1, i, 1)): j = j + 1  
  24.             Else  
  25.                 If i <> Len(Str1) Then  
  26.                     If Mid$(Str1, i + 1, 1) Like "[\{}()]" Then  
  27.                         bStr(j) = AscB(Mid$(Str1, i + 1, 1)): j = j + 1: i = i + 1  
  28.                         Exit Do  
  29.                     End If  
  30.                 End If  
  31.                 If Len(Str1) - i > 3 Then  
  32.                     For k = 1 To 3  
  33.                         If Not Mid$(Mid$(Str1, i + 1, 3), k, 1) Like "[0-9]" Then  
  34.                             Exit For  
  35.                         End If  
  36.                     Next  
  37.                     If k = 4 Then  
  38.                         bStr(j) = CByte("&O" & Mid$(Str1, i + 1, 3)): j = j + 1: i = i + 3  
  39.                     Else  
  40.                         bStr(j) = AscB(Mid$(Str1, i, 1)): j = j + 1  
  41.                     End If  
  42.                 Else  
  43.                     bStr(j) = AscB(Mid$(Str1, i, 1)): j = j + 1  
  44.                 End If  
  45.             End If  
  46.         Loop Until 1  
  47.         Next  
  48.         tStr = StrConv(bStr, vbUnicode)  
  49. '---2009/05/16-End--- by yasu  
  50. 50080  ' Second we look for hex encoding chars  
  51. 50090  If Len(Str1) >= 4 Then  
  52. 50100   If Mid$(Str1, 1, 1) = "<" And Mid$(Str1, Len(Str1), 1) = ">" Then  
  53. 50110    If Len(Str1) Mod 2 = 0 Then  
  54. '---2009/05/16-START--- by yasu  
  55.           ReDim bStr((Len(Str1) - 2) / 2)  
  56. '---2009/05/16-END---  
  57. 50120     For i = 2 To Len(Str1) - 1 Step 2  
  58. 50130      If IsNumeric("&H" & Mid$(Str1, i, 2)) = True Then  
  59. 50140        If CByte("&H" & Mid$(Str1, i, 2)) > 255 Then  
  60. 50150          Exit Function  
  61. 50160         Else  
  62. '---2009/05/09-START--- by yasu  
  63.                bStr((i - 2) / 2) = CByte("&H" & Mid$(Str1, i, 2))  
  64. '50170          tStr = tStr & Chr$(CByte("&H" & Mid$(Str1, i, 2)))  
  65. '---2009/05/09-END--- by yasu  
  66. 50180        End If  
  67. 50190       Else  
  68. 50200        Exit Function  
  69. 50210      End If  
  70. 50220     Next i  
  71. '---2009/05/09-START--- by yasu  
  72.           tStr = StrConv(bStr, vbUnicode)  
  73. '---2009/05/09-END--- by yasu  
  74. 50230    End If  
  75. 50240   End If  
  76. 50250  End If  
  77. 50260  If Len(tStr) > 0 Then  
  78. 50270   ReplaceEncodingChars = tStr  
  79. 50280  End If  
  80. '---ErrPtnr-OnError-START--- DO NOT MODIFY ! ---  
  81. Exit Function  
  82. ErrPtnr_OnError:  
  83. Select Case ErrPtnr.OnError("modPDF""ReplaceEncodingChars")  
  84. Case 0: Resume  
  85. Case 1: Resume Next  
  86. Case 2: Exit Function  
  87. Case 3: End  
  88. End Select  
  89. '---ErrPtnr-OnError-END--- DO NOT MODIFY ! ---  
  90. End Function  

後半だけでなく、前半の8進変換もどきもバイト配列に一端いれてから日本語変換する必要があったようです。

前段の8進もどきで一体なにをやっているかといいますと…。

たとえば「\203R\203\201\203\223\203g\202\360\223\212\215e」を日本語にすると「コメントの投稿」となるわけですが。「\203R」の「\数値3桁」を16進数に変換、アルファベットをASCIIの16進数に変換すると「83 54」。これはS-JISでの「コ」…。以下略。──という具合に日本語に変換していかなくてはならないわけですよ。数値にアルファベットと入り交ざっているこいつらを一端16進数に戻して、S-JISに変換する、という流れ。

引数で受け取る値を見ても、一見「!?」という感じですし、暗号でも見ている気分でしたよ。やすさんスゴイ!!ヽ(´ー`)ノ

2009/05/18

PDFCreatorの日本語問題-PDF情報編2

やすさんのUPしてくださったソースと比較して、日本語(マルチバイトの文字列)が混ざると、PDFを[保存]できない原因がわかりました。

[保存]できない現象に対しての、修正箇所は

[Common]-[modCDlg.bas]-[SaveFileDialog]

もともとこのモジュールではOPENFILENAMEに対して下記のようにセットしていますが。

オリジナル

  1. 50160  With ofn  
  2. 50170   .nStructSize = Len(ofn)  
  3. 50180   .hWndOwner = hwnd  
  4. 50190   .sFilter = tFil  
  5. 50200   .nFilterIndex = FilterIndex  
  6. 50210   .sFile = InitFilename & Space$(1024) & vbNullChar & vbNullChar  
  7. 50220   .nMaxFile = Len(.sFile)  
  8. 50230   .sDefFileExt = DefaultFileExtension & vbNullChar & vbNullChar  
  9. 50240   .sFileTitle = vbNullChar & Space$(512) & vbNullChar & vbNullChar  
  10. 50250   .nMaxTitle = Len(ofn.sFileTitle)  
  11.   
  12. 50260   If InitDir = vbNullString Then  
  13. 50270     .sInitialDir = GetPDFCreatorApplicationPath & vbNullChar & vbNullChar  
  14. 50280    Else  
  15. 50290     .sInitialDir = InitDir & vbNullChar & vbNullChar  
  16. 50300   End If  
  17. 50310   .sDialogTitle = DialogTitle  
  18. 50320   .Flags = Flags  
  19. 50330  End With  

OPENFILENAME構造体は、


.nMaxFile   :ファイル名のバッファのサイズを設定

.nMaxFileTitle :フルパス用のバッファのサイズを設定


ですので、オリジナルのようにLenで計算している(行番号07.、10.)と、マルチバイトの文字列が入るとおかしくなっちゃうんですねー。

というわけで、下記のようにLenBにあらためます。

修正後

  1. 50160  With ofn  
  2. 50170   .nStructSize = Len(ofn)  
  3. 50180   .hWndOwner = hwnd  
  4. 50190   .sFilter = tFil  
  5. 50200   .nFilterIndex = FilterIndex  
  6. 50210   .sFile = InitFilename & Space$(1024) & vbNullChar & vbNullChar  
  7. '50220   .nMaxFile = Len(.sFile)  
  8. 50220   .nMaxFile = LenB(.sFile)    
  9. 50230   .sDefFileExt = DefaultFileExtension & vbNullChar & vbNullChar  
  10. 50240   .sFileTitle = vbNullChar & Space$(512) & vbNullChar & vbNullChar  
  11. '50250   .nMaxTitle = Len(ofn.sFileTitle)  
  12. 50250   .nMaxTitle = LenB(ofn.sFileTitle)  
  13.   
  14. 50260   If InitDir = vbNullString Then  
  15. 50270     .sInitialDir = GetPDFCreatorApplicationPath & vbNullChar & vbNullChar  
  16. 50280    Else  
  17. 50290     .sInitialDir = InitDir & vbNullChar & vbNullChar  
  18. 50300   End If  
  19. 50310   .sDialogTitle = DialogTitle  
  20. 50320   .Flags = Flags  
  21. 50330  End With  

この部分を修正すると無事、マルチバイトの文字列が入っていても、[保存]できるようになりますねぇ。

ちなみに[ReplaceEncodingChars]については、前回の16進変換の修正のみのモジュールのままでも、とりあえずのところは動きました(←そして8進変換の役割が、相変わらず、わかっていないじょにでした。[\XXX]の8進数を文字に置換しているのはわかっていても、「何故変換するのか。なにが入ってきて、どう変換すべきなのか」というそもそもの役割とかが見えきていないッス・泣)。

String型の連結-VBA編

今回は「VB6.0やVBAだとこういう書き方もアリなんだー」という、個人的には目から鱗ネタです。下記のソース、(1)と(2)、どちらが速いか?というわけですね。

(1)
  1. For i = 0 To lngMax  
  2.     strText1 = strText1 & "あいうえおかきくけこさしすせそ"  
  3. Next  
(2)
  1. For i = 0 To lngMax  
  2.     strText2 = strText2 & "あいうえおかきくけこさしすせそ"  
  3.     If Len(strText2) > 3000 Then strText1 = strText1 & strText2: strText2 = vbNullString  
  4. Next  
  5. If Len(strText2) Then strText1 = strText1 & strText2  

(1)の方が一般的な書き方だと思いますが、この場合、(2)の方が圧倒的に速いのです。

結果

(1):343 ミリ秒

(2):16 ミリ秒

※Acceess2003で実験

VB6.0のString型は値型なので文字列を追加する度に、データの文字列をコピーしているわけですね。コピーするものが、長ければ長いほど、コピーの作業にコストがかかる。

ひるがえって(2)ではstrText2にちまちま文字列を追加して、 If Len(strText2) > 3000 のタイミングでstrText1に突っ込んで、strText2をカラッポにしてまた文字列をためていく。その方が、長い文字列をコピーする回数が激減して、処理が速くなるというわけなんですね(ちなみに.Netだとstring型は一応参照型なので、文字列をセットする度にコンストラクタが発生している様子でVB6.0/VBAどころではない負荷を、もはや「体感」として感じます。なのでStringBuilderのインデクサで対応)。

サンプルソース

フォームにtxtDATAという名前のテキストボックスを作って、そこにタイムを表示する。clsTimerMMクラスは「時間経過計測クラス‐VBA編」参照。

  1. Dim clsTimerMM As clsTimerMM  
  2. Dim strTextMsg As String  
  3. '************************  
  4. Dim strMsg As String  
  5. Dim strText1 As String  
  6. Dim strText2 As String  
  7. Dim lngMax As Long  
  8. Dim i As Long  
  9. '************************  
  10. Set clsTimerMM = New clsTimerMM  
  11. strMsg = "あいうえおかきくけこさしすせそ"  
  12.   
  13. lngMax = 10000  
  14. '************************  
  15. clsTimerMM.SetStartDate  
  16. For i = 0 To lngMax  
  17.     strText1 = strText1 & strMsg  
  18. Next  
  19. strTextMsg = "(1):" & clsTimerMM.ElapsedTime & vbCrLf  
  20. Me.txtText1.Value = strText1 & vbCrLf  
  21. strText1 = vbNullString  
  22. '************************  
  23. clsTimerMM.SetStartDate  
  24. For i = 0 To lngMax  
  25.     strText2 = strText2 & strMsg  
  26.     If Len(strText2) > 3000 Then strText1 = strText1 & strText2: strText2 = vbNullString  
  27. Next  
  28. If Len(strText2) Then strText1 = strText1 & strText2  
  29. strTextMsg = strTextMsg & "(2):" & clsTimerMM.ElapsedTime & vbCrLf  
  30. Me.txtText2.Value = strText1 & vbCrLf  
  31.   
  32. Me.txtDATA.Value = strTextMsg  
  33. Set clsTimerMM = Nothing  

2009/05/15

情報セキュリティEXPO

情報セキュリティEXPO行ってきましたー。行った方も多いんじゃないでしょうかね。…かくいう私の親友も、すれ違いで昨日、出展者側で受付壌とかやっていた気配があったりするわけですが(笑)。

展示会をのぞくのは1年ぶり?くらいで、楽しかったです。以下ざっくりレポ。

資産管理と情報漏えい

情報漏えい対策ツール、色々なソフトが出回っていますけど。今や資産管理とかと連動しているんですね!──というのが、ちょっとしたオドロキでした。道理といえば道理ですけど、アタマいー。

棚卸作業はいまやUSBメモリまで!という感じで、USBメモリからの情報漏えいも多いわけだからそりゃそーだよね、と思いつつ、「ほへー!」という感じでした。

ちなみに情報システム部でもない私が、何故棚卸ジャンルを気にするかというと、部内のマシン各種・ライセンス管理を不本意ながらこの数年やっているからです。これが大変面倒くさい!(てゆーか、持ち回りにして!大変さや仕組みがわかれば、不届きモノも減るだろうから)

毎回、大捜索をしたり(勝手に返すな)、発見したりしながら(ちゃんと管理人に言ってよ!)、ヘトヘトの思いで足で稼いでいるわけです。存在するものだけでも予めリストになっていたら、どれだけラクなことか…。

そんなこんなの思惑もあって「こういうソフトがあれば少しはラクチンなんじゃないかなぁ」と未練タラタラで、ブースのヒトに根堀り葉掘り…。

でもよく考えると社内で既に導入済みLanScopeでもこのテの情報をとっているハズだよなー…。以前、工場で、未登録のUSBをマシンに刺したら、管理者がとんできたことがあったし。ということは、情報システムのヒトがウチの部に情報くれてないだけ or ウチの部の上司がそういうことを考えもつかずにスルーしているだけなのかも(でも情報システムのヒトにはLanScope情報から、ぜひとも棚卸リストに情報を反映させるところを作ってほしいわー…)。

ちなみにMacはこのテのソフトは対応していないものが多いみたいですね。「Macは仕様をなかなか公開したがらないから開発しづらいんですよ」みたいなコトを言ってました(ホント?)。

MacからLinuxまで、ぜーんぶまとめて一括管理できたら、ベンリなんですけどねー。

WAF

って、今日まで知りませんでした。そういうジャンルがあるんですね。(;´Д`)

ざっくりとしたプレゼンを聞いて、「機械的なSQLインジェクション攻撃とかにはある程度はこのテのソフトで対応する、というのは可能だろうしアリかもねー」とは思いました(やばそうな既存案件とか。いまさら改修もおっつなさそうな案件とかで)。

ちょっと興味がわいて、他にも類似ソフトがあるかと思って探してみたわけですが、最初の1社以外のものは見つけられませんでした。情報セキュリティの展示会なのに!…このジャンル、流行っているんですか?そうでもないんですか?そもそもまともに開発していれば、不要ですか?

トレンドマイクロ

なんの気なしに覗いて見たわけですが。プレゼンしていたヒト、玉木宏に似ていませんでしたか?!

完全別行動だったものの、同期も会場にいることは知っていたので、「ちょっと似ているんだけど!」とメールしたら、「見たいー!でもセミナー尽くしで抜け出せない」と返信がきました。わはは、みたいよね、やっぱり。

ちなみに肝心のプレゼン内容は、クラウド、クラウド言っていましたが、SaaSタイプのセキュリティソフトってところでしょうかね。パターンファイルとかで対応するアンチウイルスソフトだと、パターンが増えるにつれ、日々、負担も増えるし。SaaSとセキュリティソフトは相性がいいかもね。…ま、ネットがつなげないときは動かない、ってコトですが。ネットでつなげないとなると、メディア経由でのセキュリティに限定されてくるわけですからね。

yarai

パターンファイルに縛らないソフトはこれだ!

昨日、こんな記事を読んだばかりだったので、チラッと野次馬。…地味なブースでした(余計なお世話)。

▲ウイルスバスターだともう少し安く、しかも1ライセンスで3台に入れられるんだよなー…。

カスペルスキー

「おぉぉ、なんだかパッケージで見たコトあるカオだ!」と思ったら、ユージン・カスペルスキー氏が来日して講演していた!──というわけで、早速、潜り込み(ミーハーだから)。

ウイルスバスターから他のソフトに乗り換えようかなぁと、思っているわけですが。カスペルスキーもいいなぁ。…高いけど。

IPA

ついつい情報セキュリティEXPOに長居してしまいましたが、同時開催のソフトウェア開発環境展の方ものぞいてきました。しかしIPAがザクザク、ブース内でセミナーをやっているのが目に付いて、そこで足止め。IPA監修の「データ白書」ももらってきました。

「データ白書」の収集データは国内20社から収集したプロジェクト・データの実績。プロジェクトの特性(開発種別、業種、業務、アーキテクチャ、主言語など)、システム規模、工期、工数などの分布図なんかが載っています。グラフや散布図を眺めているだけでも、意外と面白いです。まー個人的にそんなに興味があるジャンルってわけではないんですが、否が応でもかかわってくる話ですし、「体感」としても理解できますからね。

「データ白書」をソフト化したものが「プロジェクト診断診断ツール」ってことになるようです(登録して、自分のプロジェクト実績を入れると、20社のデータをベンチマークに評価してくれるらしい)。

ちなみに、本日最後にゲットしたこの「データ白書」が結構重くて、色んなものを捨ててきました…。( ‥)

2009/05/14

Function対決-VBA編

うーん、これも道理といば道理。さらに言えばC#を書きはじめるまで、ファンクションの返り値にこういう条件式をつっこむ、という書き方はしなかったんですけれど(なぜならVBで書くと、なんでも「=」で不気味だから)。

わざわざif文で評価してから返すよりも、ダイレクトに評価してしまった方が、当然処理は速いですものネ。…ま、Functionの中身はかなり短いロジックにならざるをえませんので需要があるかどうかはビミョーですが。とりあえず、速度対決。

(1)

  1. Private Function IsTestTrue01(ByVal a As LongAs Boolean  
  2. If (a Mod 2 = 0) Then  
  3.     IsTestTrue01 = True  
  4. Else  
  5.     IsTestTrue01 = False  
  6. End If  
  7. End Function  

(2)

  1. Private Function IsTestTrue02(ByVal a As LongAs Boolean  
  2. IsTestTrue02 = (a Mod 2 = 0)  
  3. End Function  

結果

(1):1756 ミリ秒

(2):1588 ミリ秒

※Access2003で実験

サンプルソース

フォームにtxtDATAという名前のテキストボックスを作って、そこにタイムを表示する。clsTimerMMクラスは「時間経過計測クラス‐VBA編」参照。

  1. Dim clsTimerMM As clsTimerMM  
  2. Dim i As Long  
  3. Dim lngMax As Long  
  4. Dim strMsg As String  
  5.   
  6. Set clsTimerMM = New clsTimerMM  
  7. lngMax = 10000000  
  8.   
  9. '************************  
  10. clsTimerMM.SetStartDate  
  11. For i = 0 To lngMax  
  12.     Call IsTestTrue01(i)  
  13. Next  
  14. strMsg = "(1):" & clsTimerMM.ElapsedTime & vbCrLf  
  15. '************************  
  16. clsTimerMM.SetStartDate  
  17. For i = 0 To lngMax  
  18.     Call IsTestTrue02(i)  
  19. Next  
  20. strMsg = strMsg & "(2):" & clsTimerMM.ElapsedTime & vbCrLf  
  21.   
  22. '************************  
  23. Me.txtDATA.Value = strMsg  
  24. Set clsTimerMM = Nothing  

2009/05/12

And と Ifのネスト対決-VBA編

これはまぁ意外性はないんですけど、とりあえず測定だけはしておこうかと。

.Netだったら。VBではAndAlso、C#では&&とかが使えるんですけど、VBAでは使えませんものね。

というわけで、またの名を、And v.s AndAlso ってコトですかね?!これをVBAではAnd とIfのネスト構造で再現して対決します。

(1)If IsCheck(i) And IsCheck(i + 1) Then

(2)If IsCheck(i) Then if IsCheck(i + 1) Then

結果

(1):3436 ミリ秒
(2):2563 ミリ秒

※Access2003で実験

サンプルソース

フォームにtxtDATAという名前のテキストボックスを作って、そこにタイムを表示する。clsTimerMMクラスは「時間経過計測クラス‐VBA編」参照。

  1. Dim ClsTimerMM As ClsTimerMM  
  2. Dim strTextMsg As String  
  3. '************************  
  4. Dim lngMax As Long  
  5. Dim i As Long  
  6. '************************  
  7. Set ClsTimerMM = New ClsTimerMM  
  8. lngMax = 10000000  
  9.   
  10. '************************  
  11. ClsTimerMM.SetStartDate  
  12. For i = 0 To lngMax  
  13.     If IsCheck(i) And IsCheck(i + 1) Then  
  14.     End If  
  15. Next  
  16. strTextMsg = Left("If IsCheck(i) And IsCheck(i + 1) Then" & String(50, " "), 50) & ":" & ClsTimerMM.ElapsedTime & vbCrLf  
  17. '************************  
  18. ClsTimerMM.SetStartDate  
  19. For i = 0 To lngMax  
  20.     If IsCheck(i) Then  
  21.         If IsCheck(i + 1) Then  
  22.         End If  
  23.     End If  
  24. Next  
  25. strTextMsg = strTextMsg & Left("If IsCheck(i) Then If IsCheck(i + 1) Then" & String(50, " "), 50) & ":" & ClsTimerMM.ElapsedTime & vbCrLf  
  26. '************************  
  27.   
  28. Me.txtDATA.Value = strTextMsg  
  29. Set ClsTimerMM = Nothing  
  1. Private Function IsCheck(ByVal intChk As LongAs Boolean  
  2.  IsCheck = (intChk Mod 2 = 0)  
  3. End Function  

2009/05/11

空文字チェック対決-VBA編

VBAで空文字("")をチェックするときの速度1千万回対決。とりあえず、Nullは空文字ではないので除外。

結果

strData = "あいうえおかきくけこさしすせそ"
If strData = "" Then          :517 ミリ秒
If Len(strData) = 0 Then      :230 ミリ秒
If LenB(strData) = 0 Then     :234 ミリ秒

strData = "0123456789abcdefg"
If strData = "" Then          :516 ミリ秒
If Len(strData) = 0 Then      :270 ミリ秒
If LenB(strData) = 0 Then     :234 ミリ秒

※LenとLenBの速度差は、なんだか色々フクザツです。

strDataに「あいうえお」等が入っていると、Len/LenBの速度差の順位は、状況によってはひっくりかえったりしてマチマチ。「0123abcd」などの文字列のときは、何度やってもにLenBが早くなります。何故かはいまのところ不明。

サンプルソース

フォームにtxtDATAという名前のテキストボックスを作って、そこにタイムを表示する。clsTimerMMクラスは「時間経過計測クラス‐VBA編」参照。

  1. Dim ClsTimerMM As ClsTimerMM  
  2. Dim strTextMsg As String  
  3. '************************  
  4. Dim strData As String  
  5. Dim strGet As String  
  6. Dim lngMax As Long  
  7. Dim i As Long  
  8. '************************  
  9. Set ClsTimerMM = New ClsTimerMM  
  10. strData = "あいうえおかきくけこさしすせそ"  
  11. 'strData = "0123456789abcdefg"  
  12. strTextMsg = "strData:" & strData & vbCrLf  
  13. lngMax = 10000000  
  14. '************************  
  15. ClsTimerMM.SetStartDate  
  16. For i = 0 To lngMax  
  17.     If strData = "" Then  
  18.     End If  
  19. Next  
  20. strTextMsg = Left("If strData = """" Then" & String(30, " "), 30) & ":" & ClsTimerMM.ElapsedTime & vbCrLf  
  21. '************************  
  22. ClsTimerMM.SetStartDate  
  23. For i = 0 To lngMax  
  24.     If Len(strData) = 0 Then  
  25.     End If  
  26. Next  
  27. strTextMsg = strTextMsg & Left("If Len(strData) = 0 Then" & String(30, " "), 30) & ":" & ClsTimerMM.ElapsedTime & vbCrLf  
  28. '************************  
  29. ClsTimerMM.SetStartDate  
  30. For i = 0 To lngMax  
  31.     If LenB(strData) = 0 Then  
  32.     End If  
  33. Next  
  34. strTextMsg = strTextMsg & Left("If LenB(strData) = 0 Then" & String(30, " "), 30) & ":" & ClsTimerMM.ElapsedTime & vbCrLf  
  35. '************************  
  36. Me.txtDATA.Value = strTextMsg  
  37. Set ClsTimerMM = Nothing  

$マークつきの関数について-MidとMid$関数対決

今回、PDFCreatorのソースをみていて気になったのがやたらと出てくる$マーク。UCase$とかOct$とかChr$とかMid$とかがものすごーく気になっていたわけですよ。ググってもひっかかりにくいし、VB6.0のヘルプは手元にないし、でもどうやらフツーに$記号ナシのUcaseやらMidと同じ動作をする。

悶々と々としていたのですが、ちょっと別のコトを調べていたら、スゴい記述をみつけてしまいました。英文サイトのFaster Visual Basic Programs

マジでー?!

$マークつけた方が、処理早いの??? Σ(゚Д゚;≡;゚д゚)

Midの返り値はvariantなのに対して、Mid$の返り値はString型だから、という理由にはナットクしたものの、Mid$なんて隠し玉の存在を知りませんでした。$で文字列を返すというのは、Basicの名残っぽいですよね。

「….Netでも実験してみよー!」と一瞬、思ったものの、.Netに移行してから、Mid関数とかあんまり使わないかなぁ。(´・ω・`)

私の今の行動範囲で現実的にこの知識を生かせるのってむしろVBA?──というわけでAccess2003で実験してみました。


まずはMidとMid$対決の一千万回対決。

MID$の方がちょっと速いですね。

結果

MID :3277 ミリ秒

MID$:3011 ミリ秒

サンプルソース

フォームにtxtDATAという名前のテキストボックスを作って、そこにタイムを表示する。clsTimerMMクラスは「時間経過計測クラス‐VBA編」参照。

  1. Dim ClsTimerMM As ClsTimerMM  
  2. Dim strTextMsg As String  
  3. '************************  
  4. Dim strData As String  
  5. Dim strGet As String  
  6. Dim lngMax As Long  
  7. Dim i As Long  
  8. '************************  
  9. Set ClsTimerMM = New ClsTimerMM  
  10. strData = "あいうえおかきくけこさしすせそ"  
  11. lngMax = 10000000  
  12. '************************  
  13. ClsTimerMM.SetStartDate  
  14. For i = 0 To lngMax  
  15.     strGet = Mid(strData, "5", 1)  
  16. Next  
  17. strTextMsg = "MID :" & ClsTimerMM.ElapsedTime & vbCrLf  
  18. '************************  
  19. ClsTimerMM.SetStartDate  
  20. For i = 0 To lngMax  
  21.     strGet = Mid$(strData, "5", 1)  
  22. Next  
  23. strTextMsg = strTextMsg & "MID$:" & ClsTimerMM.ElapsedTime & vbCrLf  
  24. '************************  
  25.   
  26. Me.txtDATA.Value = strTextMsg  
  27. Set ClsTimerMM = Nothing  

参考

同類な関数

Chr ChrB CurDir Dir Format Hex Input InputB LCase Left LeftB Mid MidB Oct Right RightB RTrim Space Str String Trim UCase

時間経過計測クラス‐VBA編

いろいろAccessで測定してみたくなったので、まずは測定クラスの作成。

VBA単独はではミリ秒を測れないようなので、API関数を利用。

ClsTimerMM

  1. Option Compare Database  
  2. Option Explicit  
  3.   
  4. '============================  
  5. ' ミリ秒 で経過時間を計測  
  6. '============================  
  7.   
  8. Private Declare Function timeGetTime Lib "winmm.dll" () As Long  
  9. Public StartTime As Variant  
  10.   
  11. Public Sub SetStartDate()  
  12. StartTime = timeGetTime()  
  13. End Sub  
  14. Public Function ElapsedTime() As String  
  15. ElapsedTime = (timeGetTime() - StartTime) & " ミリ秒"  
  16. End Function  

そしてオマケで、hh時間nn分ss秒での計測バージョン。

ClsTimer

  1. Option Compare Database  
  2. Option Explicit  
  3. '============================  
  4. ' hh時間nn分ss秒 で経過時間を計測  
  5. '============================  
  6.   
  7. Private StartDate As Variant  
  8. Public Sub SetStartDate()  
  9. StartDate = Now  
  10. End Sub  
  11. Public Function ElapsedTime() As String  
  12. ElapsedTime = Format(Now - StartDate, "hh時間nn分ss秒")  
  13. End Function  

2009/05/10

PDFCreatorの日本語問題-PDF情報編

「PDFCreatorの文字化け問題-修正箇所発見」のやすさんのコメント欄からの記事になります。

PDFCreatorは家使いなのでそこまで使いきっている感じでもなく、これまで私は素通りしていましたが。PDFCreatorは印刷時のPDF情報を設定する際、日本語が混じっているとその部分はスルーする、という現象があるのですね。日本語を入れるとはじかれる、無視される…。

私の場合、家にはVB6.0環境がないので、とりあえず、やすさんのコメント欄とソースコードを頼りにロジックのみ考えてみました。

ちなみに問題のモジュールを含む本家オリジナルのソースはこちら

(1)ReplaceEncodingCharsについて

やすさんの修正案のコードの全貌。

  1. Public Function ReplaceEncodingChars(Str1 As StringAs String  
  2. '---ErrPtnr-OnError-START--- DO NOT MODIFY ! ---  
  3. On Error GoTo ErrPtnr_OnError  
  4. '---ErrPtnr-OnError-END--- DO NOT MODIFY ! ---  
  5. 50010  Dim i As Integer, tStr As String  
  6. 50011  Dim bStr() As Byte  
  7. 50020  tStr = ""  
  8. 50030  ' First we look for oct encoding chars  
  9. 50040  For i = 127 To 255  
  10. 50050   Str1 = Replace$(Str1, "\" & Oct$(i), Chr$(i))  
  11. 50060  Next i  
  12. 50070  ReplaceEncodingChars = Str1  
  13. 50080  ' Second we look for hex encoding chars  
  14. 50090  If Len(Str1) >= 4 Then  
  15. 50100   If Mid$(Str1, 1, 1) = "<" And Mid$(Str1, Len(Str1), 1) = ">" Then  
  16. 50110    If Len(Str1) Mod 2 = 0 Then  
  17. 50111     ReDim bStr((Len(Str1) - 2) / 2)  
  18. 50120     For i = 2 To Len(Str1) - 1 Step 2  
  19. 50130      If IsNumeric("&H" & Mid$(Str1, i, 2)) = True Then  
  20. 50140        If CByte("&H" & Mid$(Str1, i, 2)) > 255 Then  
  21. 50150          Exit Function  
  22. 50160         Else  
  23. '50170     tStr = tStr & Chr$(CByte("&H" & Mid$(Str1, i, 2)))  
  24. 50170          bStr((i - 2) / 2) = CByte("&H" & Mid$(Str1, i, 2))  
  25. 50180        End If  
  26. 50190       Else  
  27. 50200        Exit Function  
  28. 50210      End If  
  29. 50220     Next i  
  30. 50221     tStr = StrConv(bStr, vbUnicode)  
  31. 50230    End If  
  32. 50240   End If  
  33. 50250  End If  
  34. 50260  If Len(tStr) > 0 Then  
  35. 50270   ReplaceEncodingChars = tStr  
  36. 50280  End If  
  37. '---ErrPtnr-OnError-START--- DO NOT MODIFY ! ---  
  38. Exit Function  
  39. ErrPtnr_OnError:  
  40. '---ErrPtnr-OnError-END--- DO NOT MODIFY ! ---  
  41. End Function  

ReplaceEncodingCharsの役割としては、

  1. 引数には、バイナリの文字列が渡される。
     たとえば「<82E282B782B382F182B182F182CE82F182CD8142>」こんな文字列を引き渡される。
  2. 返り値としては、日本語の文字列を返せばOK。

という関数なわけですね?(コードから推測…)

だとすると、やすさんの修正案通り、バイトの配列を一端作る流れが妥当だと私も思います。

いまのところ、敢えて修正案を出すなら

  1. 50130      If IsNumeric("&H" & Mid$(Str1, i, 2)) = True Then  
  2. 50140        If CByte("&H" & Mid$(Str1, i, 2)) > 255 Then  
  3. 50150          Exit Function  
  4. 50160         Else  

あたりの分岐はコメントアウトしちゃっていいんじゃないの?と思ったくらいでしょうか。「なんかもー、どうせバイト変換できないときに抜けちゃうなら、エラー処理でいいんじゃないの?」と思うので…。

それにしてもオリジナルのコードは明らかにおかしいですよね。2桁ずつゲットして文字変換されても、マルチバイトな言語では明らかに困るだろう。(;´Д`)

(2)EncodeCharsについて

やすさんの修正案のコードの全貌。

  1. Public Function EncodeChars(ByVal CodePage As eCodePage, ByVal Str1 As StringAs String ' UTF-16, UTF-8 conversion  
  2. '---ErrPtnr-OnError-START--- DO NOT MODIFY ! ---  
  3. On Error GoTo ErrPtnr_OnError  
  4. '---ErrPtnr-OnError-END--- DO NOT MODIFY ! ---  
  5. 50010  Dim i As Long, tStr As String, Size As Long, buffer() As Byte, c As Long, tL As Long  
  6. 50020  
  7. 50030  If LenB(Str1) = 0 Then  
  8. 50040   Exit Function  
  9. 50050  End If  
  10. 50061  Select Case CodePage  
  11.         Case eCodePage.CP_NoEncoding  
  12. 50080    EncodeChars = "(" & Str1 & ")"  
  13. 50090   Case eCodePage.CP_UTF8  
  14. 50100    For i = 1 To Len(Str1)  
  15. 50110     c = AscW(Mid$(Str1, i, 1))  
  16. 50121     Select Case c  
  17.            Case 0 To &H7F&  
  18. 50140       tStr = tStr & String(2 - Len(Hex(c)), "0") & Hex(c)  
  19. 50150      Case &H80& To &H7FF&  
  20. 50160       tL = &HC0& Or ((c And &H3FC0&) \ &H40&)  
  21. 50170       tStr = tStr & String(2 - Len(Hex(tL)), "0") & Hex(tL)  
  22. 50180       tL = &H80& Or (c And &H3F&)  
  23. 50190       tStr = tStr & String(2 - Len(Hex(tL)), "0") & Hex(tL)  
  24. 50200      Case &H800& To &HFFFF&  
  25. 50210       tL = &HE0& Or ((c And &HF000&) \ &H1000&)  
  26. 50220       tStr = tStr & String(2 - Len(Hex(tL)), "0") & Hex(tL)  
  27. 50230       tL = &H80& Or ((c And &HFC0&) \ &H40&)  
  28. 50240       tStr = tStr & String(2 - Len(Hex(tL)), "0") & Hex(tL)  
  29. 50250       tL = &H80& Or (c And &H3F&)  
  30. 50260       tStr = tStr & String(2 - Len(Hex(tL)), "0") & Hex(tL)  
  31. 50270     End Select  
  32. 50280    Next i  
  33. 50290    EncodeChars = "<BFBBEF" & tStr & ">"  
  34. 50540   Case eCodePage.CP_UTF16  
  35. 50550    For i = 1 To Len(Str1)  
  36. 50560     c = AscW(Mid$(Str1, i, 1))  
  37. '50570     tStr = tStr & String(4 - Len(Hex(c)), "0") & Hex(c)  
  38. 50570     tStr = tStr & Right("0000" & Hex(c), 4)  
  39. 50580    Next i  
  40. 50590    EncodeChars = "<FEFF" & tStr & ">"  
  41. 50600  End Select  
  42. '---ErrPtnr-OnError-START--- DO NOT MODIFY ! ---  
  43. Exit Function  
  44. ErrPtnr_OnError:  
  45.   
  46. '---ErrPtnr-OnError-END--- DO NOT MODIFY ! ---  
  47. End Function  

引数でエンコーディング、及び文字列を渡して、引数で決めたエンコーディングの16進を返すファンクションですね(eCodePageはEnumで、CP_NoEncoding/CP_UTF8/CP_UTF16の三択です)。

AscWが負の値のとき(たとえば「髙」とか)、オリジナルのコードだとHex(c)に「FFFF9AD9」などアタマ4桁に余計なコードがついて16進数を返せなくなくなりますね。36行目を

50560 c = CLng("&H" & Hex(AscW(Mid$(Str1, i, 1))))

このように修正すれば、どうにか…、という感じですけど。

やすさんのRight関数を使っての4桁取得が妥当ですよね。エレガントだし、これはこれで完成っぽいですね。


やすさんへ

いろいろネタ的には初めて尽くしで、すごく勉強になりました!ありがとうございます。

(1)の方は、根本的にこれ以上のロジックが私のアタマで浮かぶか怪しいですが、しばらく考えてみます。

もともとどこかでbyteの配列をゲットしているチャンスがあるんだから、そのままどーにかならなかったの?とか思わなくもありませんが。そこまで手を広げていくと、収拾つかなくなっていきそうですよね…。

いやー、それにしてもこうしてみてみると、つくづくと面白いですね!(←だんだんノってきた) +。:.゚ヽ(*´∀`)ノ゚.:。+゚

ソースコードのハイライト-業務連絡

久しぶりにサンプルソースを書いていて、気になりだしたのがソースのハイライト・ツール。

これまでgoogle-code-prettifyを利用していたわけですが、VBのソースのハイライトが美しくないので以前から気になってはいたのですよ。

どれどれと思って本家をのぞいてみたら、だいぶバージョンアップされていました。「早速、使ってみよう」と思って、javascriptやcssのアップロード先として便利に使っていたGoogleのPageCreatorに行ってみたら…。

えーっ! Σ(゚Д゚;≡;゚д゚)

Google Page Creator is no longer accepting new sign-ups.

お前もか、ブルータス(←GoogleNotebook愛好家)。

PageCreatorの類似品としてgにはSiteができたもんねー。SiteはSiteで結構便利機能満載なんですが、プレーンなjavascriptとかのアップロードはできないんですねよね。…多分、コンテンツは作らないのに、データだけおいて、外から呼びだしている私みたいな輩がいるから?(´・ω・`)

というわけで現在ログインはできても、更新作業ができないPageCreator。立ち退きムード満載ですね。

他にゆくあてもないので、ソース類は諦めてガジェットに突っ込むことにしました。

そしてついでなので思い切ってSyntax Highlighterへ浮気することにしました。

なぜなら行番号を出すのも簡単で、「view plane」のモードまであって実に高機能だから。

でもちょっと、「ついで」にしては思い切りすぎだったかな。(ーoー)y~~~

言語ごとにclassをつけていくのが面倒くさかったよ。VB系にC#、ColdFusionにJavaFXにコマンド系。正直、どの言語を当てればOKなのかわからないものもちらほらあったりして、その点はprettyprintはテキトーすぎてラクチンでしたねぇ。

追記:<br />タグ問題

Syntax Highlighterを導入したら、私は今後もう使わないかも…なマクロのサンプルソース、「EmEditorのマクロ 選択範囲へ改行タグ」で、ダブルクオーテーションに囲まれた<br />がどーしても表示でず、改行されてしまった(リンク先、サンプルソースの23行目とか30行目)。

「google-code-prettifyのときはヘーキだったのにー?!!コードとしてのbrで、しかもタグは16進数も使っているのに改行されちまうのさー!?」とモヤモヤとしていたら。

本家のこの記事みてなんとなーくわかっちゃった。ウチの場合、改行キー等、全部タグは手打ち(私の場合エディタのマクロ…)なので、むしろdp.SyntaxHighlighter.BloggerMode();の1行は不要なのですよ。なので、この一文をコメントアウト。するとどうやらうまくいったような気がします。…それとも他で影響でるかな?(ΦωΦ) 

2009/05/08

PDFCreatorの文字化け問題-修正箇所発見

昨日に引き続き、ソースを見ていたらキャラセット問題は解決したので、「記事を書こうかなー」と思っていたところ、前回の記事のコメント欄で匿名さんからまさに同じ結論がくだされていて笑いました。本日私が修正したソースとあまりに同じ結果でしたので。…行番号まで(w)

匿名さんのおっしゃる通り、標準モジュール([Common])の[modGeneral2]-[SetFrame]を下記のように書き換えれば(13、14行目を追加すればOK。フォントサイズも変更したければ、匿名さんのコメントどおり、11行目を「50070 ctl.Font.Name = Options.ProgramFont」に変更)、日本語表示はどーにかなります。とゆーか、キャラセット問題は全面解決しそうな予感…。未確認ですが、現状だと欧文以外は多分全部文字化けしていると思うんですよね。

  1. Public Sub SetFrame(ByRef ctl As Control, Optional TempOptionsDesign = -1)  
  2. '---ErrPtnr-OnError-START--- DO NOT MODIFY ! ---  
  3. On Error GoTo ErrPtnr_OnError  
  4. '---ErrPtnr-OnError-END--- DO NOT MODIFY ! ---  
  5. 50010  Dim tOD As Long  
  6. 50020  If TempOptionsDesign > -1 Then  
  7. 50030    tOD = TempOptionsDesign  
  8. 50040   Else  
  9. 50050    tOD = Options.OptionsDesign  
  10. 50060  End If  
  11. 50070  ctl.Font.Size = 10  
  12. '-----------------// 追加ここから //------------------------  
  13. 50071  ctl.Font.Name = Options.ProgramFont  
  14. 50072  ctl.Font.Charset = Options.ProgramFontCharset  
  15. '-----------------//  ここまで  //------------------------  
  16. 50080  ctl.TextShaddowColor = &HC00000  
  17. 50090  If ComputerScreenResolution <= 8 Or tOD = 1 Then  
  18. 50100    ctl.UseGradient = False: ctl.Caption3D = [Flat Caption]  
  19. 50110    If UCase$(ctl.Name) = "DMFRADESCRIPTION" Then  
  20. 50120      ctl.BarColorFrom = vbRed  
  21. 50130     Else  
  22. 50140      ctl.BarColorFrom = vbBlue  
  23. 50150    End If  
  24. 50160   Else  
  25. 50170    ctl.UseGradient = True: ctl.Caption3D = [Raised Caption]  
  26. 50180    If UCase$(ctl.Name) = "DMFRADESCRIPTION" Then  
  27. 50190      ctl.BarColorFrom = &HB0BED  '&HA0A0FF ' &HFB&  
  28. 50200      ctl.BarColorTo = &H20564  '&HE0& ' &HDDFF&  
  29. 50210     Else  
  30. 50220      ctl.BarColorFrom = &HED0B0B '&HFFA0A0  
  31. 50230      ctl.BarColorTo = &H640502 '&H600000  
  32. 50240    End If  
  33. 50250  End If  
  34. '---ErrPtnr-OnError-START--- DO NOT MODIFY ! ---  
  35. Exit Sub  
  36. ErrPtnr_OnError:  
  37. Select Case ErrPtnr.OnError("modGeneral2""SetFrame")  
  38. Case 0: Resume  
  39. Case 1: Resume Next  
  40. Case 2: Exit Sub  
  41. Case 3: End  
  42. End Select  
  43. '---ErrPtnr-OnError-END--- DO NOT MODIFY ! ---  
  44. End Sub  

これをコンパイルして、exeファイルを上書きしたら、ちゃんと日本語表示されました(色々訳アリで、setup.exeを作ってないので、exeの上書き)。

SourceForge.netだとこの辺のソース


本家で直してもらわないと、バージョンアップの度にこの作業をしなくちゃならないのでフィードバックしたいなぁ、と思っているわけですが。なにせSourceForgeみたいなものを使ったことがないので(スタンドアローン、バッチ処理、ほぼ単独での開発が身の上)、参加の仕方がわからない。(;´Д`)

Trackerの辺りで発言するのが手っ取り早そうだけれども、気後れ状態…。あーでも頑張りますー(たぶんね)。

追記→5/9、Trackerで投稿してみました。

…これからどうなるんでしょう。ヽ(。_°)ノ?

2009/05/07

PDFCreatorの文字化け問題(研究)

あいかわらずぼちぼちPDFCreatorの文字化け関連にまつわる記事にはアクセスいただいているようなので、久しぶりに本家をのぞいてみました。すると0.9.8まで出ているのですね。早速アップデート。

…しかしやはり日本語は化けますね。

オープンソースなので、落としてソースをみてみたところ、なんだよVB6.0じゃんか…(.NetだったらExpressで家でも開けるのに!テキストエディタで見るのはシンドイわ…)。

VB6.0の[フォーム]のプロパティの「Font」の「...」をクリックすると出てくるあの画面デス。

ちょいちょいと見た限りでは、フォームのFontプロパティの文字セットが[欧文]のままになっていて、化け化けになるように見受けられますな(※図参照)。

なんとなーくどの辺のモジュールでセットしているのかは、分かってきたけれども時間切れ。…中途半端なネタですいません。しかしこれVB6.0でいまだに開発しているのですね。それもちょっとショック(まだver0.9ですけど。ver1.0までこのまま突っ走るのでしょうかね)。C#なら張り切るのに!!

2009/05/05

Streamクラスの計測

このところバイナリデータ あーんど C#いじりにハマりつつあるじょにです。

FileStreamクラスを使って、ぐるぐるバイナリ状態でファイルのI/Oをやっていて、体感として

「ファイルの読み込み・書き込みについてだけ考えたら、TextReaderクラスやTextWriterクラスよりもFileStreamを使った方が早いような気がする…」

と思ってちょっと調べてみると、StreamReader/StreamWriterクラスは、byteデータを扱うストリーム・オブジェクトクトをラップしているクラスでした。ああ、やっぱり。(;´Д`)

ということは、「FileStreamを使ってバイナリ状態のままデータを扱った方が、StreamReader/StreamWriterクラスを使うより、処理は早い(≒Text系のストリームでは、I/Oは指定した文字コードでの処理、内部処理はUnicodeのハズ。いちいち文字コードの変換をかけている分、コストがかかっているのではないか?)」──という推論の元に実験開始!

読み込み/書き出しのクラスをセットにして、それぞれ

  1. StreamReader/StreamWriterクラス
  2. FileStreamのReadByte/WriteByteメソッド
  3. FileStreamのRead/Writeメソッド
  4. System.IO.File.Copyメソッド

で計測してみました。

4.のCopyメソッドについては、当然、バイナリでコピーをやっていると思うので、その際の参考値。予測としては多分一番早い。

コピー元の実験材料は郵便局の郵便番号データをちょちょいと加工して1行を1002バイト(改行キー含むバイト数)、1ファイル全体で117MBくらいになったものです。で、FileStreamのReadクラスやWriteクラスのMaxのバッファは1002にしたので、StreamReader/StreamWriterクラスとI/Oの回数は同一のハズ。メモリの空き容量で差がでてこないように、直前でGC.Colloect();いれてマス。


結果は

  1. 08.5791859
  2. 11.1155169
  3. 05.7603782
  4. 03.8566569

という具合でした。2.の11秒はさすがに1バイトずつだとI/Oが多くてあまりよい数字はでてこない、ということになりますが。でもまぁI/Oの回数が多いわりには、意外ととStreamReader/StreamWriterクラスに迫っていますよね。最も外付けHDDやネットワーク越しに作業をしたり、ファイルサイズがも巨大であればあるほど、I/Oの問題はもっと顕著になってくるわけですけれどね。


ちなみに実験ソースはこんな感じ。

実験環境はVC#2008Express版(.Net Framework3.5)。

_InFilePath/_OutFilePathは実験クラスのメンバー変数です。

StreamReader/StreamWriterクラスの計測

  1. //------------------------  
  2. Stopwatch sw = new Stopwatch();  
  3. sw.Reset();  
  4. sw.Start();  
  5. //------------------------  
  6. using (StreamReader _SReder = new StreamReader(_InFilePath, Encoding.GetEncoding(932)))  
  7. using (StreamWriter _SWriter = new StreamWriter(_OutFilePath, true, Encoding.GetEncoding(932)))  
  8. {  
  9.     while (_SReder.Peek() != -1)  
  10.     {  
  11.         _SWriter.WriteLine(_SReder.ReadLine());  
  12.     }  
  13. }  
  14. //------------------------  
  15. sw.Stop();  
  16. MessageBox.Show(sw.Elapsed.ToString());  
  17. //------------------------  

FileStreamのReadByte/WriteByteメソッドの計測

  1. //------------------------  
  2. Stopwatch sw = new Stopwatch();  
  3. sw.Reset();  
  4. sw.Start();  
  5. //------------------------  
  6. using (FileStream _FReder = new FileStream(_InFilePath, FileMode.Open, FileAccess.Read))  
  7. using (FileStream _FWriter = new FileStream(_OutFilePath, FileMode.Create, FileAccess.Write))  
  8. {  
  9.     int _ReadByte = 0;  
  10.     while (_ReadByte != -1)  
  11.     {  
  12.         _ReadByte = _FReder.ReadByte();  
  13.         _FWriter.WriteByte((byte)_ReadByte);  
  14.     }  
  15. }  
  16. //------------------------  
  17. sw.Stop();  
  18. MessageBox.Show(sw.Elapsed.ToString());  
  19. //------------------------  

FileStreamのRead/Writeメソッドの計測

  1. //------------------------  
  2. int _BufferSize = 1002;  
  3. //------------------------  
  4. Stopwatch sw = new Stopwatch();  
  5. sw.Reset();  
  6. sw.Start();  
  7. //------------------------  
  8. using (FileStream _FReder = new FileStream(_InFilePath, FileMode.Open, FileAccess.Read))  
  9. using (FileStream _FWriter = new FileStream(_OutFilePath, FileMode.Create, FileAccess.Write))  
  10. {  
  11.     byte[] _ReadBuffer = new byte[_BufferSize];  
  12.     int _ReadSize = _BufferSize;  
  13.     while (_ReadSize != 0)  
  14.     {  
  15.         _ReadSize = _FReder.Read(_ReadBuffer, 0, _BufferSize);  
  16.         _FWriter.Write(_ReadBuffer, 0, _ReadSize);  
  17.     }  
  18. }  
  19. //------------------------  
  20. sw.Stop();  
  21. MessageBox.Show(sw.Elapsed.ToString());  
  22. //------------------------  

2009/05/02

VB 10 でアンダースコアが不要に?

VBからC#へ移行しつつある今日この頃のじょにですが、先日、VBネタで気になるネタを拾いました。

VB 10 でアンダースコアが不要に InfoQ


なにーー? Σ(゚Д゚;≡;゚д゚)

VBなのにアンダースコアがなくなる?(そんなのVBじゃねー!)Implicit Lineだとー?それって可能?アリ?

C#等の言語では明示的に「;」で終端を表現しているからよいでしょう。

しかしVBの基本は行末=終端なのです。VBの中では「行継続」というのはある意味、イレギュラーなのです。ゆえにVBでは改行してもなお「継続」する場合には、アンダースコアの表現が不可欠──他言語からのヒトからは、アンダースコアは不評で、"面倒臭い”だの"煩雑"などと云われもしましたが、VB育ちの私にとっては自然な感覚でした(慣れればどうということもない)。

それなのに、暗黙の行継続?衝撃というか革命的というか…。成立しない構文もでてくるだろうに、そこまでコンパイラに解釈してもらうのはちょっと気色が悪いというか…。

リンク先の記事にもありますが、withの中でのピリオドとか、「どー解釈すればいいのかわからない!」とい表現もでてきちゃいますものね。かえってルールが煩雑になりはしませんか。

VBチームのオリジナルの記事、「Implicit Line Continuation in VB 10」を読むとThings are always changing.とかいって、歴史博物館やらマシンに託けてVBのコンパイラも…、なーんておっしゃっていますけど。言語仕様には興味をそそられているところもありますよ?でも、ユーザー的心境としては、ヒトコト。──大丈夫なのか…。(-_-;)

2009/05/01

DCP-535CN

DCP-535CNが我が家にやってきました。

"重さ8.0Kg"──となかなか重そうなので、どんなに大きいコがやってくるのだろうと多少不安に思っていたのですが、思ったよりもちんまりしたコでした。

一人で持てる程度の重さで、家庭用はこうでなくちゃ!というところですね(まぁ8kgというと10kgの米袋より軽いですからね…)。

「家庭内で共有してプリンターを使おう」というのが今回のテーマで、結局現時点のネットワーク構成としてはこんなふうになりました(図参照)。

プリンタについては「無線でつなげるようにしよう」というコトがまずアタマにありました。ちょっと調べてみると、どうやら「プリンタサーバ(14,000円くらいする)+プリンター」の構成で買うよりも、無線機能つきのプリンタを購入した方が安上がりになるので、「無線機能つきのインクジェット複合機」というテーマで物色。

家庭用なのでA4で十分──ということでキヤノンのPIXUS MP620とブラザーのDCP-535CNとの間で迷いました。価格にすると数千円の違いでしかないので、購入基準は家での使い方の想定やラニングコスト等のプライオリティの持ち方ですよね。

ざっくりスペックを対比するとこんな感じ(物量面ばかり拾っていますが、家庭用ではサイズ重要!)。ちょっと表現の仕方がメーカーによって違うのでなんですが、あしからず。

項目DCP-535CNPIXUS MP620
質量
(カートリッジ込み)
約8.0kg約8.6kg
外形寸法(mm)390×375×180450×368×176
メモリ容量40MB-
インターフェイス有線LAN(10/100BASE-TX)
無線LAN(IEEE802.11b/g/AOSS/WPS)
Hi-Speed USB
有線LAN(10/100BASE-TX)
無線LAN(IEEE802.11b/g)
Hi-Speed USB
Bluetooth v2.0
プリント速度カラー:最高27枚/分
モノクロ:最高33枚/分
約31秒
A4普通紙(カラー)
インクコスト
約7.9円/枚約8.4円/枚

正直言って、大差はないです(だから迷う)。なので初期投資のかからないDCP-535CN。Linux系のドライバなんかもそこそこ揃っているので、ワタクシ的には合格点です。

ネットワークの参加
「無線、無線」と連呼していたわりに、結果的にはプリンタと親機とを有線でつないでしまいました。親機なんてものは小さいものですから、親機とプリンターをLANで接続することについて、部屋のレイアウト的な制約が実のところなにも問題なかったわけですね。…というわけで、複合機のネットワーク参加は実にカンタン、物理的にルータとLANケーブルでつないで、おのおののPCにプリンタのソフトを入れるだけ。"プリンタなので、IPは固定にしておいたほうがいいかなぁ?"と思って、DCP-535CNのMACアドレスを調べて(ネットワーク設定を印刷する機能があるのでそれで出力)、AirStationの管理画面でIPを固定にしたくらいです。
印刷スピード
印刷スピードは恐れてほど、遅くはありませんでした。年賀状等はやってみないと、わかりませんが、普段、地図なんかをペラッと出す分にはノープロブレム。
印刷物について
可も不可もなく、実にフツーです(※もともと写真を印刷しようとかいう気もなく、文書を印刷できれば十分、という価値観ですので、あしからず)。黒はにじみにくい顔料インクで、カラーは発色のよい染料インクになっているあたりは、キヤノンと似ていますね。
インクカートリッジについて
もともと純正品しか使う気がないので(←色々つらい目にあった…)、ヨドバシ等の大型店で買うよりもネットで買った方が安いので、「キヤノンよりマイナーだから入手しづらい」というようなことは特にネックにはなっていません。

VirtualBoxの共有フォルダ機能

VBOXでゲストOSの起動のタイミングで自動的にホストOSとの共有フォルダをマウントする方法です。

ちなみに私の場合、Ubuntu(ゲストOS)の[home/ユーザー名/共有フォルダ]にマウントしています。あしからず。

  1. ホストOSのWinの任意の場所に共有フォルダを作成([D:\VBOXShare]など)。
  2. ゲストOSのUbutnuに任意の共有フォルダを作成([home/ユーザ名/hostShare]など)
  3. VBOXの[デバイス]-[GuestAdditonsのインストール]
  4. VBOXの[デバイス]-[共有フォルダ]-[共有フォルダ]を選択し、右側の「+」をクリック。
  5. [永続化する]にチェックを入れ、フォルダのパス欄で[その他]を選択肢、ホストで作成した1.のディレクトリを設定し[OK]。
  6. [ALT]+[F2]を押しながら[etc/rc.local]をクリック。
  7. [実行]のボックスに[gksudo gedit /etc/rc.local]と入力して[実行]。
  8. 管理者パスワードを入力。
  9. [exit0]の前の行に[mount -t vboxsf ホストOSの共有フォルダ名 ゲストOSの共有パス]
  10. [mount -t vboxsf VBOXShare home/ユーザ名/hostShare]を書き加える。
  11. [保存]-[閉じる]

実行環境

  • VBOX2.2
  • ホストOS:WinXPpro
  • ゲストOS:Ubuntu8.04(GNOMEで利用中…)