Рекурсивное преобразование текстовых файлов в UTF-8 в PowerShell

7

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

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

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

Римский
источник
1
Какая версия PowerShell это? В той, которая пришла с (моей копией) Win7 (v2?), Есть, Get-ChildItemно нет Get-Children...
Боб
Это было опечатка, я исправил это.
Роман

Ответы:

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).

боб
источник
Это не работает для меня. В строке 6 указано, что произошла ошибка ($ dest и т. Д.). Он пытается вызвать метод с нулевым аргументом, и это неправильно.
Роман
Я не использовал PowerShell достаточно, по-видимому .. цитаты не были необходимы. И каталоги должны быть созданы, если они еще не существуют. Я отредактировал это, чтобы исправить это, и фактически протестировал это на этот раз (больше чем просто повторение путей). Не уверен, как вы получили эту ошибку, однако, что вы заменили some_folder?
Боб
@Roman, вам нужно определить $ PWD, иначе $ PWD равно NULL. Если ваши файлы хранятся в «X: \ txt_Files» и вы хотите сохранить преобразованные файлы в «X: \ UTF_Files», то добавьте: $ PWD = «X: \ txt_Files» и замените «some_folder» на «X: \». UTF_Files "
Мартин
@Martin $PWDдолжен автоматически ссылаться на текущий рабочий каталог. "some_folder"должен быть заменен на соответствующую папку.
Боб
@Bob Это сработало, как и ожидалось, за исключением того факта, что оно выдает некоторые ошибки о некоторых несуществующих файлах, потому что оно пытается найти файл в недопустимом месте. Что если я захочу конвертировать файлы в UTF-8 без спецификации? Что я должен добавить к этому сценарию?
darksoulsong
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
JDennis
источник