web-dev-qa-db-ja.com

PowerShellでテキストファイルを再帰的にUTF-8に変換する

他のフォルダを含むテキストファイルを含むフォルダがあり、これらにもいくつかのテキストファイルが含まれています。 PowerShellでこれらすべてのファイルを再帰的にUTF-8エンコーディングに変換し、このプロセス中にフォルダー構造を保持する必要があります。私はこれを試しました:

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

ただし、機能せず、フォルダの階層を再現できません。この問題にどのように対処しますか?

7
Roman

これを試してください。

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が見つかると、$destsome_folder\2\file.txtが表示されます。

最初のifブロックが存在するため、ディレクトリを変換しようとはしません。

ディレクトリがまだ存在しない場合は作成する必要があります-私はもともとそれを忘れていました。


BOMなしのUTF8が必要な場合は、get-content $i | out-file -encoding utf8 -filepath $dest行を次の( source )に置き換えます。

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

これは、ファイルを再度書き込む前にファイル全体をメモリに読み込むため、大きなファイルの場合はあまりパフォーマンスが良くない場合があることに注意してください。効率が必要な場合は、1行ずつ、または一度に特定のバイト数を読み取ることができます。ただし、私はむしろその時点でC#で簡単なプログラムを記述したいだけです(とにかくPSで.NET関数を使用しているためです)。

13
Bob
  • ファイルとフォルダを許可します
  • ファイル拡張子にとらわれない
  • 宛先がパスと等しい場合、元のファイルを上書きします
  • パラメータとしてのエンコーディング

使用法:& "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
1
JDennis