2009-05-21 4 views
45

は、私は、文字列パラメータで提供されているファイル名にファイルの名前を変更しています。基本的に私は、既存のものを埋めるのは嫌だとNEWNAMEはすでに、いくつかの他のファイルによって取られていないかどうかをチェックする方法Java - ファイル名が有効かどうかを調べるには?私のJavaアプリケーションで

boolean OKtoRename(String oldName, String newName) 

があります。

今では、おそらくNEWNAME文字列が有効なファイル名を表すないことを私に起こりました。 、

if (new File(newName).isFile()) { 
    return false; 
} 

ほとんどの場合にnewFileがまだ存在しないため、したがって OKtoRenameですが、明らかにそれを行うための正しい方法は、ないです。だから私はこの方法には、このチェックを追加すると思いました関数はfalseを返します。

私が思っていた

canExist()のような方法(私が知っているのjava.io.Fileオブジェクトにありません)がありますか?それとも私が例えば?、*、」、:)?私は多分そこにあるかしらJDKのどこかに隠された機能は、それが文字列があれば私に言うだろう(にnewFile文字列に無効な文字が含まれていないことを確認するとregexに頼らなければならないだろうおそらく有効なファイル名を表すことができます。

+0

お願い、もう存在しません()回答、これは役に立ちません。ファイルが存在する可能性があるかどうかをチェックしようとしています。 –

+1

@ MasterPeter:あなたの質問を書き換えてみてください。最初は、ファイルが存在するかどうかを知りたいと思っているように見えます。実際に必要なのは、ファイルNAMEが有効かどうかを知ることです。私はタイトルを変更しましたが、質問文に触れませんでした。 – OscarRyz

+0

関連性があるようです:http://eng-przemelek.blogspot.com/2009/07/how-to-create-valid-file-name.html – greenoldman

答えて

21

それはまだ存在しない場合にのみ、アトミックファイルを作成します使用createNewFile()を、。

をファイルが作成されている場合は、名前が有効であり、それが追い払ってくれるされていません既存のファイルを開いて、FileChannel.transferXXX操作でファイルを開き、データを効率的にコピーすることができます。

一般的に、チェックと作成はアトミックでなければなりません。最初に操作が安全かどうかを確認してから別の手順として操作を実行すると、その間に条件が変更され、操作が安全でない可能性があります。

思考のための追加の食品は、この関連の記事で提供されています:"Move/Copy operations in Java."


更新:

この回答以来、NIO.2のAPIが導入されている、と多くの対話を追加ファイルシステム。

あなたは対話型プログラムがあると、そのファイルが潜在的に有効であるかどうか、各キーストロークの後に検証します。たとえば、[保存]を押した後にエラーダイアログを表示するのではなく、エントリが有効な場合にのみ[保存]ボタンを有効にすることができます。上記の私の提案が必要とする多くの不要なファイルの削除を作成して保証することは混乱のように思えます。

NIO.2では、ファイルシステムでは無効な文字を含むPathインスタンスを作成することはできません。 Pathを作成しようとするとすぐにInvalidPathExceptionが生成されます。

ただし、Windows上で「PRN」などの有効な文字で構成される違法名を、検証するためのAPIはありません。回避策として、実験では、不正なファイル名を使用すると、属性にアクセスしようとするときに別個の例外が発生することが判明しました(たとえば、Files.getLastModifiedTime()を使用)。

存在するファイルに正当な名前を指定しても例外はありません。

存在しないファイルに有効な名前を指定すると、NoSuchFileExceptionが生成されます。

無効な名前を指定すると、FileSystemExceptionが生成されます。

しかし、これは非常に複雑で、他のオペレーティングシステムでは信頼できない可能性があります。

+2

OKtoRename関数はファイルシステムを実際に変更することは想定されていないため、作成したファイルを削除したいと思うでしょう。 –

+1

@Matt:ファイルを作成するだけで、createNewFileがfalseを返す場合は、ファイル名が有効でない(...または作成できない:-S)¬¬ – OscarRyz

+0

正確には、このソリューションは、私はすぐに後でそれを削除する空のファイルを作成する考えが好きではない... –

57

私は数ヶ月前にいくつかのオンラインリサーチに基づいて、不正なファイル名の文字のリスト(UNIX、Mac OS XおよびWindowsシステムを考慮)を組み立てました。新しいファイル名にこれらのファイル名が含まれていると、すべてのプラットフォームで有効でない可能性があります。

private static final char[] ILLEGAL_CHARACTERS = { '/', '\n', '\r', '\t', '\0', '\f', '`', '?', '*', '\\', '<', '>', '|', '\"', ':' }; 

EDIT:それはあなたのファイル名は、まだWindowsの特定のキーワードかもしれない、このテストに合格していても、コメンターが指摘するように: 私はこれがない完全なソリューションであることを、強調したいですCOM、PRNなどのようなものです。ただし、ファイル名にこれらの文字が含まれていると、クロスプラットフォーム環境で問題が発生します。

+10

しかし、COM、COM1、COM2、PRNなどと呼ばれるファイルを作成しようとするようなキーワードは忘れないでください(少なくともWindowsプラットフォームで) – Instantsoup

+0

ポイントは、それについても考えていません... –

+1

これは完全な解決策ではなく、これは私にとってはうまくいっています(ファイル名の一部のみが動的なので、キーワードは危険ではありません)。 このリストをコンパイルしていただきありがとうございます。 – radai

2

私にはOS依存の問題があるようです。ファイル名に無効な文字がいくつかあるかどうかを確認したいだけかもしれません。 Windowsはファイルの名前を変更しようとすると、ファイルに次の文字を含めることができないというメッセージを表示します。\ /:*? <> | あなたの質問が「私に仕事をしている図書館はありますか?その場合私は何も知らない。

String validName = URLEncoder.encode(fileName , "UTF-8"); 

File newFile = new File(validName); 

を使用して

+2

おそらくファイル名の長さもチェックするべきです。 –

0

は、作業を行います。

私は今発見しました。私は時間の100%が動作するかわからないが、これまでのところ、私は有効なファイル名を作成することができました。

+4

申し訳ありませんが、fileNameに星があった場合、コードは役に立たないでしょう。 System.out.println(URLEncoder.encode( "* hello world *"、 "UTF-8")); * hello + world *を出力します。これは有効なファイル名ではありません。 –

+0

偉大な!..あなたは正しいです、実際に私はこれを尋ねようとしていました。 :) – OscarRyz

4

これは私がこれを実装する方法です:

public boolean isValidFileName(final String aFileName) { 
    final File aFile = new File(aFileName); 
    boolean isValid = true; 
    try { 
     if (aFile.createNewFile()) { 
      aFile.delete(); 
     } 
    } catch (IOException e) { 
     isValid = false; 
    } 
    return isValid; 
} 
+2

これは、ディレクトリトラバーサルセキュリティのバグにつながります。ファイル名が第三者に由来する場合は、安全なコーディング方法ではありません。 –

+0

@VishnuPrasadKallummelディレクトリトラバーサルは、ユーザが提供する入力ファイル名のセキュリティの検証/サニタイズが不十分であることから成ります。サニタイズを実行するには、アプリケーションに別のレイヤーが必要です。特定のパスが有効かどうかを検証するメソッドで、ユーザー入力の検証を混在させる必要がある理由を説明してください。 –

+0

この方法は、ディレクトリトラバーサルの問題になります。しかし、このメソッドが呼び出される前にチェックを行うレイヤーが追加されていればOKです。私が実際にファイルを作成して削除することなく同じものを探していたのは、自発的なコメントでした。 –

16

Hereシステム固有の方法が提案されています。

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

ああ、私の悪い、私はあなたの答えを見ていない... –

+1

残念なことにそれはAndroidで動作しません:-(iefgetCanonicalPath()は、不正なファイル名の例外をスローしません –

+6

それは危険ではないですか? [職場では作成されていない]機能に頼っています(http://docs.oracle.com/javase/7/docs/api/java/io/File.html#getCanonicalFile())? – Nielsvh

4

Eclipse用の開発、Javaの7で私が見つけただけで何かを、org.eclipse.core.internal.resources.OS

public abstract class OS { 
    private static final String INSTALLED_PLATFORM; 

    public static final char[] INVALID_RESOURCE_CHARACTERS; 
    private static final String[] INVALID_RESOURCE_BASENAMES; 
    private static final String[] INVALID_RESOURCE_FULLNAMES; 

    static { 
     //find out the OS being used 
     //setup the invalid names 
     INSTALLED_PLATFORM = Platform.getOS(); 
     if (INSTALLED_PLATFORM.equals(Platform.OS_WIN32)) { 
     //valid names and characters taken from http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/naming_a_file.asp 
     INVALID_RESOURCE_CHARACTERS = new char[] {'\\', '/', ':', '*', '?', '"', '<', '>', '|'}; 
     INVALID_RESOURCE_BASENAMES = new String[] {"aux", "com1", "com2", "com3", "com4", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ 
       "com5", "com6", "com7", "com8", "com9", "con", "lpt1", "lpt2", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ 
       "lpt3", "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9", "nul", "prn"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ 
     Arrays.sort(INVALID_RESOURCE_BASENAMES); 
     //CLOCK$ may be used if an extension is provided 
     INVALID_RESOURCE_FULLNAMES = new String[] {"clock$"}; //$NON-NLS-1$ 
     } else { 
     //only front slash and null char are invalid on UNIXes 
     //taken from http://www.faqs.org/faqs/unix-faq/faq/part2/section-2.html 
     INVALID_RESOURCE_CHARACTERS = new char[] {'/', '\0',}; 
     INVALID_RESOURCE_BASENAMES = null; 
     INVALID_RESOURCE_FULLNAMES = null; 
     } 
    } 

    /** 
    * Returns true if the given name is a valid resource name on this operating system, 
    * and false otherwise. 
    */ 
    public static boolean isNameValid(String name) { 
     //. and .. have special meaning on all platforms 
     if (name.equals(".") || name.equals("..")) //$NON-NLS-1$ //$NON-NLS-2$ 
     return false; 
     if (INSTALLED_PLATFORM.equals(Platform.OS_WIN32)) { 
     //empty names are not valid 
     final int length = name.length(); 
     if (length == 0) 
      return false; 
     final char lastChar = name.charAt(length-1); 
     // filenames ending in dot are not valid 
     if (lastChar == '.') 
      return false; 
     // file names ending with whitespace are truncated (bug 118997) 
     if (Character.isWhitespace(lastChar)) 
      return false; 
     int dot = name.indexOf('.'); 
     //on windows, filename suffixes are not relevant to name validity 
     String basename = dot == -1 ? name : name.substring(0, dot); 
     if (Arrays.binarySearch(INVALID_RESOURCE_BASENAMES, basename.toLowerCase()) >= 0) 
      return false; 
     return Arrays.binarySearch(INVALID_RESOURCE_FULLNAMES, name.toLowerCase()) < 0; 
     } 
     return true; 
    } 
} 
+2

これは 'org.eclipse.core.resources.IWorkspace.validateName(String、int) 'を介してアクセス可能です – Basilevs

2

をチェックアウトし、後で、1以上かかりgetと呼ばれる方法がありますPathsと呼ばれるクラスが存在する場合String sおよび

InvalidPathExceptionを投げる - パス文字列をパスに変換できない場合

+0

これは試してみる価値があります –

+0

注目すべき点は次のとおりです:on UNIXベースのシステムでは、これらは有効なファイル名です: "hi!"、 "hello file"、 "really?"このアプローチがこれらを可能にしていることが判明しました。 – lordoku

関連する問題