1

私はJava1.4.2とDebian6.0.3を使用しています。ネットワークには共有Windowsフォルダーがあり、CIFSを使用してfstabを介して正しくマウントされます/mnt/share/(たとえば、OSから完全に表示され、すべての操作が可能です)。ただし、Javaでこれを実行しようとすると、次のようになります。

System.out.println(new File("/mnt/share/").listFiles().length)

常に返されます。0つまり、File[]によって返されるlistFilesは空です。同じ問題がのすべてのサブディレクトリに当てはまります/mnt/share/list空の配列も返します。面白いことに、File「作成」、「isDirectory」、さらには「削除」などの他の関数は正常に機能します。USBフラッシュドライブ(fat32)からマウントされたディレクトリも正常に機能します。

これを、異なるWindowsシステムの2つの異なる「共有フォルダー」でテストしました。1つはドメインベースの認証システムを使用し、もう1つは「単純な共有」(つまり、ゲストアクセス)を使用します。マウントされたディレクトリはファイルシステムの一部になるはずなので、どのプログラムでも使用できるため、状況は奇妙に思えます。またはそう思った、少なくとも。

プログラム内のディレクトリを削除したいのですが、現在、再帰的に歩く以外に削除する方法がないlistFilesため、このバグはかなり厄介になります。私が考えることができる唯一の「回避策」は、どういうわけか外部のbashスクリプトを実行することですが、それはひどい解決策のようです。

編集:これは1.4.2固有のバグのようで、Java 6ではすべて正常に動作します。しかし、移行できないため、問題は残ります。

いくつかの回避策を提案できますか?できれば、ネイティブライブラリではなくサードパーティのライブラリに切り替えることなく、単一のコード行のためにプロジェクト全体を書き直すというアイデアが好きだとは言えません。

4

2 に答える 2

0

Java 1.2方法があるのでFile.getCanonicalFile()。マウントされたディレクトリを使用する場合は、次のようなスタイルでこれを使用する必要があります。

new File("/mnt/share/").getCanonicalFile().listFiles()

于 2014-03-25T08:19:19.697 に答える
0

そのため、あきらめてから2年半後、同じ問題が発生しました。コードを廃止されたOracle Forms 10gバージョンに埋め込む必要があるため、1.4.2で問題が発生しました。

誰かが偶然この問題に遭遇し、それを適切に解決することを決定した場合、それはおそらく、CIFSがリモートファイルシステムをマウントするときに行う(非常に)異常なiノードマッピングに関係しており、よりあいまいなバグを引き起こしますそのうちのserverfaultで見つけることができます。このようなマッピングの副作用の1つは、すべてのディレクトリのハードリンク数がゼロになることです。もう1つは、すべてのディレクトリの「サイズ」が、通常の「セクターサイズ以上」ではなく、正確に0であるということです。これは、。でもチェックできますls

(プロプライエタリ)ソースコードを調べないとわかりませんが、1.5より前のJavaは、実際にCでreaddir()を呼び出す代わりに、リンクカウントを内部でチェックするなどのショートカットを使用していたと推測できます。これは、マウントされたFSでも同様に機能します。 。

とにかく、2番目の副作用は、ディレクトリがCIFSを使用してマウントされていると疑われる場合を除いて、システムコールに依存しないFileの単純なラッパーを作成するために使用できます。フィルタを使用しているものも含め、他のバージョンのlistおよびlistFiles関数は内部的java.io.Fileに依存してlist()いるため、それだけをオーバーライドしても問題ありません。

私はlistFiles戻ってFile[]こないFileEx[]ことを気にしなかったので、それを上書きすることを気にしませんでしたが、それは十分に単純なはずです。ls明らかに、そのコードは、コマンドが便利なUnixライクなシステムでのみ機能します。

package FSTest;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;

import java.util.ArrayList;

public class FileEx extends File
{
    public FileEx(String path)
    {
        super(path);
    }

    public FileEx(File f)
    {
        super(f.getAbsolutePath());
    }

    public String[] list()
    {
        if (this.canRead() && this.isDirectory())
            {
            /*
             * Checking the length of dir is not the most reliable way to distinguish CIFS mounts.
             * However, zero directory length generally indicates something unusual,
             * so calling ls on it wouldn't hurt. Ordinary directories don't suffer any overhead this way.
             * If this "zero-size" behavior is ever changed by CIFS but list() still won't work,
             * it will be safer to call super.list() first and call this.listUsingExec if returned array has 0 elements.
             * Though it might have serious performance implications, of course.
             */
            if (this.length() > 0)
                return super.list();
            else
                return this.listUsingExec();
           }
        else
            return null;
    }

    private String[] listUsingExec()
    {
        Process p;
        String command = "/bin/ls -1a " + this.getAbsolutePath();
        ArrayList list = new ArrayList();
        try
            {
            p = Runtime.getRuntime().exec(command);
            p.waitFor();
            BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
            for (String line = reader.readLine(); line != null; line = reader.readLine())
                {
                if (!line.equalsIgnoreCase(".") && !line.equalsIgnoreCase(".."))
                    list.add(line);
               }
            String[] ret = new String[list.size()];
            list.toArray(ret);
            return ret;
           }
        catch (IOException e)
            {
            return null;
           }
    }
}
于 2015-01-05T08:40:36.607 に答える