Out-File
UTF-8 का उपयोग करते समय BOM को बाध्य करने के लिए लगता है:
$MyFile = Get-Content $MyPath
$MyFile | Out-File -Encoding "UTF8" $MyPath
मैं PowerShell का उपयोग करके बिना BOM वाले UTF-8 में एक फ़ाइल कैसे लिख सकता हूं?
Out-File
UTF-8 का उपयोग करते समय BOM को बाध्य करने के लिए लगता है:
$MyFile = Get-Content $MyPath
$MyFile | Out-File -Encoding "UTF8" $MyPath
मैं PowerShell का उपयोग करके बिना BOM वाले UTF-8 में एक फ़ाइल कैसे लिख सकता हूं?
जवाबों:
.NET की UTF8Encoding
क्लास का उपयोग करना और $False
कंस्ट्रक्टर को पास करना काम करने लगता है:
$MyRawString = Get-Content -Raw $MyPath
$Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding $False
[System.IO.File]::WriteAllLines($MyPath, $MyRawString, $Utf8NoBomEncoding)
[System.IO.File]::WriteAllLines($MyPath, $MyFile)
पर्याप्त है। यह WriteAllLines
अधिभार BOM के बिना बिल्कुल UTF8 लिखता है।
WriteAllLines
आवश्यकता प्रतीत होती $MyPath
है।
WriteAllLines
से वर्तमान निर्देशिका मिलती है [System.Environment]::CurrentDirectory
। यदि आप PowerShell को खोलते हैं और फिर अपनी वर्तमान निर्देशिका (उपयोग cd
या Set-Location
) को बदलते हैं , तो [System.Environment]::CurrentDirectory
परिवर्तित नहीं किया जाएगा और फ़ाइल गलत निर्देशिका में समाप्त हो जाएगी। आप इसके द्वारा काम कर सकते हैं [System.Environment]::CurrentDirectory = (Get-Location).Path
।
अब तक का उचित तरीका है @ रमन कुज़मिन द्वारा सुझाए गए समाधान का उपयोग करके टिप्पणियों में @ एम। डडले उत्तर :
[IO.File]::WriteAllLines($filename, $content)
(मैंने अनावश्यक System
नाम स्थान स्पष्टीकरण को हटाकर इसे थोड़ा छोटा कर दिया है - इसे डिफ़ॉल्ट रूप से स्वचालित रूप से प्रतिस्थापित किया जाएगा)
[IO.File]::WriteAllLines(($filename | Resolve-Path), $content)
मुझे लगा कि यह यूटीएफ नहीं होगा, लेकिन मुझे बस एक बहुत ही सरल समाधान मिला है जो काम करने लगता है ...
Get-Content path/to/file.ext | out-file -encoding ASCII targetFile.ext
स्रोत प्रारूप की परवाह किए बिना बम फ़ाइल के बिना utf-8 में मेरे लिए यह परिणाम है।
-encoding utf8
मेरी आवश्यकता के।
-Encoding ASCII
BOM समस्या से बचा जाता है, लेकिन आपको स्पष्ट रूप से केवल 7-बिट ASCII वर्ण मिलते हैं । यह देखते हुए कि ASCII UTF-8 का सबसेट है, परिणामस्वरूप फ़ाइल तकनीकी रूप से एक मान्य UTF-8 फ़ाइल है, लेकिन आपके इनपुट में सभी गैर-ASCII अक्षर शाब्दिक ?
वर्णों में बदल जाएंगे ।
-encoding utf8
भी एक BOM के साथ UTF-8 का उत्पादन करता है। :(
नोट: यह उत्तर Windows PowerShell पर लागू होता है ; इसके विपरीत, क्रॉस-प्लेटफॉर्म PowerShell कोर संस्करण (v6 +) में, बिना BOM के UTF-8 सभी cmdlets में डिफ़ॉल्ट एन्कोडिंग है ।
दूसरे शब्दों में: यदि आप PowerShell [Core] संस्करण 6 या उच्चतर का उपयोग कर रहे हैं , तो आपको डिफ़ॉल्ट रूप से BOM- कम UTF-8 फ़ाइलें मिलती हैं (जिसे आप स्पष्ट रूप से -Encoding utf8
/ के साथ अनुरोध कर सकते हैं -Encoding utf8NoBOM
, जबकि आप -BOM एन्कोडिंग के साथ प्राप्त करते हैं )।-utf8BOM
की मदद के लिए एम डुडले की अपनी सरल और व्यावहारिक जवाब (और ForNeVeR के अधिक संक्षिप्त पुनर्निर्माण ):
सुविधा के लिए, यहां उन्नत कार्य Out-FileUtf8NoBom
, एक पाइपलाइन-आधारित विकल्प जो कि नकल करता हैOut-File
, जिसका अर्थ है:
Out-File
एक पाइपलाइन की तरह उपयोग कर सकते हैं ।Out-File
।उदाहरण:
(Get-Content $MyPath) | Out-FileUtf8NoBom $MyPath
ध्यान दें कि कैसे (Get-Content $MyPath)
संलग्न है (...)
, जो यह सुनिश्चित करता है कि पूरी फ़ाइल को खोला गया है, पूर्ण रूप से पढ़ा गया है, और पाइपलाइन के माध्यम से परिणाम भेजने से पहले बंद कर दिया गया है। यह उसी फ़ाइल में वापस लिखने में सक्षम होने के लिए आवश्यक है (इसे जगह में अपडेट करें )।
आम तौर पर, हालांकि, यह तकनीक 2 कारणों से उचित नहीं है: (ए) पूरी फ़ाइल को मेमोरी में फिट होना चाहिए और (बी) यदि कमांड बाधित है, तो डेटा खो जाएगा।
स्मृति उपयोग पर एक नोट :
का स्रोत कोडOut-FileUtf8NoBom
( MIT- लाइसेंस प्राप्त Gist के रूप में भी उपलब्ध है ):
<#
.SYNOPSIS
Outputs to a UTF-8-encoded file *without a BOM* (byte-order mark).
.DESCRIPTION
Mimics the most important aspects of Out-File:
* Input objects are sent to Out-String first.
* -Append allows you to append to an existing file, -NoClobber prevents
overwriting of an existing file.
* -Width allows you to specify the line width for the text representations
of input objects that aren't strings.
However, it is not a complete implementation of all Out-String parameters:
* Only a literal output path is supported, and only as a parameter.
* -Force is not supported.
Caveat: *All* pipeline input is buffered before writing output starts,
but the string representations are generated and written to the target
file one by one.
.NOTES
The raison d'être for this advanced function is that, as of PowerShell v5,
Out-File still lacks the ability to write UTF-8 files without a BOM:
using -Encoding UTF8 invariably prepends a BOM.
#>
function Out-FileUtf8NoBom {
[CmdletBinding()]
param(
[Parameter(Mandatory, Position=0)] [string] $LiteralPath,
[switch] $Append,
[switch] $NoClobber,
[AllowNull()] [int] $Width,
[Parameter(ValueFromPipeline)] $InputObject
)
#requires -version 3
# Make sure that the .NET framework sees the same working dir. as PS
# and resolve the input path to a full path.
[System.IO.Directory]::SetCurrentDirectory($PWD.ProviderPath) # Caveat: Older .NET Core versions don't support [Environment]::CurrentDirectory
$LiteralPath = [IO.Path]::GetFullPath($LiteralPath)
# If -NoClobber was specified, throw an exception if the target file already
# exists.
if ($NoClobber -and (Test-Path $LiteralPath)) {
Throw [IO.IOException] "The file '$LiteralPath' already exists."
}
# Create a StreamWriter object.
# Note that we take advantage of the fact that the StreamWriter class by default:
# - uses UTF-8 encoding
# - without a BOM.
$sw = New-Object IO.StreamWriter $LiteralPath, $Append
$htOutStringArgs = @{}
if ($Width) {
$htOutStringArgs += @{ Width = $Width }
}
# Note: By not using begin / process / end blocks, we're effectively running
# in the end block, which means that all pipeline input has already
# been collected in automatic variable $Input.
# We must use this approach, because using | Out-String individually
# in each iteration of a process block would format each input object
# with an indvidual header.
try {
$Input | Out-String -Stream @htOutStringArgs | % { $sw.WriteLine($_) }
} finally {
$sw.Dispose()
}
}
संस्करण 6 से शुरू PowerShell सेट-सामग्री और आउट-फ़ाइलUTF8NoBOM
दोनों के लिए एन्कोडिंग का समर्थन करता है और यहां तक कि इसे डिफ़ॉल्ट एन्कोडिंग के रूप में उपयोग करता है।
तो उपरोक्त उदाहरण में यह इस तरह होना चाहिए:
$MyFile | Out-File -Encoding UTF8NoBOM $MyPath
$PSVersionTable.PSVersion
Set-Content
इसके बजाय का उपयोग करते समय Out-File
, आप एन्कोडिंग को निर्दिष्ट कर सकते हैं Byte
, जिसका उपयोग फ़ाइल में बाइट सरणी लिखने के लिए किया जा सकता है। यह कस्टम UTF8 एन्कोडिंग के साथ संयोजन में जो BOM का उत्सर्जन नहीं करता है वांछित परिणाम देता है:
# This variable can be reused
$utf8 = New-Object System.Text.UTF8Encoding $false
$MyFile = Get-Content $MyPath -Raw
Set-Content -Value $utf8.GetBytes($MyFile) -Encoding Byte -Path $MyPath
उपयोग करने [IO.File]::WriteAllLines()
या इसके समान अंतर यह है कि यह किसी भी प्रकार के आइटम और पथ के साथ ठीक काम करना चाहिए, न केवल वास्तविक फ़ाइल पथ।
यह स्क्रिप्ट, बिना BOM के UTF-8 में परिवर्तित हो जाएगी, DIRECTORY1 में सभी .txt फाइलें और उन्हें DIRECTORY2 में आउटपुट कर देगा
foreach ($i in ls -name DIRECTORY1\*.txt)
{
$file_content = Get-Content "DIRECTORY1\$i";
[System.IO.File]::WriteAllLines("DIRECTORY2\$i", $file_content);
}
[System.IO.FileInfo] $file = Get-Item -Path $FilePath
$sequenceBOM = New-Object System.Byte[] 3
$reader = $file.OpenRead()
$bytesRead = $reader.Read($sequenceBOM, 0, 3)
$reader.Dispose()
#A UTF-8+BOM string will start with the three following bytes. Hex: 0xEF0xBB0xBF, Decimal: 239 187 191
if ($bytesRead -eq 3 -and $sequenceBOM[0] -eq 239 -and $sequenceBOM[1] -eq 187 -and $sequenceBOM[2] -eq 191)
{
$utf8NoBomEncoding = New-Object System.Text.UTF8Encoding($False)
[System.IO.File]::WriteAllLines($FilePath, (Get-Content $FilePath), $utf8NoBomEncoding)
Write-Host "Remove UTF-8 BOM successfully"
}
Else
{
Write-Warning "Not UTF-8 BOM file"
}
स्रोत PowerShell का उपयोग करके किसी फ़ाइल से UTF8 बाइट ऑर्डर मार्क (BOM) कैसे निकालें
यदि आप उपयोग करना चाहते हैं [System.IO.File]::WriteAllLines()
, तो आपको दूसरे पैरामीटर को String[]
(यदि प्रकार $MyFile
है Object[]
), और इसके साथ निरपेक्ष पथ निर्दिष्ट करना चाहिए $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($MyPath)
, जैसे:
$Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding $False
Get-ChildItem | ConvertTo-Csv | Set-Variable MyFile
[System.IO.File]::WriteAllLines($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($MyPath), [String[]]$MyFile, $Utf8NoBomEncoding)
यदि आप उपयोग करना चाहते हैं [System.IO.File]::WriteAllText()
, तो कभी-कभी आपको | Out-String |
प्रत्येक पंक्ति के अंत में CRLFs को जोड़ने के लिए दूसरे पैरामीटर को पाइप में अन्वेषण करना चाहिए (विशेषकर जब आप उनका उपयोग करते हैं ConvertTo-Csv
):
$Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding $False
Get-ChildItem | ConvertTo-Csv | Out-String | Set-Variable tmp
[System.IO.File]::WriteAllText("/absolute/path/to/foobar.csv", $tmp, $Utf8NoBomEncoding)
या आप के [Text.Encoding]::UTF8.GetBytes()
साथ उपयोग कर सकते हैं Set-Content -Encoding Byte
:
$Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding $False
Get-ChildItem | ConvertTo-Csv | Out-String | % { [Text.Encoding]::UTF8.GetBytes($_) } | Set-Content -Encoding Byte -Path "/absolute/path/to/foobar.csv"
देखें: बिना BOM के UTF-8 में एक फ़ाइल में ConvertTo-Csv का परिणाम कैसे लिखें
$ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($MyPath)
है Convert-Path $MyPath
; यदि आप एक अनुगामी CRLF सुनिश्चित करना चाहते हैं, तो बस एक इनपुट स्ट्रिंग (कोई ज़रूरत नहीं है ) के [System.IO.File]::WriteAllLines()
साथ भी उपयोग करें । Out-String
एक तकनीक जो मैं उपयोग करता हूं वह आउट-फाइल cmdlet का उपयोग करके ASCII फ़ाइल में आउटपुट को पुनर्निर्देशित करना है ।
उदाहरण के लिए, मैं अक्सर SQL स्क्रिप्ट चलाता हूं जो Oracle में निष्पादित करने के लिए एक और SQL स्क्रिप्ट बनाता है। सरल पुनर्निर्देशन (">") के साथ, आउटपुट UTF-16 में होगा जो SQLPlus द्वारा मान्यता प्राप्त नहीं है। इसके आसपास काम करने के लिए:
sqlplus -s / as sysdba "@create_sql_script.sql" |
Out-File -FilePath new_script.sql -Encoding ASCII -Force
फिर उत्पन्न स्क्रिप्ट को किसी अन्य यूनिकोड चिंताओं के बिना किसी अन्य SQLPlus सत्र के माध्यम से निष्पादित किया जा सकता है:
sqlplus / as sysdba "@new_script.sql" |
tee new_script.log
-Encoding ASCII
BOM समस्या से बचा जाता है, लेकिन आपको स्पष्ट रूप से केवल 7-बिट ASCII वर्णों के लिए समर्थन मिलता है । यह देखते हुए कि ASCII UTF-8 का सबसेट है, परिणामस्वरूप फ़ाइल तकनीकी रूप से एक मान्य UTF-8 फ़ाइल है, लेकिन आपके इनपुट में सभी गैर-ASCII अक्षर शाब्दिक ?
वर्णों में बदल जाएंगे ।
बिना BOM के UTF-8 के लिए एक्सटेंशन द्वारा कई फाइलें बदलें:
$Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding($False)
foreach($i in ls -recurse -filter "*.java") {
$MyFile = Get-Content $i.fullname
[System.IO.File]::WriteAllLines($i.fullname, $MyFile, $Utf8NoBomEncoding)
}
जो भी कारण के लिए, WriteAllLines
कॉल अभी भी मेरे लिए एक BOM का उत्पादन कर रहे थे, BOMless UTF8Encoding
तर्क के साथ और इसके बिना। लेकिन निम्नलिखित ने मेरे लिए काम किया:
$bytes = gc -Encoding byte BOMthetorpedoes.txt
[IO.File]::WriteAllBytes("$(pwd)\BOMthetorpedoes.txt", $bytes[3..($bytes.length-1)])
मुझे काम करने के लिए फ़ाइल पथ को पूर्ण बनाना पड़ा। अन्यथा यह मेरे डेस्कटॉप के लिए फ़ाइल लिखा था। इसके अलावा, मुझे लगता है कि यह केवल तभी काम करता है जब आपको पता हो कि आपका BOM 3 बाइट्स है। मुझे नहीं पता कि एन्कोडिंग के आधार पर किसी BOM प्रारूप / लंबाई की अपेक्षा करना कितना विश्वसनीय है।
साथ ही, जैसा कि लिखा गया है, यह संभवतः तभी काम करता है जब आपकी फ़ाइल एक पॉवरशेल सरणी में फिट हो जाती है, जो लगता है कि [int32]::MaxValue
मेरी मशीन की तुलना में कुछ मान की लंबाई सीमा कम है ।
WriteAllLines
एन्कोडिंग तर्क के बिना कभी भी BOM स्वयं नहीं लिखता है , लेकिन यह बोधगम्य है कि आपका स्ट्रिंग BOM वर्ण से शुरू हुआ है (U+FEFF
) के , जिसने लेखन पर प्रभावी ढंग से एक यूटीएफ -8 बीओएम बनाया; उदाहरण: $s = [char] 0xfeff + 'hi'; [io.file]::WriteAllText((Convert-Path t.txt), $s)
(यह [char] 0xfeff +
देखने के लिए कि कोई BOM नहीं लिखा गया है)।
[Environment]::CurrentDirectory = $PWD.ProviderPath
, या, आपके "$(pwd)\..."
दृष्टिकोण के लिए एक अधिक सामान्य विकल्प के रूप में (बेहतर:, "$pwd\..."
और भी बेहतर: "$($pwd.ProviderPath)\..."
या (Join-Path $pwd.ProviderPath ...)
), उपयोग करें(Convert-Path BOMthetorpedoes.txt)
U+FEFF
के बाइट प्रतिनिधित्व हैं ।
बिना BOM के UTF8 प्राप्त करने के लिए नीचे का उपयोग कर सकते हैं
$MyFile | Out-File -Encoding ASCII
ASCII
UTF-8 नहीं है, लेकिन यह वर्तमान ANSI कोडपेज नहीं है - आप सोच रहे हैं Default
; ASCII
सही मायने में 7-बिट ASCII एन्कोडिंग है, कोडपॉइंट्स के साथ = = 128 शाब्दिक ?
उदाहरणों में परिवर्तित हो रहा है ।
-Encoding ASCII
वास्तव में केवल 7-बिट ASCII है: 'äb' | out-file ($f = [IO.Path]::GetTempFilename()) -encoding ASCII; '?b' -eq $(Get-Content $f; Remove-Item $f)
- ä
a में अनुवाद किया गया है ?
। इसके विपरीत, -Encoding Default
("एएनएसआई") सही ढंग से इसे संरक्षित करेगा।
यह मेरे लिए काम करता है ("UTF8" के बजाय "डिफ़ॉल्ट" का उपयोग करें):
$MyFile = Get-Content $MyPath
$MyFile | Out-File -Encoding "Default" $MyPath
परिणाम BOM के बिना ASCII है।
Default
, सिस्टम के वर्तमान एएनएसआई कोड पेज का उपयोग करेगा, जो कि यूटीएफ -8 नहीं है, जैसा कि मुझे आवश्यक था।