2009-02-16 29 views
8

Tôi đang viết kịch bản quản trị và tôi cần tính toán kích thước tệp trên đĩa.Cách lấy kích thước thực tế trên đĩa của tệp từ PowerShell?

Các tệp này có dung lượng NTFS nén.

Tôi không thể sử dụng FileInfo.Length, vì đó là kích thước tệp và không phải kích thước trên đĩa. Ví dụ, nếu tôi có một tập tin 100MB, nhưng nó chỉ sử dụng 25MB do nén NTFS, tôi cần kịch bản của tôi để trở về 25MB.

Có cách nào để thực hiện việc này trong Powershell không?

(Tôi biết về GetCompressedFileSize() Win32 cuộc gọi, nhưng tôi đã hy vọng rằng điều này đã được wrappered ở một mức độ nào.)

+0

Bạn có muốn bao gồm các không gian trên đĩa lãng phí do không gian cụm không sử dụng? (điều này là khó khăn với các tệp nhỏ do nội tuyến trong MFT) hoặc chỉ là khía cạnh nén đủ – ShuggyCoUk

Trả lời

9

(chỉnh sửa)

tôi đã tìm ra cách để tự động thêm một tài sản (gọi là "kịch bản tài sản") đến Fileobject, vì vậy bây giờ, tôi có thể sử dụng cú pháp: $ theFileObject.CompressedSize để đọc kích thước.

(kết thúc chỉnh sửa)

phản ứng của đọc Goyuix, và tôi nghĩ "Cool, nhưng không phải là có một số loại khả năng kiểu mở rộng trong Powershell?". Vì vậy, sau đó tôi tìm thấy bài đăng này Scott Hanselman: http://www.hanselman.com/blog/MakingJunctionsReparsePointsVisibleInPowerShell.aspx

Và tôi đã tạo Thuộc tính tập lệnh cho đối tượng FileInfo: CompressedSize.

Dưới đây là những gì tôi đã làm: (lưu ý: Tôi là khá mới để Powershell, hoặc ít nhất là tôi không sử dụng nó nhiều này có thể có thể được thực hiện tốt hơn rất nhiều, nhưng đây là những gì tôi đã làm:.

Trước tiên, tôi biên soạn Ntfs.ExtendedFileInfo từ bài Goyuix của. tôi đặt DLL trong thư mục hồ sơ Powershell của tôi (Documents \ WindowsPowershell)

Tiếp theo, tôi đã tạo ra một tập tin trong thư mục hồ sơ của tôi tên là My.Types.ps1xml.

Tôi đặt XML sau vào tệp:

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

Mã đó (khi được hợp nhất vào hệ thống kiểu) sẽ tự động thêm thuộc tính có tên là CompressedSize vào đối tượng FileInfo được trả về bởi get-childitem/dir.Nhưng Powershell không biết về mã, và nó không biết về DLL của tôi được nêu ra. Chúng tôi xử lý điều đó trong bước tiếp theo:

Chỉnh sửa tiểu sử.ps1. trong cùng một thư mục. Bây giờ, hồ sơ của tôi xảy ra đã có một số nội dung trong đó vì tôi đã cài đặt Tiện ích mở rộng cộng đồng cho quyền năng. Hy vọng rằng, tôi sẽ bao gồm mọi thứ bạn cần trong đoạn mã tiếp theo này, vì vậy nó sẽ hoạt động ngay cả trên một máy không có phần mở rộng. Thêm mã sau vào Profile.ps1:

#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 

Bây giờ, biến $ ProfileDir mà tôi tham chiếu được xác định trước đó trong tập lệnh Profile.ps1 của tôi. Chỉ trong trường hợp nó không phải là của bạn, đây là định nghĩa:

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

Vậy đó. Lần sau khi bạn chạy Powershell, bạn có thể truy cập thuộc tính CompressedSize trên đối tượng FileInfo giống như thể nó là bất kỳ thuộc tính nào khác. Ví dụ:

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

$ myFile.CompressedSize

này hoạt động (trên máy tính của tôi, dù sao), nhưng tôi rất thích nghe dù nó phù hợp với các phương pháp hay nhất. Một điều tôi biết tôi đang làm sai: trong file Profile.ps1, tôi trả về kết quả của LoadFile thành một biến mà tôi sẽ không sử dụng ($ null = blah blah). Tôi đã làm điều đó để ngăn chặn hiển thị kết quả của tập tin tải vào bàn điều khiển. Có lẽ là một cách tốt hơn để làm điều đó.

8

tải lên Windows API Managed (http://mwinapi.sourceforge.net/) và kiểm tra các lớp ExtendedFileInfo. Có một phương thức GetPhysicalFileSize() sẽ trả về kích thước tệp yêu cầu trên đĩa.

public static ulong GetPhysicalFileSize(string filename) 

Aternatively, bạn có thể biên dịch DLL của riêng bạn và tải lắp ráp cho rằng một trong những chức năng:

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; 
     } 
    } 
    } 
} 

Sau đó, để biên dịch:

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

Và cuối cùng, để nạp và chạy trong PowerShell:

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

Nếu bạn không thể tìm thấy API được quản lý mà bạn thích, trong PowerShell V2, nó dễ dàng hơn nhiều để P/Gọi một API Win32. Đọc PowerShell P/Invoke Walkthrough để được hướng dẫn.

5

Dễ dàng để làm bằng V2 Thêm-Type và Pinvoke.NET:

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") 

thí nghiệm! Thưởng thức! Thuê!

Jeffrey Snover [MSFT] của Windows Đối tác Quản lý Kiến trúc sư Thăm blog Windows PowerShell Đội tại địa chỉ: http://blogs.msdn.com/PowerShell Visit Windows PowerShell ScriptCenter tại địa chỉ: http://www.microsoft.com/technet/scriptcenter/hubs/msh.mspx

+0

Tôi yêu sự đơn giản của giải pháp này ... nhưng đối với tôi, nó luôn trả về cùng giá trị với "độ dài", thậm chí khi nào thì khác. Đó có phải là giới hạn của cuộc gọi API Win32 không? – ewall

+1

@ewall Đây là một bài đăng cũ nhưng API chính xác để gọi là ở đây: http://stackoverflow.com/a/22508299/520612 –

0

$ s = (compact/q C: \ whatever.dat | where-object {$ _. contains ('total bytes')}). split()}; $ s [8] .padleft (20) + $ s [0] .padleft (20)

Các vấn đề liên quan