2009-02-16 28 views
8

Bir yönetimsel komut dosyası yazıyorum ve diskteki dosyaların boyutunu hesaplamam gerekiyor.Bir dosyanın disk üzerindeki gerçek boyutu PowerShell'den nasıl edinilir?

Bu dosyalar, sıkıştırılmış bir NTFS birimindedir.

FileInfo.Length kullanamıyorum, çünkü bu dosya boyutu ve diskte boyut değil. Örneğin, 100 MB'lık bir dosyam varsa, ancak NTFS sıkıştırması nedeniyle yalnızca 25MB kullanıyorsa, 25 MB'lık geri dönmek için komut dosyasına ihtiyacım var.

Bunu Powershell'de yapmanın bir yolu var mı?

(I GetCompressedFileSize() Win32 çağrısı hakkında biliyorum, ama bu zaten bazı seviyede wrappered olduğunu umuyordum.)

+0

adresinde açıklanmıştır kullanılmayan küme alanı nedeniyle israf diskte boşluk istiyor musunuz? (Bu, MFT'deki satır içi nedeniyle küçük dosyalar ile zor) ya da sadece sıkıştırılmış boyuttur. – ShuggyCoUk

cevap

9

Ben dinamik olarak şimdi, sözdizimi kullanabilirsiniz FileObject (a "komut dosyası özelliği" olarak adlandırılan) bir özelliği nasıl ekleneceğini anladım

(düzenle): boyutu okumak için $ theFileObject.CompressedSize.

(düzenleme sonu)

Oku Goyuix tepkisi, ben de "Serin ama PowerShell tip uzatma yeteneği çeşit yok?" Diye düşündüm. Sonra bu Scott Hanselman yazısını buldum: http://www.hanselman.com/blog/MakingJunctionsReparsePointsVisibleInPowerShell.aspx Ve FileInfo nesnesi için bir Script Özelliği oluşturdum: CompressedSize. (Not: Burada

ne yaptım ben PowerShell için oldukça yeni, ya da en azından ben bu muhtemelen çok daha iyi yapılabilir pek kullanmıyorum yok, ama burada öyle yaptım.

Birincisi, Goyuix en görevinden Ntfs.ExtendedFileInfo derlenmiş. Ben PowerShell profili dizininde DLL koymak (Belgeler WindowsPowerShell \)

ileri, ben My.Types.ps1xml adlı Profilimi dizininde bir dosya oluşturdum.

Aşağıdaki XML dosyasını şu dosyaya koydum:

<Types> 
<Type> 
    <Name>System.IO.FileInfo</Name> 
    <Members> 
     <ScriptProperty> 
      <Name>CompressedSize</Name> 
      <GetScriptBlock> 
      [Ntfs.ExtendedFileInfo]::GetCompressedFileSize($this.FullName) 
      </GetScriptBlock> 
     </ScriptProperty> 
    </Members> 
</Type> 
</Types> 

Bu kod (bir kez tip sistemde birleştirildiğinde), get-childitem/dir tarafından döndürülen FileInfo nesnelerine CompressedSize adlı bir özelliği dinamik olarak ekleyecektir.Ancak Powershell henüz kod hakkında bilgi sahibi değil ve henüz benim DLL'imi bilmiyor. Bunu sonraki adımda ele alıyoruz:

Edit Profile. aynı dizinde. Şimdi, Profil dosyamda, içinde powershell için Topluluk Eklentileri yüklü olduğu için zaten bir şeyler yapılıyor. Umarım, bir sonraki kod snippet'inde ihtiyacınız olan her şeyi dahil ederim, böylece uzantıları olmayan bir makinede bile çalışır. Profile.ps1 için aşağıdaki kodu ekleyin:

#This will load the ExtendedfileInfo assembly to enable the GetCompressedFileSize method. this method is used by the 
#PSCompressedSize Script Property attached to the FileInfo object. 
$null = [System.Reflection.Assembly]::LoadFile("$ProfileDir\ntfs.extendedfileinfo.dll") 

#merge in my extended types 
$profileTypes = $ProfileDir | join-path -childpath "My.Types.ps1xml" 
Update-TypeData $profileTypes 

Şimdi, başvuru $ ProfileDir değişken Daha önceki Profile.ps1 komut tanımlanır. Sadece sizinki durumunda değil, işte buradaki tanım:

$ProfileDir = split-path $MyInvocation.MyCommand.Path -Parent 

Bu kadar. Powershell'i bir sonraki çalıştırmanızda FileInfo nesnesindeki CompressedSize özelliğine herhangi bir başka özellik gibi erişebilirsiniz. Örnek:

$ myFile = dir c: \ temp \ myfile.txt

$ myFile.CompressedSize

Bu (her neyse, benim makinede) çalışır, ama uyup uymadığını duymak isteriz En iyi uygulamalarla. Bildiğim bir şey yanlış yapıyorum: Profile.ps1 dosyasında LoadFile sonuçlarını kullanamayacağım bir değişkene döndürüyorum ($ null = blah blah). Bunu, yükleme dosyasının sonucunu konsola göstermek için yaptım. Muhtemelen bunu yapmanın daha iyi bir yolu vardır.

8

Yük kadar Yönetilen Windows API (http://mwinapi.sourceforge.net/) ve ExtendedFileInfo sınıfını kontrol edin. Diskte bir dosya için gereken boyutu döndürecek bir GetPhysicalFileSize() yöntemi vardır.

public static ulong GetPhysicalFileSize(string filename) 

Aternatively, kendi DLL derlemek ve bu bir fonksiyon için montaj yükleyebilir: Sonra

using System; 
using System.Runtime.InteropServices; 

namespace NTFS { 
    public class ExtendedFileInfo 
    { 
    [DllImport("kernel32.dll", SetLastError=true, EntryPoint="GetCompressedFileSize")] 
    static extern uint GetCompressedFileSizeAPI(string lpFileName, out uint lpFileSizeHigh); 
    public static ulong GetCompressedFileSize(string filename) 
    { 
     uint high; 
     uint low; 
     low = GetCompressedFileSizeAPI(filename, out high); 
     int error = Marshal.GetLastWin32Error(); 
     if (high == 0 && low == 0xFFFFFFFF && error != 0) 
     { 
     throw new System.ComponentModel.Win32Exception(error); 
     } 
     else 
     { 
     return ((ulong)high << 32) + low; 
     } 
    } 
    } 
} 

derlemek için:

csc /target:library /out:ntfs.extendedfileinfo.dll ntfs.extendedfileinfo.cs 

Ve nihayet, yük ve çalıştırmak için PowerShell:

PS C:\> [System.Reflection.Assembly]::LoadFile("C:\ntfs.extendedfileinfo.dll") 
PS C:\> [NTFS.ExtendedFileInfo]::GetCompressedFileSize("C:\sample.txt") 
2

İstediğiniz yönetilen API'yi bulamıyorsanız, PowerShell V2'de bir Win32 API'sini P/Invoke etmek çok daha kolaydır. Talimatlar için PowerShell P/Invoke Walkthrough'u okuyun.

5

Kolay V2 ekle-Type ve Pinvoke.NET kullanarak yapmak:

add-type -type @' 
using System; 
using System.Runtime.InteropServices; 
using System.ComponentModel; 

namespace Win32Functions 
{ 
    public class ExtendedFileInfo 
    { 
     [DllImport("kernel32.dll", SetLastError=true, EntryPoint="GetCompressedFileSize")] 
     static extern uint GetCompressedFileSizeAPI(string lpFileName, out uint lpFileSizeHigh); 

     public static ulong GetCompressedFileSize(string filename) 
     { 
      uint high; 
      uint low; 
      low = GetCompressedFileSizeAPI(filename, out high); 
      int error = Marshal.GetLastWin32Error(); 
      if (high == 0 && low == 0xFFFFFFFF && error != 0) 
      throw new Win32Exception(error); 
      else 
      return ((ulong)high << 32) + low; 
     } 
    } 
} 
'@ 

[Win32Functions.ExtendedFileInfo]::GetCompressedFileSize("C:\autoexec.bat") 

Experiment! Keyfini çıkarın! Engage!

Jeffrey Snover [MSFT] Windows Yönetim Ortağı Mimar Ziyaret Windows PowerShell Takım günlüğü de: http://blogs.msdn.com/PowerShell Ziyaret Windows PowerShell ScriptCenter at: http://www.microsoft.com/technet/scriptcenter/hubs/msh.mspx

+0

Bu çözümün sadeliğini seviyorum ... ama benim için her zaman "uzunluk" ile aynı değere dönüyor, farklı olduğunda. Bu, Win32 API çağrısı sınırlaması mı? – ewall

+1

@ewall Bu eski bir gönderi ancak aranacak doğru API: http://stackoverflow.com/a/22508299/520612 –

0

$ s = (kompakt/q C: \ whatever.dat Üste | Geri Bildirim Ver Neden {$ _. içerir ('toplam bayt')}). bölünmüş()}; $ s [8] .poleft (20) + $ s [0] .poleft (20)

İlgili konular