var length = new System.IO.FileInfo(path).Length;
これにより、ディスク上のサイズではなく、ファイルの論理サイズがわかります。
Windowsエクスプローラーで報告されるように、C#で(できれば相互運用機能なしで)ディスク上のファイルのサイズを取得したいと思います。
次のような正しいサイズを指定する必要があります。
- 圧縮ファイル
- スパースファイル
- 断片化されたファイル
回答:
これは、ho1が提案したようにGetCompressedFileSizeを使用し、PaulStackが提案したようにGetDiskFreeSpaceを使用しますが、P / Invokeを使用します。圧縮ファイルについてのみテストしましたが、断片化されたファイルでは機能しないと思われます。
public static long GetFileSizeOnDisk(string file)
{
FileInfo info = new FileInfo(file);
uint dummy, sectorsPerCluster, bytesPerSector;
int result = GetDiskFreeSpaceW(info.Directory.Root.FullName, out sectorsPerCluster, out bytesPerSector, out dummy, out dummy);
if (result == 0) throw new Win32Exception();
uint clusterSize = sectorsPerCluster * bytesPerSector;
uint hosize;
uint losize = GetCompressedFileSizeW(file, out hosize);
long size;
size = (long)hosize << 32 | losize;
return ((size + clusterSize - 1) / clusterSize) * clusterSize;
}
[DllImport("kernel32.dll")]
static extern uint GetCompressedFileSizeW([In, MarshalAs(UnmanagedType.LPWStr)] string lpFileName,
[Out, MarshalAs(UnmanagedType.U4)] out uint lpFileSizeHigh);
[DllImport("kernel32.dll", SetLastError = true, PreserveSig = true)]
static extern int GetDiskFreeSpaceW([In, MarshalAs(UnmanagedType.LPWStr)] string lpRootPathName,
out uint lpSectorsPerCluster, out uint lpBytesPerSector, out uint lpNumberOfFreeClusters,
out uint lpTotalNumberOfClusters);
FileInfo.Directory.Root
あらゆる種類のファイルシステムリンクを処理できるようには見えません。したがって、シンボリックリンク/ハードリンク/ジャンクションポイントやNTFSが提供するものがない従来のローカルドライブ文字でのみ機能します。
System.ComponentModel
とが必要System.Runtime.InteropServices
です。
上記のコードは、上で正常に動作しないWindows Server 2008のクラスタサイズが常にゼロであるとして、または2008 R2またはWindows 7およびWindows Vistaベースのシステム(GetDiskFreeSpaceWとGetDiskFreeSpaceのリターン-1でもとUAC無効。)ここで変更されたコードは、作品ということです。
C#
public static long GetFileSizeOnDisk(string file)
{
FileInfo info = new FileInfo(file);
uint clusterSize;
using(var searcher = new ManagementObjectSearcher("select BlockSize,NumberOfBlocks from Win32_Volume WHERE DriveLetter = '" + info.Directory.Root.FullName.TrimEnd('\\') + "'") {
clusterSize = (uint)(((ManagementObject)(searcher.Get().First()))["BlockSize"]);
}
uint hosize;
uint losize = GetCompressedFileSizeW(file, out hosize);
long size;
size = (long)hosize << 32 | losize;
return ((size + clusterSize - 1) / clusterSize) * clusterSize;
}
[DllImport("kernel32.dll")]
static extern uint GetCompressedFileSizeW(
[In, MarshalAs(UnmanagedType.LPWStr)] string lpFileName,
[Out, MarshalAs(UnmanagedType.U4)] out uint lpFileSizeHigh);
VB.NET
Private Function GetFileSizeOnDisk(file As String) As Decimal
Dim info As New FileInfo(file)
Dim blockSize As UInt64 = 0
Dim clusterSize As UInteger
Dim searcher As New ManagementObjectSearcher( _
"select BlockSize,NumberOfBlocks from Win32_Volume WHERE DriveLetter = '" + _
info.Directory.Root.FullName.TrimEnd("\") + _
"'")
For Each vi As ManagementObject In searcher.[Get]()
blockSize = vi("BlockSize")
Exit For
Next
searcher.Dispose()
clusterSize = blockSize
Dim hosize As UInteger
Dim losize As UInteger = GetCompressedFileSizeW(file, hosize)
Dim size As Long
size = CLng(hosize) << 32 Or losize
Dim bytes As Decimal = ((size + clusterSize - 1) / clusterSize) * clusterSize
Return CDec(bytes) / 1024
End Function
<DllImport("kernel32.dll")> _
Private Shared Function GetCompressedFileSizeW( _
<[In](), MarshalAs(UnmanagedType.LPWStr)> lpFileName As String, _
<Out(), MarshalAs(UnmanagedType.U4)> lpFileSizeHigh As UInteger) _
As UInteger
End Function
.First()
、それがあるとしてIEnumerable
ではなくIEnumerable<T>
、コードの最初の呼び出しを使用したい場合は、.Cast<object>()
MSDNソーシャルフォーラムによると:
ディスク上のサイズは、ファイルを格納するクラスターのサイズの合計である
long sizeondisk = clustersize * ((filelength + clustersize - 1) / clustersize);
必要があります。クラスターサイズを見つけるには、P / Invokeにアクセスする必要があります。GetDiskFreeSpace()
それを返します。
C#でファイルのディスク上のサイズを取得する方法を参照してください。
ただし、これは圧縮がオンになっているNTFSでは機能しないことに注意してください。
GetCompressedFileSize
ではなく、のようなものを使用することをお勧めしfilelength
ます。
私はそれがこのようになると思います:
double ifileLength = (finfo.Length / 1048576); //return file size in MB ....
確認を得るために、私はまだこれについていくつかのテストを行っています。