在 PowerShell 中将文本文件递归转换为 UTF-8

在 PowerShell 中将文本文件递归转换为 UTF-8

我有一个包含文本文件的文件夹,其中包含其他文件夹,这些文件夹也包含一些文本文件。我需要在 PowerShell 中将所有这些文件递归转换为 UTF-8 编码,并在此过程中保留文件夹结构。我试过这个:

foreach( $i in get-childitem -recurse -name ) {
    get-content $i | out-file -encoding utf8 -filepath some_folder/$i
}

但它不起作用,它无法重现文件夹的层次结构。我该如何解决这个问题?

答案1

尝试一下这个。

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
    }

    get-content $i | out-file -encoding utf8 -filepath $dest
}

它会获取文件的完整路径,并将当前目录替换为您想要的目录。例如,您在目录C:\1\( $PWD = C:\1\) 中运行此命令。如果它找到文件C:\1\2\file.txt,它会为您$dest提供some_folder\2\file.txt

第一个 if 块在那里,所以您不会尝试转换目录。

如果目录不存在,则必须创建它们 - 我最初忘记了这一点。


如果您想要无 BOM 的 UTF8,请将get-content $i | out-file -encoding utf8 -filepath $dest以下行替换为(来源):

$filecontents = Get-Content $i
$Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding($False)
[System.IO.File]::WriteAllLines($i, $filecontents, $Utf8NoBomEncoding)

请注意,对于较大的文件,这可能不是非常高效,因为它会先将整个文件读入内存,然后再将其再次写入。如果需要提高效率,可以逐行读取,甚至可以一次读取特定数量的字节。但是,到那时我宁愿用 C# 编写一个快速程序(因为无论如何你都会在 PS 中使用 .NET 函数)。

答案2

  • 允许文件和文件夹
  • 不受文件扩展名限制
  • 如果目标等于路径,则覆盖原始文件
  • 编码为参数

用法:&“TextEncoding.ps1”-path“c:\windows\temps\folder1”-encoding“UTF8”

这是我创建的脚本:

[CmdletBinding()]
param(  
    [Parameter(Mandatory=$true)]
    [string]$path,
    [Parameter(Mandatory=$false)]
    [string]$dest = $path,
    [Parameter(Mandatory=$true)]
    [string]$encoding
)

function Set-Encoding(){

    #ensure it is a valid path
    if(-not(Test-Path -Path $path)){

        throw "File or directory not found at {0}" -f $path
    }

    #if the path is a file, else a directory
    if(Test-Path $path -PathType Leaf){

        #if the provided path equals the destination
        if($path -eq $dest){

            #get file extension
            $ext = [System.IO.Path]::GetExtension($path)

            #create destination
            $dest = $path.Replace([System.IO.Path]::GetFileName($path), ("temp_encoded{0}" -f $ext))

            #output to file with encoding
            Get-Content $path | Out-File -FilePath $dest -Encoding $encoding -Force

            #copy item to original path to overwrite (note move-item loses encoding)
            Copy-Item -Path $dest -Destination $path -Force -PassThru | ForEach-Object { Write-Output -inputobject ("{0} encoded {1}" -f $encoding, $_) }

            #remove the extra file
            Remove-Item $dest   

        }else{

            #output to file with encoding
            Get-Content $path | Out-File -FilePath $dest -Encoding $encoding -Force     

        }

    }else{

        #get all the files recursively
        foreach($i in Get-ChildItem -Path $path -Recurse) {


            if ($i.PSIsContainer) {
                continue
            }

            #get file extension
            $ext = [System.IO.Path]::GetExtension($i)

            #create destination
            $dest = "$path\temp_encoded{0}" -f $ext

            #output to file with encoding
            Get-Content $i.FullName | Out-File -FilePath $dest -Encoding $encoding -Force

            #copy item to original path to overwrite (note move-item loses encoding)
            Copy-Item -Path $dest -Destination $i.FullName -Force -PassThru | ForEach-Object { Write-Output -inputobject ("{0} encoded {1}" -f $encoding, $_) }

            #remove the extra file
            Remove-Item $dest

        }

    }

}

Set-Encoding

答案3

我必须稍微修改一下这里的脚本,才能在我的 W10/PS 5.1 上运行它

Get-ChildItem -Include *.php -Recurse | ForEach-Object {
    $file = $_.FullName

    $mustReWrite = $false
    # Try to read as UTF-8 first and throw an exception if
    # invalid-as-UTF-8 bytes are encountered.
    try
    {
        [IO.File]::ReadAllText($file,[Text.Utf8Encoding]::new($false, $true))
    }
    catch [System.Text.DecoderFallbackException]
    {
        # Fall back to Windows-1250
        $content = [IO.File]::ReadAllText($file,[Text.Encoding]::GetEncoding(1250))
        $mustReWrite = $true
    }

    # Rewrite as UTF-8 without BOM (the .NET frameworks' default)
    if ($mustReWrite)
    {
        Write "Converting from 1250 to UTF-8"
        [IO.File]::WriteAllText($file, $content)
    }
    else
    {
        Write "Already UTF-8-encoded"
    } }

相关内容