2009/11/30

C#MacOS9混在だとGetFilesが落ちる

このエントリーをはてなブックマークに追加
MacOS9とWindowsの混在環境における現象です。
もうこんな環境はほとんどないかもしれませんけれどね。

MacOSはファイルに対しての情報を保持するために、同じ階層のフォルダ内に隠しファイルをいくつか生成します。Macでのオペレーションの上ではそれらのファイルは見えないようになっているのですが、Windowsからアクセスすると、思い当たらないファイルやフォルダが隠しファイルとして山のように出現しているのです。

そのフォルダに対してSystem.IO.Directory.GetFilesでファイルを列挙しようとすると、例外エラーを吐いて落ちる。
原因は、その隠しファイルの一つである「Icon」という名前のファイルにあります。実はこのファイルは、「Icon\r」という名前で、Windows上ではありえないファイル名となっているのです。

ですが、Windowsのエクスプローラ上でそのファイルが見えるということは、直接APIを呼んであげれば一応取得できるということを示しています。
↓こういうの


[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public class FindData {
public const int INVALID_HANDLE_VALUE = -1;
public int fileAttributes = 0;
public int creationTime_lowDateTime = 0;
public int creationTime_highDateTime = 0;
public int lastAccessTime_lowDateTime = 0;
public int lastAccessTime_highDateTime = 0;
public int lastWriteTime_lowDateTime = 0;
public int lastWriteTime_highDateTime = 0;
public int nFileSizeHigh = 0;
public int nFileSizeLow = 0;
public int dwReserved0 = 0;
public int dwReserved1 = 0;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public String fileName = null;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
public String alternateFileName = null;
}

[DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr FindFirstFile(String fileName, [In, Out] FindData findFileData);

[DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
public static extern int FindNextFile(IntPtr handle, [In, Out] FindData findFileData);

Windowsから、例えばNASのファイルを一括にバックアップを取ろうとすると、きっと上記のことが原因で失敗しまうのではないかと思われます。

他にMacOS混在環境にてトラップになりそうなファイル名。


  • 末尾に半角スペースが入っている

  • MacOSでは、日本語の漢字変換するためにはスペースを押して変換候補を探します。全角入力だと問題ないのですが、英数入力していてても習慣的に変換キーとなるスペースキーを打ってしまうことがあって、その状態のままファイル名を決定してしまうと、末尾に半角スペースが入ったファイル名ができあがります。これがWindows上では操作不能なファイルとなる。半角スペースだけに、オペレータも気づきにくい。

  • 半角スラッシュが入っている

  • 半角アスタリスクなども同様。
    MacOS上では、普通に使われてしまいますのでタチが悪いです。もとい。タチが悪いのはWindowsのほうというべきかもしれません。
    全角を使うようにしましょう。
    Windowsで見ると、「_U78ID~Y」とか「_9LPCK~0」という風に表示され、ファイル名が正常に取得できません。
    半角円マークの場合は、文字コードが違うのか、何故か許容するようです。

  • 拡張子のドットの代わりに半角カンマを入れている

  • Macユーザーには長らく拡張子の習慣がなかったので、十年ほど前の時代のファイルにはありがちです。

2009/11/26

GridViewにテンプレート列を動的に生成する

このエントリーをはてなブックマークに追加
これは備忘録です。
GridViewの列に、好きなコントロールを配置させたいときはTemplateFieldを使います。
デザイナ画面の「テンプレートの編集」を使うことで、コードなんて書かなくても何かと編集できるようになっています。
デザイナ画面でテンプレート列の追加をしたくない場合、コードだけでなんとかやりくりしたい場合について書きます。

デザイナ画面でテンプレート列の追加をしたくない場合


デザイナ画面でテンプレート列の追加をしたくない場合は、ITemplateを継承したクラスを作成し、InstantiateInメソッドを実装します。
InstantiateInは引数にControlを持っていて、必要なコントロールを追加することができます。

// ITemplateを継承したCustomTemplateクラス
public class CustomTemplate : ITemplate {

#region ITemplate メンバ
    public void InstantiateIn(Control container) {
    // ボタンとテキストを追加
        container.Controls.Add(new Button());
        container.Controls.Add(new TextBox());
    }
#endregion

}

public partial class _Default : System.Web.UI.Page {
    protected void Page_Load(object sender, EventArgs e) {
        if (!this.IsCallback) {
            // GridViewにテンプレート列を追加する。
            TemplateField template = new TemplateField();
            template.ItemTemplate = new CustomTemplate();
            this.GridView1.Columns.Add(template);

            // GridViewにデータを追加する
            string[] list = { "Sunday", "Monday", "Tuesday" };
            this.GridView1.DataSource = list;
            this.GridView1.DataBind();
        }
    }

    protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e) {
        if (e.Row.RowType == DataControlRowType.DataRow) {
            Button button = (Button)e.Row.Cells[0].Controls[0];
            button.Text = e.Row.DataItem.ToString(); // ボタンの表示名を変更
        }
    }
}

できあがり。
Item列は、GridViewにAutoGenerateColumnsがTrueになっているためです。あまりにも意味のないサンプルですみません。


「動的に」とか言ってるわりにテンプレート列の位置は固定しないといけません。テンプレート内のコントローラの値を引っ張り出すのに、列のインデックスを指定しないといけないからです。固定しないでもよい方法(簡単かつ軽快な方法)、知ってる人教えていただきたいです。

参考
http://msdn.microsoft.com/ja-jp/library/system.web.ui.itemplate(VS.80).aspx

2009/11/18

iPodTouch好きになってきた

このエントリーをはてなブックマークに追加
見事にやられてる。
家で、ごろごろするときに使ってただけだけど、持ち歩きたくなってきた。

当初は、さわり心地、UIとしてのインスピレーションを頂きつつ、ハード的な限界をいろいろと模索していて弄(いじ)ったり弄(もてあそ)んだりしてました。

それからゲームやユーティリティーを探しだす。主に無料ゲームばっかりで、どんなに安価でも有料にはいまいち手を出す気になりません。というのも、やはり、基本ベースが暇つぶしを目的とされているような印象があるからですね。インスピレーションもらうのにも、後ろ向きに見える用途では腰が重たい。
あちこちのアプリサイトに紹介されている優良の無料アプリも、見ると、有料になっていたりするわけで、「無料だからまあいいや」みたいな文句に導かれているという心境もあって、気持ちを挫かれてる感じです。

しかし、iPodTouchを基点として何かを始められる思うと、楽しくなってくるわけです。

  • PodCastとか見ていると、英会話レッスンが沢山あります。「英会話なんて勉強できたら、まあ便利」くらいの興味でも、ライフスタイルに導入するための敷居が低いので、すぐに、これなら出来そうだと思わせるに至る。

  • ぐるナビのように、食べ物屋を探すのに便利なアプリとか、ちょっと時間が空いたときに確認するニュースとか。

  • わざわざ、こいつで音楽聞くことはないだろうな、と思っていたけれど、そんなことはなかった。ナチュラルな音質が自分の聞く曲にあってるのか、バイオリンとかピアノとか聴くのには使えるやつだという評価になってきている。Zen X-Fiで音楽を聴いていたのでそれとの比較ですけどね。

  • がっつり系のゲームであれば有料いいように思ってきた。暇つぶしではなくて、ゲーム自体を目的とするような、そんなのです。三国志とか。あとぜひCivがほしい(英語はあるみたいだけど)。


持ち歩くと、やっぱり通信がほしくなるんでしょうね。
電池の持ちは、無線を切るのが効果的でした。通信するとしても、受信時だけ設定するくらいのがいいんだろうなあ。

2009/11/10

javascript innerHTML/innerTextを高速化したい

このエントリーをはてなブックマークに追加
documentに対して何らかの操作をすると、それがすぐ画面に反映されるという利点があってとても楽しいんですが、しかし反面アクセスが多くなるとすぐにボトルネックになります。

innerHTMLはめちゃくちゃ汎用的なのですが、文字をちょこっと表示/変更したいだけのようなときには仕様が大げさすぎることもあって、そういうときはinnerTextを使います。
しかしinnerTextよりもTextNodeを直接いじるほうが高速なのではと思って、計測してみた。

●コード

// ①innerHTMLを使う
var func1 = (function(){
var element = document.getElementById("id1");
return function(str){
element.innerHTML = str;
};
})();

// ②innerTextを使う
var func2 = (function(){
var element = document.getElementById("id2");
return function(str){
element.innerText = str;
};
})();

// ③TextNodeのnodeValueを更新する
var func3 = (function(){
var element = document.getElementById("id3");
var textNode = document.createTextNode(count);
element.appendChild(textNode);
return function(str){
textNode.nodeValue = str;
};
})();

●測定
測定方法は、ブラウザごとに上記の関数をそれぞれ、一秒間に何回呼べるかを計測した。

・IE8
① 9388回
② 32648回
③ 59668回

・firefox3
① 18431回
③ 74487回

※innerTextはfirefoxでは使用できないので飛ばします。

・GoogleChrome
① 222675回
② 608540回
③ 642903回

ただし、文字数や処理内容に影響すると思う。どんなときも一秒間にこんなに呼べるとは思えません。
今回はコンテンツ自体もすかすかで、カウンタとなる数値を代入していっただけなので早いのでしょう。

●まとめ
TextNodeのnodeValueを更新したほうが高速。

お決まりの文句ですが、大体の場合、高速化についてはアルゴリズムを見直すのがよいです。
でももっと言うと、クライアントの環境によって処理内容や速度が変わってしまったりするようなものに、速度を求めるのが間違っている気がします。でもこれはほとんど愚痴。