13

まったく使用せずにC#でファイルのサイズを取得することは可能ですか?System.IO.FileInfo

Path.GetFileName(yourFilePath)と をそれぞれ使用して名前や拡張子などの他のものを取得できることは知っていますがPath.GetExtension(yourFilePath)、ファイルサイズは明らかにそうではありませんか? を使用せずにファイルサイズを取得する別の方法はありますSystem.IO.FileInfoか?

これの唯一の理由は、私が正しければ、FileInfo は実際に必要とするよりも多くの情報を取得するためです。そのため、ファイルのサイズだけが必要な場合、これらすべての FileInfo を収集するには時間がかかります。もっと速い方法はありますか?

4

6 に答える 6

8

次の2つの方法を使用してベンチマークを実行しました。

    public static uint GetFileSizeA(string filename)
    {
        WIN32_FIND_DATA findData;
        FindFirstFile(filename, out findData);
        return findData.nFileSizeLow;
    }

    public static uint GetFileSizeB(string filename)
    {
        IntPtr handle = CreateFile(
            filename,
            FileAccess.Read,
            FileShare.Read,
            IntPtr.Zero,
            FileMode.Open,
            FileAttributes.ReadOnly,
            IntPtr.Zero);
        long fileSize;
        GetFileSizeEx(handle, out fileSize);
        CloseHandle(handle);
        return (uint) fileSize;
    }

GetFileSizeAは、2300を少し超えるファイルに対して実行され、実行に62〜63ミリ秒かかりました。GetFileSizeBは18秒以上かかりました。

私が間違っていることを誰かが見ない限り、どちらの方法が速いかについての答えは明らかだと思います。

実際にファイルを開かないようにする方法はありますか?

アップデート

FileAttributes.ReadOnlyをFileAttributes.Normalに変更すると、タイミングが短縮され、2つのメソッドのパフォーマンスが同じになりました。

さらに、CloseHandle()呼び出しをスキップすると、GetFileSizeExメソッドが約20〜30%速くなりますが、それをお勧めするかどうかはわかりません。

于 2013-01-18T22:41:47.597 に答える
5

私が行った短いテストから、FileStream を使用すると、Pete の GetFileSizeB を使用するよりも平均でわずか 1 ミリ秒遅いことがわかりました (ネットワーク共有で約 21 ミリ秒かかりました...)。個人的には、できる限り BCL の制限内にとどまることを好みます。

コードは簡単です:

using (var file = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
    return file.Length;
}
于 2013-12-19T09:19:48.340 に答える
3

このコメントに従って:

サイズ情報を収集して配列に保存する小さなアプリケーションがあります...しかし、50万個のファイルがあり、ギブまたはテイクし、それらすべてのファイルを処理するのに時間がかかります(FileInfoを使用しています) . もっと早い方法はないかと考えていたのですが…

非常に多くのファイルの長さを見つけているので、別の方法でファイルサイズを取得しようとするよりも、並列化の恩恵を受ける可能性がはるかに高くなります。FileInfoクラスは十分に優れている必要があり、改善は小さい可能性があります。

一方、ファイル サイズの要求を並列化すると、速度が大幅に向上する可能性があります。(改善の度合いは、プロセッサではなくディスク ドライブに大きく依存するため、結果は大きく異なる可能性があることに注意してください。)

于 2013-01-18T22:16:04.213 に答える
3

直接的な答えではありません....NETフレームワークを使用するより高速な方法があるかどうかわからないためです。

私が使用しているコードは次のとおりです。

  List<long> list = new List<long>();
  DirectoryInfo di = new DirectoryInfo("C:\\Program Files");
  FileInfo[] fiArray = di.GetFiles("*", SearchOption.AllDirectories);
  foreach (FileInfo f in fiArray)
    list.Add(f.Length);

それを実行すると、「Program Files」ディレクトリで実行するのに2709ミリ秒かかりました。これは約22720ファイルでした。それは決して前かがみではありません。さらに、メソッド*.txtの最初のパラメーターのフィルターとして配置するGetFilesと、時間が 461ms に大幅に短縮されました。

これの多くは、ハード ドライブの速度に依存しますが、FileInfo がパフォーマンスを低下させているとは思いません。

注:これは.NET 4+でのみ有効だと思います

于 2013-02-13T20:21:45.327 に答える
0

あなたはこれを試すことができます:

[DllImport("kernel32.dll")]
static extern bool GetFileSizeEx(IntPtr hFile, out long lpFileSize);

しかし、それはそれほど改善されていません...

pinvoke.netから取得したサンプルコードは次のとおりです。

IntPtr handle = CreateFile(
    PathString, 
    GENERIC_READ, 
    FILE_SHARE_READ, 
    0, 
    OPEN_EXISTING, 
    FILE_ATTRIBUTE_READONLY, 
    0); //PInvoked too

if (handle.ToInt32() == -1) 
{
    return; 
}

long fileSize;
bool result = GetFileSizeEx(handle, out fileSize);
if (!result) 
{
    return;
}
于 2013-01-18T21:33:55.610 に答える