7

У меня есть папка с текстовыми файлами, которая включает в себя другие папки, и они также содержат некоторые текстовые файлы. Мне нужно рекурсивно преобразовать все эти файлы в кодировку UTF-8 в PowerShell и сохранить структуру папок во время этого процесса. Я попробовал это:

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

Но это не работает, оно не может воспроизвести иерархию папок. Как мне справиться с этой проблемой?

2 ответа2

13

Попробуй это.

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 есть, поэтому вы не пытаетесь конвертировать каталог.

Каталоги должны быть созданы, если они еще не существуют - я изначально забыл это.


Если вы хотите 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 # к этому моменту (так как в любом случае вы будете использовать функции .NET в PS).

1
  • Позволяет для файлов и папок
  • Расширение файла agnostic
  • Перезаписывает исходный файл, если место назначения равно пути
  • Кодировка как параметр

Использование: & "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

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .