program tip

Windows에서 파일 이름 유효성 검사

radiobox 2021. 1. 5. 07:55
반응형

Windows에서 파일 이름 유효성 검사


public static boolean isValidName(String text)
{
    Pattern pattern = Pattern.compile("^[^/./\\:*?\"<>|]+$");
    Matcher matcher = pattern.matcher(text);
    boolean isMatch = matcher.matches();
    return isMatch;
}

이 방법은 Windows에서 유효한 파일 이름을 보장합니까?


이전에 인용 된 MSDN 문서에 지정된 요구 사항을 고려할 때 다음 정규식이 꽤 잘 작동합니다.

public static boolean isValidName(String text)
{
    Pattern pattern = Pattern.compile(
        "# Match a valid Windows filename (unspecified file system).          \n" +
        "^                                # Anchor to start of string.        \n" +
        "(?!                              # Assert filename is not: CON, PRN, \n" +
        "  (?:                            # AUX, NUL, COM1, COM2, COM3, COM4, \n" +
        "    CON|PRN|AUX|NUL|             # COM5, COM6, COM7, COM8, COM9,     \n" +
        "    COM[1-9]|LPT[1-9]            # LPT1, LPT2, LPT3, LPT4, LPT5,     \n" +
        "  )                              # LPT6, LPT7, LPT8, and LPT9...     \n" +
        "  (?:\\.[^.]*)?                  # followed by optional extension    \n" +
        "  $                              # and end of string                 \n" +
        ")                                # End negative lookahead assertion. \n" +
        "[^<>:\"/\\\\|?*\\x00-\\x1F]*     # Zero or more valid filename chars.\n" +
        "[^<>:\"/\\\\|?*\\x00-\\x1F\\ .]  # Last char is not a space or dot.  \n" +
        "$                                # Anchor to end of string.            ", 
        Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE | Pattern.COMMENTS);
    Matcher matcher = pattern.matcher(text);
    boolean isMatch = matcher.matches();
    return isMatch;
}

이 정규식은 파일 이름 길이에 제한을 두지 않지만 실제 파일 이름은 플랫폼에 따라 260 자 또는 32767 자로 제한 될 수 있습니다.


충분하지 않습니다. Windows 및 DOS에서 일부 단어는 예약되어있어 파일 이름으로 사용할 수 없습니다.

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.

봐 ~

http://en.wikipedia.org/wiki/Filename


편집하다:

Windows는 일반적으로 파일 이름을 260 자로 제한합니다 . 그러나 전체 경로 (예 : C : \ Program Files \ filename.txt)가이 문자 수에 포함되므로 파일 이름은 실제로 그보다 짧아야합니다.

따라서 파일 이름이 매우 긴 파일을 현재 위치보다 경로가 더 긴 위치로 복사 할 때 가끔 오류가 발생할 수 있습니다.


글쎄, 나는 다음 방법이 유효한 파일 이름을 보장한다고 생각합니다.

public static boolean isValidName(String text)
{
    try
    {
        File file = new File(text);
        file.createNewFile();
        if(file.exists()) file.delete();
        return true;
    }
    catch(Exception ex){}
    return false;
}

어떻게 생각해?


일반적으로 Windows 파일 이름이 유효하다는 것을 보장하는 방법 (해당 이름의 파일을 만드는 것이 합법적 일 수 있음)은 구현이 불가능합니다.

Windows 파일 이름이 유효하지 않음을 보장하는 것은 비교적 간단합니다 . 다른 정규식 중 일부는이를 시도합니다. 그러나 원래 질문 은 Windows에서 파일 이름이 유효 함 보장 하는 더 강력한 주장을 요구합니다 .

The MSDN reference cited in other answers indicates that a Windows filename cannot contain "Any other character that the target file system does not allow". For instance, a file containing NUL would be invalid on some file systems, as would extended Unicode characters on some older file systems. Thus, a file called ☃.txt would be valid in some cases, but not others. So whether a hypothetical isValidName(\"☃\") would return true is dependent on the underlying file system.

그러나 그러한 함수가 보수적이며 파일 이름이 인쇄 가능한 ASCII 문자로 구성되어야한다고 가정하십시오. 모든 최신 버전의 Windows는 기본적으로 유니 코드 파일 이름을 허용하는 NTFS, FAT32 및 FAT16 파일 형식을 지원합니다. 그러나 임의의 파일 시스템 용 드라이버를 설치할 수 있으며, 예를 들어 문자 'n'을 허용하지 않는 파일 시스템을 자유롭게 만들 수 있습니다. 따라서 "snowman.txt"와 같은 단순한 파일조차도 "보장"되지 않습니다.

But even with extreme cases aside, there are other complications. For instance, a file named "$LogFile" cannot exist in the root of a NTFS volume, but can exist elsewhere on the volume. Thus, without knowing the directory, we cannot know if "$LogFile" is a valid name. But even "C:\data\$LogFile" might be invalid if, say, "c:\data\" is a symbolic link to another NTFS volume root. (Similarly, "D:\$LogFile" can be valid if D: is an alias to a subdirectory of an NTFS volume.)

더 많은 합병증이 있습니다. 예를 들어 파일의 대체 데이터 스트림은 NTFS 볼륨에서 합법적이므로 "snowman.txt : ☃"가 유효 할 수 있습니다. 세 가지 주요 Windows 파일 시스템에는 모두 경로 길이가 재구성되므로 파일 이름의 유효성도 경로의 기능입니다. 그러나 isValidName경로가 볼륨의 물리적 경로가 아닌 가상 별칭, 매핑 된 네트워크 드라이브 또는 심볼릭 링크 인 경우 물리적 경로의 길이를 사용하지 못할 수도 있습니다 .

다른 사람들은 대안을 제안했습니다. 제안 된 이름으로 파일을 만든 다음 삭제하고 생성이 성공한 경우에만 true를 반환합니다. 이 접근 방식에는 몇 가지 실용적이고 이론적 인 문제가 있습니다. 하나는 앞서 언급했듯이 유효성이 파일 이름과 경로의 함수이므로 c : \ test \ ☃.txt의 유효성이 c : \ test2 \ ☃.txt의 유효성과 다를 수 있다는 것입니다. 또한이 함수는 디렉토리에 대한 쓰기 권한이없는 등 파일의 유효성과 관련이없는 여러 가지 이유로 파일 쓰기에 실패합니다. 세 번째 결점은 파일 이름의 유효성이 비 결정적 일 필요가 없다는 것입니다. 예를 들어 가상의 파일 시스템은 삭제 된 파일의 교체를 허용하지 않거나 (이론적으로) 파일 이름이 유효한지 무작위로 결정할 수도 있습니다.

대안으로, isInvalidFileName(String text)파일이 Windows에서 유효 하지 않다고 보장되는 경우 true를 반환 하는 메서드를 만드는 것은 매우 간단합니다 . "aux", "*"및 "abc.txt"와 같은 파일 이름 true를 반환합니다. 파일 생성 작업은 먼저 파일 이름이 유효하지 않은지 확인하고 false를 반환하면 중지됩니다. 그렇지 않으면 파일 이름이 유효하지 않아 파일을 생성 할 수없는 경우에 대비하는 동안 메서드가 파일 생성을 시도 할 수 있습니다.


Eng.Fouad의 코드에 댓글을 달 수있는 담당자 임계 값이 없기 때문에 새 답변 게시

public static boolean isValidName(String text)
{
    try
    {
        File file = new File(text);
        if(file.createNewFile()) file.delete();
        return true;
    }
    catch(Exception ex){}
    return false;
}

기존 파일을 삭제하지 못하도록 답변을 약간 변경했습니다. 이 메서드 호출 중에 파일이 생성 된 경우에만 파일이 삭제되지만 반환 값은 동일합니다.


Here you can find which file names are allowed.

The following characters are not allowed:

  • < (less than)
  • (greater than)

  • : (colon)
  • " (double quote)
  • / (forward slash)
  • \ (backslash)
  • | (vertical bar or pipe)
  • ? (question mark)
  • * (asterisk)

  • Integer value zero, sometimes referred to as the ASCII NUL character.

  • Characters whose integer representations are in the range from 1 through 31, except for alternate data streams where these characters are allowed. For more information about file streams, see File Streams.
  • Any other character that the target file system does not allow.

This solution will only check if a given filename is valid according to the OS rules without creating a file.

You still need to handle other failures when actually creating the file (e.g. insufficient permissions, lack of drive space, security restrictions).

import java.io.File;
import java.io.IOException;

public class FileUtils {
  public static boolean isFilenameValid(String file) {
    File f = new File(file);
    try {
       f.getCanonicalPath();
       return true;
    }
    catch (IOException e) {
       return false;
    }
  }

  public static void main(String args[]) throws Exception {
    // true
    System.out.println(FileUtils.isFilenameValid("well.txt"));
    System.out.println(FileUtils.isFilenameValid("well well.txt"));
    System.out.println(FileUtils.isFilenameValid(""));

    //false
    System.out.println(FileUtils.isFilenameValid("test.T*T"));
    System.out.println(FileUtils.isFilenameValid("test|.TXT"));
    System.out.println(FileUtils.isFilenameValid("te?st.TXT"));
    System.out.println(FileUtils.isFilenameValid("con.TXT")); // windows
    System.out.println(FileUtils.isFilenameValid("prn.TXT")); // windows
    }
  }

Looks good. At least if we believe to this resource: http://msdn.microsoft.com/en-us/library/aa365247%28v=vs.85%29.aspx

But I'd simplify use the code. It is enough to look for one of these characters to say that the name is invalid, so:

public static boolean isValidName(String text)
{
    Pattern pattern = Pattern.compile("[^/./\\:*?\"<>|]");
    return !pattern.matcher(text).find();
}

This regex is simpler and will work faster.


Not sure how to implement it in Java (either Regex or own method). But, Windows OS has the following rules to create file/directory in the file system:

  1. Name is not only be Dots
  2. Windows device names like AUX, CON, NUL, PRN, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, LPT9, cannot be used for a file name nor for the first segment of a file name (i.e. test1 in test1.txt).
  3. Device names are case insensitive. (i.e. prn, PRN, Prn, etc. are identical.)
  4. All characters greater than ASCII 31 to be used except "*/:<>?\|

So, the program needs to stick with these rules. Hope, it covers the validation rules for your question.


You can check all the reserved names (AUX, CON, and the like) and then use this code:

bool invalidName = GetFileAttributes(name) == INVALID_FILE_ATTRIBUTES && 
        GetLastError() == ERROR_INVALID_NAME;

to check for any additional restriction. But note that if you check for a name in a non existant directory you will get ERROR_PATH_NOT_FOUND whether the name is really valid or not.

Anyway, you should remember the old saying:

It's easier to ask for forgiveness than it is to get permission.


How about letting the File class do your validation?

public static boolean isValidName(String text) {
    try {
        File file = new File(text);
        return file.getPath().equals(text);
    }
    catch(Exception ex){}
    return false;
}

ReferenceURL : https://stackoverflow.com/questions/6730009/validate-a-file-name-on-windows

반응형