[c#] 임의의 문자열에서 유효한 Windows 파일 이름을 만드는 방법은 무엇입니까?

파일 이름으로 사용하려는 “Foo : Bar”와 같은 문자열이 있지만 Windows에서는 파일 이름에 “:”문자를 사용할 수 없습니다.

“Foo : Bar”를 “Foo- Bar”와 같은 것으로 바꾸는 방법이 있습니까?



답변

다음과 같이 시도하십시오.

string fileName = "something";
foreach (char c in System.IO.Path.GetInvalidFileNameChars())
{
   fileName = fileName.Replace(c, '_');
}

편집하다:

GetInvalidFileNameChars()10 개 또는 15 개의 문자를 반환 하므로 StringBuilder간단한 문자열 대신 a를 사용하는 것이 좋습니다. 원래 버전은 더 오래 걸리고 더 많은 메모리를 소비합니다.


답변

fileName = fileName.Replace(":", "-") 

그러나 “:”는 Windows에서 유일한 잘못된 문자가 아닙니다. 또한 다음을 처리해야합니다.

/, \, :, *, ?, ", <, > and |

이들은 System.IO.Path.GetInvalidFileNameChars ();에 포함되어 있습니다.

또한 (Windows에서는) “.” 파일 이름에서 유일한 문자가 될 수 없습니다 ( “.”, “..”, “…”등 모두 유효하지 않음). “.”로 파일 이름을 지정할 때주의하십시오. 예를 들면 다음과 같습니다.

echo "test" > .test.

“.test”라는 파일을 생성합니다.

마지막으로, 정말로 제대로하고 싶다면 찾아봐야 할 특별한 파일 이름이 있습니다. Windows에서는 다음과 같은 파일을 만들 수 없습니다.

CON, PRN, AUX, CLOCK$, NUL
COM0, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9
LPT0, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, and LPT9.


답변

이것은 더 효율적이지는 않지만 더 재미 있습니다. 🙂

var fileName = "foo:bar";
var invalidChars = System.IO.Path.GetInvalidFileNameChars();
var cleanFileName = new string(fileName.Where(m => !invalidChars.Contains(m)).ToArray<char>());


답변

을 기반으로 최적화 된 버전을 원하는 사람이 있으면 StringBuilder이것을 사용하십시오. rkagerer의 트릭을 옵션으로 포함합니다.

static char[] _invalids;

/// <summary>Replaces characters in <c>text</c> that are not allowed in 
/// file names with the specified replacement character.</summary>
/// <param name="text">Text to make into a valid filename. The same string is returned if it is valid already.</param>
/// <param name="replacement">Replacement character, or null to simply remove bad characters.</param>
/// <param name="fancy">Whether to replace quotes and slashes with the non-ASCII characters ” and ⁄.</param>
/// <returns>A string that can be used as a filename. If the output string would otherwise be empty, returns "_".</returns>
public static string MakeValidFileName(string text, char? replacement = '_', bool fancy = true)
{
    StringBuilder sb = new StringBuilder(text.Length);
    var invalids = _invalids ?? (_invalids = Path.GetInvalidFileNameChars());
    bool changed = false;
    for (int i = 0; i < text.Length; i++) {
        char c = text[i];
        if (invalids.Contains(c)) {
            changed = true;
            var repl = replacement ?? '\0';
            if (fancy) {
                if (c == '"')       repl = '”'; // U+201D right double quotation mark
                else if (c == '\'') repl = '’'; // U+2019 right single quotation mark
                else if (c == '/')  repl = '⁄'; // U+2044 fraction slash
            }
            if (repl != '\0')
                sb.Append(repl);
        } else
            sb.Append(c);
    }
    if (sb.Length == 0)
        return "_";
    return changed ? sb.ToString() : text;
}


답변

다음을 사용 Linq하는 허용되는 답변의 버전은 다음과 같습니다 Enumerable.Aggregate.

string fileName = "something";

Path.GetInvalidFileNameChars()
    .Aggregate(fileName, (current, c) => current.Replace(c, '_'));


답변

Diego는 올바른 해결책을 가지고 있지만 거기에 아주 작은 실수가 하나 있습니다. 사용중인 string.Replace의 버전은 string.Replace (char, char) 여야하며 string.Replace (char, string)가 없습니다.

답변을 수정할 수 없거나 약간만 변경했을 것입니다.

따라서 다음과 같아야합니다.

string fileName = "something";
foreach (char c in System.IO.Path.GetInvalidFileNameChars())
{
   fileName = fileName.Replace(c, '_');
}


답변

Diego의 대답에 약간의 비틀기가 있습니다.

유니 코드를 두려워하지 않는 경우 유효하지 않은 문자를 유사한 유효한 유니 코드 기호로 대체하여 좀 더 충실도를 유지할 수 있습니다. 다음은 목재 절단 목록과 관련된 최근 프로젝트에서 사용한 코드입니다.

static string MakeValidFilename(string text) {
  text = text.Replace('\'', '’'); // U+2019 right single quotation mark
  text = text.Replace('"',  '”'); // U+201D right double quotation mark
  text = text.Replace('/', '⁄');  // U+2044 fraction slash
  foreach (char c in System.IO.Path.GetInvalidFileNameChars()) {
    text = text.Replace(c, '_');
  }
  return text;
}

1⁄2” spruce.txt대신 다음 과 같은 파일 이름이 생성 됩니다.1_2_ spruce.txt

예, 실제로 작동합니다.

Explorer 샘플

경고 Emptor

이 트릭이 NTFS에서 작동한다는 것을 알고 있었지만 FAT 및 FAT32 파티션에서도 작동한다는 사실에 놀랐습니다. 때문에의 그 긴 파일 이름이 되는 유니 코드로 저장 심지어 까지 다시 윈도우 95 / NT 등. 나는 Win7, XP, 심지어 Linux 기반 라우터에서도 테스트를했는데 괜찮았다. DOSBox 내부에서도 똑같이 말할 수 없습니다.

즉, 당신이 이것에 열광하기 전에 추가 충실도가 정말로 필요한지 고려하십시오. 유니 코드와 유사한 모양은 사람이나 오래된 프로그램을 혼동 할 수 있습니다. 예를 들어 코드 페이지에 의존하는 오래된 OS가 있습니다.