rm /blog

IT系技術職のおっさんがIT技術とかライブとか日常とか雑多に語るブログです。* 本ブログに書かれている内容は個人の意見・感想であり、特定の組織に属するものではありません。/All opinions are my own.*

【Java】ファイル名やディレクトリ名に使ってはいけない文字に関するjava.io.File実験

「ファイル名(ディレクトリ名)に使ってはいけない文字」のファイルをJavaで扱った時の挙動について


 

 


OSによって違うようだが、以下の文字はファイル名やディレクトリ名には使えないことになっている。

OS使ってはいけない文字

Windows \ / : * ? " < & > |
Unix / (U+0000;NUL)

Windowsのほうが禁止文字が多い。
逆に言うとUnix系OSのほうが使える文字が多い。
Unix系OSは、実は*や?や\や"とかまでファイル名に使えるらしい。
でも使わないで済むなら使わないほうがよかろう。
(なんかいろいろ不具合でそう)
どうしても必要なときでも、アプリケーションで最終的にユーザ提供するときには
エスケープしてやるなどの考慮が必要とは思う。

まあここまでは前段で。




で、これらの文字を含むファイルをJavaで扱ったらどうなるか?を
興味本位で実験してみた。

import java.io.*;

public class IllegularNameFileTest {
	
	private static final String name = "test\\/:*?\"><|.txt";
	
	
	public static void main(String[] args) {
		
		System.out.println("1.START");
		File file = new File(name);
		System.out.println("2.File instance make end");
		if (!file.exists()) {
			System.out.println("3.File#exists end");
		}
		try {
			file.createNewFile();
			System.out.println("4-1.File#createNewFile end");
		} catch(Throwable e) {
			System.out.println("4-2.File#createNewFile exception happend.");
			e.printStackTrace();
		}
		
	}
	
}

簡単にこんな↑プログラムを組んで実行してみる。

WindowsUNIX系OS(実行したのはSolaris)でちょっとだけ実行結果が変わった。
まずWindows

1.START
2.File instance make end
3.File#exists end
4-2.File#createNewFile exception happend.
java.io.IOException: ファイル名、ディレクトリ名、またはボリューム ラベルの構文が間違っています。
        at java.io.WinNTFileSystem.createFileExclusively(Native Method)
        at java.io.File.createNewFile(Unknown Source)
        at IllegularNameFileTest.main(IllegularNameFileTest.java:17)


次にUNIX

1.START
2.File instance make end
3.File#exists end
4-2.File#createNewFile exception happend.
java.io.IOException: ファイルもディレクトリもありません。
        at java.io.UnixFileSystem.createFileExclusively(Native Method)
        at java.io.File.createNewFile(Unknown Source)
        at IllegularNameFileTest.main(IllegularNameFileTest.java:17)


いずれのOSでも4.のFile#createNewFileのところでjava.io.IOExceptionが発生する。
これはまあ想定通り。
ただExceptionの発生元が、Windowsだと「WinNTFileSystem」UNIXだと「UnixFileSystem」だった。
Javaが、実行した環境のファイルシステムを自動で判定して先に進んでくれているようだ。
System#getPropertyでfile.separatorを取得するときにも似たようなことやってるんだろうなあ。

stackTraceの内容もOS別に異なる。
Windows「ファイル名、ディレクトリ名、またはボリューム ラベルの構文が間違っています。」は、
存在しないドライブに対してdirコマンド投げたとき等に発生するもの。
Unix「ファイルもディレクトリもありません。」は、
存在しないパスに対してls投げたとき等に発生するもの。
これだけ見ると内部的にOSコマンド投げて(そのうえで失敗を検知して)るようにも見えるが、
なんかOSレベルで、「ファイルシステムエラー時のメッセージ集」みたいの管理してて、
Javaがそれ拾ってstackTraceしてるだけなのかもしれんね。
良くは知らないが。

ちなみに、個人的には3.のFile#existsでもう落ちる(Exceptionがthrowされる)と思ってたのだが
ここは問題なく素通りする(falseを返してくるだけ)らしい。
↑の例でいえば、禁止文字をファイル名やディレクトリ名に含むパスに対して
dirやlsで「探す」段階でもうすでにエラーになったので、
existsもだめかもと踏んでいたのだが。
もしかしたら実際に「探して見つからない」っていう意味のfalseではなく、
「ファイル名に禁則文字入ってたら探すまでもなく速攻false返す」みたいな作りなのかもしれない。
作れないに決まってるんだから存在するわけない=false、というのも考え方として合ってるしね。

java.io.Fileにはもっといろいろなメソッドがあり、
諸々全部試してみたいところではあるが、
暇つぶしの一環なので一旦これくらいにしておく。
また興味が合ったらやってみよう。