Windows에서 파일 이름 인코딩 결정 및 변경


1

Windows 서버에 이름에 특정 악센트 문자가있는 파일이 있습니다. Windows 탐색기에서 파일이 정상적으로 표시되지만 기본 설정으로 명령 프롬프트에서 'dir'을 실행하면 대체 문자가 표시됩니다.

예를 들어, 문자 öo"목록 과 같이 표시됩니다 . 인코딩 / 코드 페이지가 충돌하여 SMB를 통해 다른 플랫폼에서 이러한 파일에 액세스 할 때 문제가 발생합니다. 모든 파일에 문제가있는 것은 아니며 문제 파일의 출처를 모릅니다.

예:

E:\folder\files>dir
 Volume in drive E is data
 Volume Serial Number is 5841-C30E

 Directory of E:\folder\files  

07/05/2016  07:46 PM    <DIR>          .
07/05/2016  07:46 PM    <DIR>          ..
12/01/2015  11:12 AM            14,105 file with o" character.xlsx
01/22/2015  05:30 PM            11,598 file with correct ö character.xlsx
               2 File(s)         25,703 bytes
               2 Dir(s)  2,727,491,600,384 bytes free

파일 및 디렉토리 이름을 변경했지만 아이디어를 얻을 수 있습니다.

어떻게 이런 식으로 이름을 얻었는지 알 수 있습니까? 다른 플랫폼이나 도구를 사용하여 복사하거나 만들었습니까?

모든 문제 파일을 배치하고 이름을 바꾸려면 어떻게해야합니까? GUI 이름 바꾸기 유틸리티 몇 가지를 살펴 봤지만 문제가 표시되지 않고 Windows 탐색기에 표시된 이름으로 만 작동합니다.

드라이브의 파일 시스템이 ReFS인데, 이와 관련이있을 수 있습니까?

편집 : PowerShell 명령 실행

Y:\test>powershell -c Get-ChildItem ^|ForEach-Object {$x=$_.Name; For ($i=0;$i
-lt $x.Length; $i++) {\"{0} {1} {2}\" -f $x,$x[$i],[int]$x[$i]}}
file with o¨ character.xlsx o 111
file with o¨ character.xlsx ¨ 776

관련 부분 만 보이도록 정리했습니다.

실제로 combining diaeresis세로 따옴표가 아닌 것처럼 보입니다 . 내가 이해하는 것처럼 유니 코드 정규화에 대해 이야기 할 때와 마찬가지로.


사용 chcpcmd적절한 코드 페이지를 설정하는 쉘. chcp- 활성 콘솔 코드 페이지 변경을 참조하십시오 . 기본 코드 페이지는 Windows 로캘에 의해 결정됩니다.
DavidPostill

nixer하십시오 편집 질문을하고 추가 실제 등의 예를 dir( Copy & Pastecmd창). @DavidPostill chcp은 충분하지 않습니다. 문자 ( 라틴어 소문자 O와 Diaeresis ) 대신 정식 또는 호환성 분해 o ̈ ( U+006F 라틴 문자 소문자 O 다음에 U+0308 Diaeresis 결합 ) 가 표시되는 것 같습니다 . öU+00F6
JosefZ

@DavidPostill @JosefZ 함께 놀았 chcp지만 이름이 올바르게 표시되지 않았습니다. 그냥와 "같은 다른 문자로 변경합니다 ?. 따라서 원래 분해되어 저장된 것으로 보이며 명령 프롬프트에 실제 이름이 표시되고 Windows 탐색기는이를 즉시 다시 결합합니다.
nixer

"이 문자가 파일 이름 , 경로 및 네임 스페이스 기사에 의해 예약되어 있기 때문에 파일 이름에 (인용 부호) 가 있다고 믿을 수 없습니다 . 파일 시스템 NTFSReFS파일 시스템 모두에 적용해야 합니다. oneliner 실행하십시오 powershell -c Get-ChildItem ^|ForEach-Object {$x=$_.Name; For ($i=0;$i -lt $x.Length; $i++) {\"{0} {1} {2}\" -f $x,$x[$i],[int]$x[$i]}}대신 dir하고 편집 다시 Copy&Paste에만 해당 출력 라인 (숫자는 충분합니다). 참고 "코드는 34 입니다.
JosefZ

답변:


1

다음 간단한 Powershell 스크립트를 사용하여 문제를 재현 할 수 있습니다

$RatedName = "šöü"                            # set sample string
$FormDName = $RatedName.Normalize("FormD")    # its Canonical Decomposition
$FormCName = $FormDName.Normalize("FormC")    #     followed by Canonical Composition
                                              # list each string character by character
($RatedName,$FormDName,$FormCName) | ForEach-Object {
    $charArr = [char[]]$_ 
    "$_"      # display string in new line for better readability
              # display each character together with its Unicode codepoint
    For( $i=0; $i -lt $charArr.Count; $i++ ) { 
        $charInt = [int]$charArr[$i]
        # next "Try-Catch-Finally" code snippet adopted from my "Alt KeyCode Finder"
        #                                       http://superuser.com/a/1047961/376602
        Try {    
            # Get-CharInfo module downloadable from http://poshcode.org/5234
            #        to add it into the current session: use Import-Module cmdlet
            $charInt | Get-CharInfo |% {
                $ChUCode = $_.CodePoint
                $ChCtgry = $_.Category
                $ChDescr = $_.Description
            }
        }
        Catch {
            $ChUCode = "U+{0:x4}" -f $charInt
            if ( $charInt -le 0x1F -or ($charInt -ge 0x7F -and $charInt -le 0x9F)) 
                 { $ChCtgry = "Control" } else { $ChCtgry = "" }
            $ChDescr = ""
        }
        Finally { $ChOut = $charArr[$i] }
        "{0} {1,-2} {2} {3,5} {4}" -f $i, $charArr[$i], $ChUCode, $charInt, $ChDescr
    }
}
# create sample files
$RatedName | Out-File "D:\test\1097217Rated$RatedName.txt" -Encoding utf8
$FormDName | Out-File "D:\test\1097217FormD$FormDName.txt" -Encoding utf8
$FormCName | Out-File "D:\test\1097217FormC$FormCName.txt" -Encoding utf8


""                                 # very artless draft of possible solution
Get-ChildItem "D:\test\1097217*" | ForEach-Object {
    $y = $_.Name.Normalize("FormC")
    if ( $y.Length -ne $_.Name.Length ) {
        Rename-Item -NewName $y -LiteralPath $_ -WhatIf
    } else {
        "       : file name is already normalized $_"
    }
}

위의 스크립트는 다음과 같이 업데이트 됩니다. 1st 는 구성 / 분해 된 유니 코드 문자, 즉 해당 유니 코드 이름에 대한 추가 정보를 표시합니다 ( Get-CharInfo 모듈 참조 ). 두 번째 로 가능한 솔루션의 초안 이 포함되어 있습니다.
출력 에서 cmd프롬프트 :

==> powershell -c D:\PShell\SU\1097217.ps1
šöü
0 š  U+0161   353 Latin Small Letter S With Caron
1 ö  U+00F6   246 Latin Small Letter O With Diaeresis
2 ü  U+00FC   252 Latin Small Letter U With Diaeresis
šöü
0 s  U+0073   115 Latin Small Letter S
1 ̌  U+030C   780 Combining Caron
2 o  U+006F   111 Latin Small Letter O
3 ̈  U+0308   776 Combining Diaeresis
4 u  U+0075   117 Latin Small Letter U
5 ̈  U+0308   776 Combining Diaeresis
šöü
0 š  U+0161   353 Latin Small Letter S With Caron
1 ö  U+00F6   246 Latin Small Letter O With Diaeresis
2 ü  U+00FC   252 Latin Small Letter U With Diaeresis

       : file name is already normalized D:\test\1097217FormCšöü.txt
What if: Performing the operation "Rename File" on target "Item: D:\test\1097217
FormDšöü.txt Destination: D:\test\1097217FormDšöü.txt".
       : file name is already normalized D:\test\1097217Ratedšöü.txt

==> dir /b D:\test\1097217*
1097217FormCšöü.txt
1097217FormDšöü.txt
1097217Ratedšöü.txt

실제로 위의 dir출력 창과 같 1097217FormDsˇo¨u¨.txt으며 cmd유니 코드 인식 브라우저 는 위에 나열된 문자열작성 하지만 유니 코드 분석기 는 최신 이미지뿐만 아니라 문자를 실제로 표시합니다.

악센트 결합

그러나 다음 예제는 전체 너비에서 문제를 보여줍니다. for루프가 악센트를 결합 하여 일반적인 악센트로 변경 합니다.

==> for /F "delims=" %G in ('dir /b /S D:\test\1097217*') do @echo %~nxG & dir /B %~fG
1097217FormCšöü.txt
1097217FormCšöü.txt
1097217FormDsˇo¨u¨.txt
File Not Found
1097217Ratedšöü.txt
1097217Ratedšöü.txt

==>

가능한 해결책에 대한 매우 예술적인 초안 이 있습니다 (위 출력 참조).

""                                 # very artless draft of possible solution
Get-ChildItem "D:\test\1097217*" | ForEach-Object {
    $y = $_.Name.Normalize("FormC")
    if ( $y.Length -ne $_.Name.Length ) {
        Rename-Item -NewName $y -LiteralPath $_ -WhatIf
    } else {
        "       : file name is already normalized $_"
    }
}

( ToDo : Rename-Item필요한 경우에만 호출 ) :

Get-ChildItem "D:\test\1097217*" | ForEach-Object {
    $y = $_.Name.Normalize("FormC")
    if ($true) {                                         ### ToDo
        Rename-Item -NewName $y -LiteralPath $_ -WhatIf
    }
}

그리고 그 출력 (다시, 여기에 구성된 문자열 로 렌더링 되며 아래 이미지는 cmd바이어스되지 않은 창 모양을 보여줍니다 ) :

What if: Performing the operation "Rename File" on target "Item: D:\test\1097217
FormCšöü.txt Destination: D:\test\1097217FormCšöü.txt".
What if: Performing the operation "Rename File" on target "Item: D:\test\1097217
FormDšöü.txt Destination: D:\test\1097217FormDšöü.txt".
What if: Performing the operation "Rename File" on target "Item: D:\test\1097217
Ratedšöü.txt Destination: D:\test\1097217Ratedšöü.txt".

악센트 결합

업데이트 된 cmd출력

업데이트 된 cmd 출력


아주 좋은 형사 일! 현재 PowerShell 스크립트는 문제를 해결하기위한 최상의 옵션 인 것 같습니다. 분해 된 유니 코드를 이해하는 파일 이름 바꾸기 유틸리티를 찾지 못했습니다.
nixer

@nixer 업데이트 된 답변 참고 : 부분 이름을 바꾸면 도움이 될 수 있습니다!
JosefZ

초안 스크립트는 현재 디렉토리에서 훌륭하게 작동합니다. 재귀 적으로 이름을 바꾸도록 수정하려고했지만 PowerShell 기술이 좋지 않아 아직 할 수 없었습니다.
nixer

@nixer는 추가 요청에 대해 stackoverflow를 검색하십시오.
JosefZ

0

지역 제어판 의이 탭에서 문제가 발생합니다 .

여기에 이미지 설명을 입력하십시오

이것은 화면 글꼴뿐만 아니라 파일 시스템 (기본적으로 설명하는 방식)에도 영향을줍니다.

스크린 샷은 내 컴퓨터에서 가져온 것입니다. 로케일을 영어로 변경하면 ľôščťž 파일 이름 과 같은 모든 특수 슬로바키아어 국가 문자 가 쓰레기가되고 일부는 해결 방법없이 파일을 열지 못하게합니다 (코드 페이지가 되돌릴 때까지). . 그러나이 문제는 áíé여러 언어에서 볼 수있는 보다 일반적인 자국 문자로는 나타나지 않습니다 .

이는 다른 로케일로 작성된 백업을 열려고하는 등 일부 오프라인 매체에도 영향을줍니다.

가장 쉬운 해결책은 리소스에 액세스하는 모든 컴퓨터에서 동일한 로캘을 유지하는 것입니다.

해결 방법은 다른 로케일을 가진 시스템을 판별하고 해당 시스템과 모든 파일 이름에서 모든 국가 문자 (예 : č-> c, ž-> z) 의 대량 교체를 수행하는 시스템을 판별하는 것입니다 . Total Commander (파일 관리자)는 전체 디렉토리 트리에서 이러한 각 쌍을 한 번에 교체 할 수 있습니다. 그런 다음 해당 머신을 영어로 되돌 리거나 (자체 백업을 읽지 못할 수도 있음) 사용자가 파일 이름에 자국 문자를 사용하지 않도록 요청하여 그대로 유지할 수 있습니다.

(하지만 그 전에 한 가지 시도를 할 수 있습니다. chcp다른 로케일로 시스템에서 실행 하고, 사용중인 코드 페이지 (예 : 852)를 학습 한 다음로 다른 시스템에서 시도해보십시오 chcp 852. 문제가 만족스럽게 해결되는지 여부는 확실하지 않습니다.)


팁 고마워. 여러 로케일을 시도했지만 그중 어느 것도 분해에 영향을 미치지 않았으며 문제를 재현 할 수 없었습니다. 또한 몇 가지 파일 이름 바꾸기 유틸리티를 사용해 보았지만 분해로 작동하는 방법을 알지 못했습니다. 이로 인해 파일이 엉망이 된 도구를 사용하여 다른 컴퓨터 또는 플랫폼에서 파일이 전송되었다고 믿게되었습니다. 나는 여전히이 문제가있는 모든 파일을 찾아서 수정할 수있는 대량 이름 바꾸기를 찾고 있습니다.
nixer

@nixer – 벌크 이름 변경과 관련하여 이미 수행 방법을 썼습니다. 자세한 내용 : TCMD 내에서 다중 이름 변경 도구 (주 메뉴에서 액세스 가능)의 검색 및 바꾸기를 사용하십시오. 이전에 조심해서 백업을 생성하더라도 잘못된 이름 변경 순서를 사용하여 논리적으로 파악할 수 있습니다. 최선의 선택 (가능한 경우)은 파일을 사용하여 파일을 업로드 한 사람을 결정하고 해당 사용자의 컴퓨터에 집중하는 것입니다.
miroxlav

0

JosefZ의 스크립트를 기반으로 다음은 재귀 적으로 작동하는 수정 된 버전입니다.

Get-ChildItem "X:\" -Recurse | ForEach-Object {
    $y = $_.Name.Normalize("FormC")
    $file = $_.Fullname
    if ( $y.Length -ne $_.Name.Length ) {
        Rename-Item -LiteralPath "$file" -NewName "$y" -WhatIf
        Write-Host "renamed file $file"
    }
}

-WhatIf테스트 후 제거하십시오 . 너무 길었던 경로에 문제가 있었지만 다른 게시물의 주제입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.