我正在尝试做一件简单的事情:将文件编码从任何东西更改为UTF-8而不使用BOM。我找到了几个执行此操作的脚本,唯一真正适用于我的脚本就是这一个:https://superuser.com/questions/397890/convert-text-files-recursively-to-utf-8-in-powershell#answer-397915。
它按预期工作,但我需要生成的文件没有BOM。所以我尝试稍微修改脚本,添加了给出这个问题的解决方案:Using PowerShell to write a file in UTF-8 without the BOM
这是我的最终剧本:
foreach ($i in Get-ChildItem -Recurse) {
if ($i.PSIsContainer) {
continue
}
$dest = $i.Fullname.Replace($PWD, "some_folder")
$Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding($False)
if (!(Test-Path $(Split-Path $dest -Parent))) {
New-Item $(Split-Path $dest -Parent) -type Directory
}
get-content $i | out-file -encoding $Utf8NoBomEncoding -filepath $dest
}
问题是,对于System.Text.UTF8Encoding($False)
行,powershell返回错误,抱怨参数不正确:
无法验证“编码”参数的参数。参数“System.Text.UTF8Encoding”不属于ValidateSet属性指定的“unicode,utf7,utf8,utf32,ascii”组。
我想知道我是否遗漏了一些东西,比如PowerShell版本或类似的东西。我以前从未编写过Powershell脚本,所以我完全迷失了。我需要更改这些文件编码,有数百个,我不想自己一个接一个地做。
实际上我使用的是Windows 7附带的2.0版本。
提前致谢!
编辑1
我尝试了以下代码,由@LarsTruijens和其他帖子建议:
$Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding($False)
foreach ($i in Get-ChildItem -Recurse) {
if ($i.PSIsContainer) {
continue
}
$dest = $i.Fullname.Replace($PWD, "some_folder")
if (!(Test-Path $(Split-Path $dest -Parent))) {
New-Item $(Split-Path $dest -Parent) -type Directory
}
$content = get-content $i
[System.IO.File]::WriteAllLines($dest, $content, $Utf8NoBomEncoding)
}
这给了我一个异常,抱怨WriteAllLines的一个参数:"Exception on calling 'WriteAllLines' with 3 arguments. The value can't be null". Parameter name: contents
。但是,该脚本会创建所有文件夹。但它们都是空的。
编辑2
关于此错误的一个有趣的事情是“content”参数不为null。如果我输出$ content变量的值(使用Write-host),则存在行。那么为什么它传递给WriteAllLines方法时变为null?
编辑3
我已经为变量添加了内容检查,因此脚本现在看起来像这样:
$Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding($False)
foreach ($i in Get-ChildItem -Recurse) {
if ($i.PSIsContainer) {
continue
}
$dest = $i.Fullname.Replace($PWD, "some_folder")
if (!(Test-Path $(Split-Path $dest -Parent))) {
New-Item $(Split-Path $dest -Parent) -type Directory
}
$content = get-content $i
if ( $content -ne $null ) {
[System.IO.File]::WriteAllLines($dest, $content, $Utf8NoBomEncoding)
}
else {
Write-Host "No content from: $i"
}
}
现在每次迭代都会返回“No content from:$ i”消息,但该文件不为空。还有一个错误:Get-content: can't find the path 'C:\root\FILENAME.php' because it doesn't exists.
似乎它试图在根目录而不是子文件夹中找到文件。它似乎能够从子文件夹中获取文件名,但尝试从root文件中读取它。
编辑4 - 最终工作版
经过一番挣扎并遵循我来到这里的建议,特别是@LarsTruijens和@AnsgarWiechers,我终于成功了。我不得不改变从$ PWD获取目录的方式,并为文件夹设置一些固定名称。在那之后,它运作得很好。
对于任何可能感兴趣的人来说,
$Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding($False)
$source = "path"
$destination = "some_folder"
foreach ($i in Get-ChildItem -Recurse -Force) {
if ($i.PSIsContainer) {
continue
}
$path = $i.DirectoryName -replace $source, $destination
$name = $i.Fullname -replace $source, $destination
if ( !(Test-Path $path) ) {
New-Item -Path $path -ItemType directory
}
$content = get-content $i.Fullname
if ( $content -ne $null ) {
[System.IO.File]::WriteAllLines($name, $content, $Utf8NoBomEncoding)
} else {
Write-Host "No content from: $i"
}
}
答案 0 :(得分:4)
你没有按照here中的完整答案。你忘记了WriteAllLines部分。
$Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding($False)
foreach ($i in Get-ChildItem -Recurse) {
if ($i.PSIsContainer) {
continue
}
$dest = $i.Fullname.Replace($PWD, "some_folder")
if (!(Test-Path $(Split-Path $dest -Parent))) {
New-Item $(Split-Path $dest -Parent) -type Directory
}
$content = get-content $i
[System.IO.File]::WriteAllLines($dest, $content, $Utf8NoBomEncoding)
}
答案 1 :(得分:2)
答案的一半在错误消息中。它告诉您Encoding参数接受的可能值,其中一个是utf8。
... out-file -encoding utf8
答案 2 :(得分:0)
cd c:\MyDirectoryWithCrazyCharacterEncodingAndUnicode
复制并通过Powershell窗口中的脚本
foreach($FileNameInUnicodeOrWhatever in get-childitem)
{
$FileName = $FileNameInUnicodeOrWhatever.Name
$TempFile = "$($FileNameInUnicodeOrWhatever.Name).ASCII"
get-content $FileNameInUnicodeOrWhatever | out-file $FileNameInUnicodeOrWhatever -Encoding ASCII
remove-item $FileNameInUnicodeOrWhatever
rename-item $TempFile $FileNameInUnicodeOrWhatever
write-output $FileNameInUnicodeOrWhatever "converted to ASCII ->" $TempFile
}
答案 3 :(得分:0)
我已经做了一些修复
并将所有内容打包到cmdlet中:
<#
.SYNOPSIS
Encode-Utf8
.DESCRIPTION
Re-Write all files in a folder in UTF-8
.PARAMETER Source
directory path to recursively scan for files
.PARAMETER Destination
directory path to write files to
#>
[CmdletBinding(DefaultParameterSetName="Help")]
Param(
[Parameter(Mandatory=$true, Position=0, ParameterSetName="Default")]
[string]
$Source,
[Parameter(Mandatory=$true, Position=1, ParameterSetName="Default")]
[string]
$Destination,
[Parameter(Mandatory=$false, Position=0, ParameterSetName="Help")]
[switch]
$Help
)
if($PSCmdlet.ParameterSetName -eq 'Help'){
Get-Help $MyInvocation.MyCommand.Definition -Detailed
Exit
}
if($PSBoundParameters['Debug']){
$DebugPreference = 'Continue'
}
$Source = Resolve-Path $Source
if (-not (Test-Path $Destination)) {
New-Item -ItemType Directory -Path $Destination -Force | Out-Null
}
$Destination = Resolve-Path $Destination
$Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding($False)
foreach ($i in Get-ChildItem $Source -Recurse -Force) {
if ($i.PSIsContainer) {
continue
}
$path = $i.DirectoryName.Replace($Source, $Destination)
$name = $i.Fullname.Replace($Source, $Destination)
if ( !(Test-Path $path) ) {
New-Item -Path $path -ItemType directory
}
$content = get-content $i.Fullname
if ( $content -ne $null ) {
[System.IO.File]::WriteAllLines($name, $content, $Utf8NoBomEncoding)
} else {
Write-Host "No content from: $i"
}
}
答案 4 :(得分:0)
这种方法会在将文件从当前目录复制到UTF-8之前创建整个文件夹结构。 最后,我们交换父目录名称。
$destination = "..\DestinationFolder"
Remove-item $destination -Recurse -Force
robocopy $PWD $destination /e /xf *.*
foreach($i in Get-ChildItem -Recurse) {
if ($i.PSIsContainer) {
continue
}
$originalContent = $i.Fullname
$dest = $i.Fullname.Replace($PWD, $destination)
if (!(Test-Path $(Split-Path $dest -Parent))) {
New-Item $(Split-Path $dest -Parent) -type Directory
}
get-content $originalContent | out-file -encoding utf8 -filepath $dest
}
答案 5 :(得分:0)
当我需要UTF8编码大量的日志文件时,我改编了一些代码片段。
注意!不应与-recurse
一起使用write-host " "
$sourcePath = (get-location).path # Use current folder as source.
# $sourcePath = "C:\Source-files" # Use custom folder as source.
$destinationPath = (get-location).path + '\Out' # Use "current folder\Out" as target.
# $destinationPath = "C:\UTF8-Encoded" # Set custom target path
$cnt = 0
write-host "UTF8 convertsation from " $sourcePath " to " $destinationPath
if (!(Test-Path $destinationPath))
{
write-host "(Note: target folder created!) "
new-item -type directory -path $destinationPath -Force | Out-Null
}
Get-ChildItem -Path $sourcePath -Filter *.txt | ForEach-Object {
$content = Get-Content $_.FullName
Set-content (Join-Path -Path $destinationPath -ChildPath $_) -Encoding UTF8 -Value $content
$cnt++
}
write-host " "
write-host "Totally " $cnt " files converted!"
write-host " "
pause
答案 6 :(得分:-1)
使用:
foreach ($i in Get-ChildItem -Path $source -Recurse -Force) {
仅使用子文件夹$source
中的文件。