C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[7]: ファイル名のソート方法について


(過去ログ 91 を表示中)

[トピック内 12 記事 (1 - 12 表示)]  << 0 >>

■54584 / inTopicNo.1)  ファイル名のソート方法について
  
□投稿者/ ペンネ (1回)-(2010/10/27(Wed) 09:45:49)

分類:[VB.NET/VB2005 以降] 

VB 2008を使用しています。
指定したフォルダ内のファイル一覧を、System.IO.Directory.GetFilesで取得、
これをファイル名でソートしたいと思います。
しかしながら、たとえば、

2010-1.txt
2010-5.txt
2010-10.txt

というファイルが対象フォルダ内にある場合、ファイル名の文字列でソートすると、

2010-1.txt
2010-10.txt
2010-5.txt

という順にソートされますが、エクスプローラーの詳細表示だと、

2010-1.txt
2010-5.txt
2010-10.txt

というように、枝番(ハイフン以降の文字)の数値でもソートされます。
このように、エクスプローラのソート順と同じようなソートを行いたいのですが、
VB.netでそのようなライブラリはありますでしょうか?
なお、0000-0形式のファイル名だけであるならば本番と枝番に分割してソートを考えればよいとは思いますが、
ファイル名の規則は上記の通りとは限らないので、エクスプローラーのファイル名ソートを忠実に再現したいのです。
よろしくお願いします。
引用返信 編集キー/
■54585 / inTopicNo.2)  Re[1]: ファイル名のソート方法について
□投稿者/ ごう (193回)-(2010/10/27(Wed) 10:10:23)
No54584 (ペンネ さん) に返信
> エクスプローラーの詳細表示だと、
>
> 2010-1.txt
> 2010-5.txt
> 2010-10.txt

ファイルの更新日時はどうなっていますか?
おそらく、ファイルの更新日時を元にしてソートしているから
エクスプローラで見た並び順が上記のとおりになっているんではないでしょうか。

これを再現したいのであれば、(更新日時で並べたいのであれば)
ファイルの更新日時という情報を取得し、それを元にソートすればいいと思います。
「更新日時の並びは必ずしもファイル名の年月の並びと一致しない、あくまでファイル名の年月の並び順で並べたい」というのであれば、ファイル名を文字列で取得し、ハイフンでSplitしてint型変数またはDateTime型変数に入れてソートする・・・などといった方法でどうでしょう。
引用返信 編集キー/
■54586 / inTopicNo.3)  Re[2]: ファイル名のソート方法について
□投稿者/ 774RR (550回)-(2010/10/27(Wed) 10:20:26)
ファイル名の 「ロジカルソート」 という奴っすね。
API の StrCmpLogicalW で出来るっす。
http://msdn.microsoft.com/en-us/library/bb759947(VS.85).aspx

こいつの locale の指定がどうなっているのか微妙に不明。
どっとねっと系からどう呼べばよいのかはまったく知らないので誰か詳しい人にパス。
引用返信 編集キー/
■54588 / inTopicNo.4)  Re[3]: ファイル名のソート方法について
□投稿者/ ペンネ (2回)-(2010/10/27(Wed) 10:50:29)
ロジカルソートという名称は分かりませんが、おそらくご提示のms英語サイトのような、
数値部分を考慮したソートです。
(確か、XPの時にこのようなソートがデフォルトになっていて戸惑ったことがありました。)
これをどのように利用すればいいか、アドバイスをお願いします。
引用返信 編集キー/
■54589 / inTopicNo.5)  Re[3]: ファイル名のソート方法について
□投稿者/ Algol (1回)-(2010/10/27(Wed) 10:52:01)
No54586 (774RR さん) に返信
> ファイル名の 「ロジカルソート」 という奴っすね。
> API の StrCmpLogicalW で出来るっす。
> http://msdn.microsoft.com/en-us/library/bb759947(VS.85).aspx
> 
> こいつの locale の指定がどうなっているのか微妙に不明。
> どっとねっと系からどう呼べばよいのかはまったく知らないので誰か詳しい人にパス。

私はこんな感じで書いてます。

    // ソート方法

    string[] filenames = new string[] {"2010-1.txt","2010-10.txt","2010-5.txt" };
    Array.Sort(filenames, new FileNameComparer());

  // 以下クラス 

    public class FileNameComparer : IComparer<string>
    {

        public FileNameComparer() 
            : this(false)
        { }

        public FileNameComparer(bool descending)
        {
            if (descending) modifier = -1;
        }

        private readonly int modifier = 1;

        public int Compare(string x, string y)
        {
            return SafeNativeMethods.StrCmpLogicalW(x ?? "", y ?? "") * modifier;
        }

        [SuppressUnmanagedCodeSecurity]
        internal static class SafeNativeMethods
        {
            [DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
            public static extern int StrCmpLogicalW(string psz1, string psz2);
        }

    } 

引用返信 編集キー/
■54590 / inTopicNo.6)  Re[4]: ファイル名のソート方法について
□投稿者/ ペンネ (3回)-(2010/10/27(Wed) 10:58:21)
Algolさん、サンプルありがとうございます。
これを参考にVBに変換して試してみます。
ありがとうございました。
解決済み
引用返信 編集キー/
■54591 / inTopicNo.7)  Re[5]: ファイル名のソート方法について
□投稿者/ 774RR (551回)-(2010/10/27(Wed) 11:09:49)
これ (StrCmpLogicalW) でよい(期待通り)であるなら話は終了なんだけど

explorer のソート順はレジストリで変更できて、例えば
http://www.atmarkit.co.jp/fwin2k/win2ktips/342xpsort/xpsort.html

ということで、ユーザーが [エクスプローラ] の表示順を変更していればそれに従うとか
Win2000 で当該プログラムを動かしたいとか (StrCmpLogicalW は XP 以後のみ)
そういう要望があれば仕様レベルで再検討が必要かもしれないぞ、っと。
# 解決済みは維持しておこう
解決済み
引用返信 編集キー/
■54593 / inTopicNo.8)  Re[5]: ファイル名のソート方法について
□投稿者/ 魔界の仮面弁士 (1894回)-(2010/10/27(Wed) 11:17:55)
No54590 (ペンネ さん) に返信
> これを参考にVBに変換して試してみます。

変換例。

Imports System.IO
Module Module1

    Private Declare Unicode Function StrCmpLogicalW Lib "SHLWAPI" _
        (ByVal psz1 As String, ByVal psz2 As String) As Integer

    Sub Main()
        Dim dirName As String = "C:\A\B\"

        '取得 & ソート
        Dim q = Directory.GetFiles(dirName).ToList()
        q.Sort(Function(x, y) StrCmpLogicalW(x, y))

        '結果確認
        q.ForEach(AddressOf Console.WriteLine)
    End Sub
End Module

解決済み
引用返信 編集キー/
■54594 / inTopicNo.9)  Re[5]: ファイル名のソート方法について
□投稿者/ Algol (2回)-(2010/10/27(Wed) 11:29:53)
No54590 (ペンネ さん) に返信
> Algolさん、サンプルありがとうございます。
> これを参考にVBに変換して試してみます。
> ありがとうございました。

あっ… VB でしたか(汗
お詫びにVB(2005 2008で確認)へマイグレーションしてみました。

' 使い方
 Dim filenames As String() = New String() {"2010-1.txt", "2010-10.txt", "2010-5.txt"}
 Array.Sort(filenames, New FileNameComparer())


' クラス

Imports System.Collections.Generic
Imports System.Security
Imports System.Runtime.InteropServices

Public Class FileNameComparer
    Implements IComparer(Of String)

    Public Sub New()
        Me.New(False)
    End Sub

    Public Sub New(ByVal descending As Boolean)
        If (descending) Then Me.modifier = -1
    End Sub

    Private ReadOnly modifier = 1

    Public Function Compare(ByVal x As String, ByVal y As String) As Integer _
        Implements IComparer(Of String).Compare

        Dim psz1 As String = ""
        Dim psz2 As String = ""
        If (String.IsNullOrEmpty(x) = False) Then psz1 = x
        If (String.IsNullOrEmpty(y) = False) Then psz2 = y

        Return SafeNativeMethods.StrCmpLogicalW(psz1, psz2) * Me.modifier
    End Function

End Class

<SuppressUnmanagedCodeSecurity()> _
Friend Module SafeNativeMethods

    <DllImport("shlwapi.dll", CharSet:=CharSet.Unicode)> _
    Public Function StrCmpLogicalW(ByVal psz1 As String, ByVal psz2 As String) As Integer
    End Function

End Module

解決済み
引用返信 編集キー/
■54595 / inTopicNo.10)  Re[6]: ファイル名のソート方法について
□投稿者/ ペンネ (4回)-(2010/10/27(Wed) 11:30:49)
774RRさん、アドバイスありがとうございます。
とりあえず、OSはXP以降の想定ですし、エクスプローラのソート順設定についても
レジストリの値を参照して対応しようと思います。
ありがとうございました。
解決済み
引用返信 編集キー/
■54596 / inTopicNo.11)  Re[6]: ファイル名のソート方法について
□投稿者/ ペンネ (5回)-(2010/10/27(Wed) 11:34:14)
皆様、VBのサンプルまで頂き、誠にありがとうございます。感謝。
解決済み
引用返信 編集キー/
■54602 / inTopicNo.12)  Re[7]: ファイル名のソート方法について
□投稿者/ 774RR (552回)-(2010/10/27(Wed) 12:52:07)
ついでだから native C++ でも (祭りだ祭りだ)

#if 0 // standard function
bool mycmp(const std::wstring& l, const std::wstring& r) {
    return StrCmpLogicalW(l.c_str(), r.c_str())<0;
}
#endif

#if 1 // functional object
struct mycmp {
    int factor;
    mycmp(int order=1) : factor(order) {}
    bool operator()(const std::wstring& l, const std::wstring& r) const {
        return (factor*StrCmpLogicalW(l.c_str(), r.c_str()))<0;
    }
};
#endif

int main() {
    std::vector<std::wstring> tx;
    tx.push_back(L"2003-4.txt");
    tx.push_back(L"2001-1.txt");
    tx.push_back(L"2001-11.txt");
    tx.push_back(L"2001-3.txt");
    std::sort(tx.begin(), tx.end(), mycmp()); // descending order cmp(-1)
    std::copy(tx.begin(), tx.end(), std::ostream_iterator<std::wstring,wchar_t>(std::wcout, L"\n"));
    return 0;
}

引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -