2012-02-02 15 views
23

Tôi hiện đang làm việc với một số thao tác tìm kiếm và thay thế mà tôi đang cố gắng tự động hóa bằng cách sử dụng PowerShell. Thật không may, tôi đã công nhận ngày hôm qua rằng chúng tôi đã mã hóa tập tin khác nhau trong codebase của chúng tôi (UTF8 và ASCII). Bởi vì chúng tôi đang thực hiện các thao tác tìm kiếm và thay thế này trong một nhánh khác, tôi không thể thay đổi mã hóa tệp ở giai đoạn này.Tệp out-out của PowerShell: ngăn các thay đổi mã hóa

Nếu tôi đang chạy các dòng sau, nó sẽ thay đổi tất cả các tệp thành UCS-2 Little Eindian mặc dù mã hóa quyền hạn mặc định của tôi được đặt thành iso-8859-1 (Tây Âu (Windows)).

$content = Get-Content $_.Path 
$content -replace 'myOldText' , 'myNewText' | Out-File $_.Path 

Có cách nào để ngăn chặn quyền hạn thay đổi mã hóa của tệp không?

Trả lời

31

Out-File có một mã hóa mặc định trừ khi overriden với -Encoding tham số:

gì tôi đã thực hiện để giải quyết này là cố gắng để có được mã hóa các tập tin gốc bằng cách đọc cố gắng đọc nó byte order mark và sử dụng nó như là -Encoding Giá trị tham số.

Dưới đây là một ví dụ xử lý một loạt các đường dẫn tệp văn bản, nhận được mã hóa ban đầu, xử lý nội dung và ghi nó trở lại tệp với mã hóa ban đầu.

function Get-FileEncoding { 
    param ([string] $FilePath) 

    [byte[]] $byte = get-content -Encoding byte -ReadCount 4 -TotalCount 4 -Path $FilePath 

    if ($byte[0] -eq 0xef -and $byte[1] -eq 0xbb -and $byte[2] -eq 0xbf) 
     { $encoding = 'UTF8' } 
    elseif ($byte[0] -eq 0xfe -and $byte[1] -eq 0xff) 
     { $encoding = 'BigEndianUnicode' } 
    elseif ($byte[0] -eq 0xff -and $byte[1] -eq 0xfe) 
     { $encoding = 'Unicode' } 
    elseif ($byte[0] -eq 0 -and $byte[1] -eq 0 -and $byte[2] -eq 0xfe -and $byte[3] -eq 0xff) 
     { $encoding = 'UTF32' } 
    elseif ($byte[0] -eq 0x2b -and $byte[1] -eq 0x2f -and $byte[2] -eq 0x76) 
     { $encoding = 'UTF7'} 
    else 
     { $encoding = 'ASCII' } 
    return $encoding 
} 

foreach ($textFile in $textFiles) { 
    $encoding = Get-FileEncoding $textFile 
    $content = Get-Content -Encoding $encoding 
    # Process content here... 
    $content | Set-Content -Path $textFile -Encoding $encoding 
} 

Cập nhật Dưới đây là một ví dụ về việc mã hóa tập tin ban đầu bằng cách sử dụng lớp StreamReader. Ví dụ này đọc 3 byte đầu tiên của tệp để thuộc tính CurrentEncoding được đặt dựa trên kết quả của thường trình phát hiện BOM nội bộ của nó.

http://msdn.microsoft.com/en-us/library/9y86s1a9.aspx

Tham số detectEncodingFromByteOrderMarks phát hiện mã hóa bởi nhìn vào ba byte đầu tiên của dòng. Tự động nhận dạng UTF-8, Unicode nhỏ gọn và văn bản Unicode lớn nhất nếu tệp bắt đầu bằng các dấu thứ tự byte thích hợp. Nếu không, UTF8Encoding được sử dụng. Xem phương thức Encoding.GetPreamble để biết thêm thông tin .

http://msdn.microsoft.com/en-us/library/system.text.encoding.getpreamble.aspx

$text = @" 
This is 
my text file 
contents. 
"@ 

#Create text file. 
[IO.File]::WriteAllText($filePath, $text, [System.Text.Encoding]::BigEndianUnicode) 

#Create a stream reader to get the file's encoding and contents. 
$sr = New-Object System.IO.StreamReader($filePath, $true) 
[char[]] $buffer = new-object char[] 3 
$sr.Read($buffer, 0, 3) 
$encoding = $sr.CurrentEncoding 
$sr.Close() 

#Show the detected encoding. 
$encoding 

#Update the file contents. 
$content = [IO.File]::ReadAllText($filePath, $encoding) 
$content2 = $content -replace "my" , "your" 

#Save the updated contents to file. 
[IO.File]::WriteAllText($filePath, $content2, $encoding) 

#Display the result. 
Get-Content $filePath 
+0

Tôi đã nghĩ về điều đó nhưng phải có một cách dễ dàng hơn, không phải nó? Nhưng điều đó làm việc cho tôi bây giờ. Cảm ơn Andy! – Pete

+2

@Pete Bạn sẽ phải lấy mã hóa. Không có lệnh ghép ngắn nào cho bạn. Tôi đã cập nhật câu trả lời của mình bằng cách thêm một cách tiếp cận khác. Cả hai cách đều sử dụng tính năng phát hiện BOM. –

+0

'Set-Content -Path BOM_Utf32.txt -Giá trị $ null -Kích hoạt UTF32' ghi _UTF-32, bit-endian_ BOM nghĩa là chuỗi byte' FF FE 00 00'. Tuy nhiên, hàm 'Get-FileEncoding' trả về' Unicode'. Mặt khác, chuỗi byte '00 00 FE FF' được nhận dạng là' UTF32' nhưng theo [Unicode Consortium] (http://unicode.org/faq/utf_bom.html#BOM) đây là _UTF-32, big-endian_ BOM. Liệu tôi có sai? Lỗi đâu rồi? – JosefZ

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