2016-01-17 4 views
15

nioの.listは、ストリーム全体を呼び出すまで、繰り返し使用するファイルごとに1つのファイル記述子を保持するストリームを返します。つまり、1000個以上のファイルを持つデータディレクトリは、共通のulimitの値に対して簡単にブラシすることができます。このファイル記述子の蓄積の全体的な影響は、ネストされたトラバーサルを扱う際にさらに悪化します。O(1)のファイル記述子を開くには

OSファイルリストコマンドの呼び出しを開始する以外に、大きなディレクトリのファイルを繰り返し処理する方法はありますか?大規模なディレクトリのファイルを反復するのはクールです。適切なストリームセマンティクスによって暗示されているように、ファイル記述子は現在反復されているファイルごとにのみ保持されます。

編集:

listは、それが処理されていたら、無駄の反復のため、全体ではなく、ストリームが閉じているときのみに比べ、ストリーム上の各項目を閉じるために使用されるAPIコールjava.nio.file.PathのJavaストリームを返しますか?スカラーでは、より良いファイルからのapiラッパーを使用して簡単に手を加えることができ、hereから始まります。

+0

「、ファイルごとに1つのファイル記述子が繰り返しに上保持していますあなたはその結論にどうやって来たのですか? – Tunaki

+1

私はこの結論に、 '.list'の結果を反復する前後に、反復の後に' close'を呼び出すこととしないで、JMX(Ubuntu上のOracle Java 8のScala 2.11)を通してファイル記述子を数えることによってその結論に達しました。 – matanster

+1

SparkのカスタムRDDと同じ問題がありました。開いている接続のリストと、最後に開いているすべての接続を閉じるためのclose()メソッドを追加しました。すでにストリーミングされたファイルを閉じるためにイテレータコードを変更することができます。 –

答えて

2

ストリームを閉じなかったときに同じ問題(Windows Server 2012 R2)が発生しました。反復されたすべてのファイルは、JVMがシャットダウンされるまで読み取りモードでオープンされていました。しかし、それはMac OS Xでは発生せず、ストリームはFileSystemProviderDirectoryStreamというOS依存の実装に依存しているため、問題はOSにも依存する可能性があると私は推測しています。

@Ian McLairdコメントに反しては、ファイル・システム・リソースのタイムリーな処分が必要な場合は、試し-と資源構築物があることを確実にするために使用されるべき

ことFiles.list()ドキュメントに記載されていますストリームのcloseメソッドは、ストリーム操作が完了した後に呼び出されます。

返されたストリームは、そのJavadocの言うDirectoryStream、次のとおりです。

A DirectoryStreamは、作成時に開かれ、closeメソッドを呼び出すことによって閉じられています。ディレクトリストリームを閉じると、そのストリームに関連するすべてのリソースが解放されます。ストリームを閉じないと、リソースがリークする可能性があります。

私のソリューションは、アドバイスに従うと

try-with-resources構文を使用していた
try (Stream<Path> fileListing = Files.list(directoryPath)) { 
    // use the fileListing stream 
} 

私は(上記try-with-resources構文を使用)、正しくストリームを閉じたときに、ファイルハンドルがすぐに解放されました。

File directory = new File("/path/to/dir"); 
File[] files = directory.listFiles(); 
if (files != null) { // 'files' can be null if 'directory' "does not denote a directory, or if an I/O error occurs." 
    // use the 'files' array or convert to a stream: 
    Stream<File> fileStream = Arrays.stream(files); 
} 
:あなたはストリームとしてファイルを取得を気にしないか、あなた自身をメモリにファイル全体のリストを読み込むと、ストリームに変換してOKであれば

、あなたはIOのAPIを使用することができます

私はこのファイルロックの問題を経験しませんでした。ただし、どちらのソリューションもネイティブのOS依存コードに依存しているため、使用するすべての環境でテストすることをお勧めします。

+0

なぜあなたはあなたのケースでストリームを閉じるだけで十分ではありませんでしたか?あなたは、ファイルハンドラが反復されたファイルごとに取得(および蓄積)された経験をエコーし​​ているように見えますが、後で再現できませんでした。 – matanster

+0

私の質問は一種の質問ではありませんが、ファイルハンドラがディレクトリを反復するだけで再現できないため、この回答が全体的な問題を最もよく説明しているように私はここで恩恵を授与しています。他のケース/検索にも便利です。また、私はパノラマと研究指向の答えに非常に感謝しています。 – matanster

+0

@matanster:感謝のおかげで!私たちがお互いを正しく理解しているかどうかは分かりません。最初は私はストリームを閉じず、同じ問題に遭遇しました。 'try-with-resources'コンストラクトを使用したとき**役に立ちました。ファイルハンドルはすぐに解放されました(しかし、ストリームを閉じた後にのみ)。それを強調する答えを編集しました。この問題が発生しなかったMac OS Xで開発していましたが、Windows Server 2012 R2に導入したときに問題が発生しました。 –

4

なぜ、古い学校のjava.io.Fileを使用しないのですか?

File folder = new File(pathToFolder); 
String[] files = folder.list(); 

lsofでテストされ、リストされたファイルの何が開いているように見えません。その後、アレイをリストまたはストリームに変換できます。ディレクトリが大きすぎるか遠隔でない限り、私はPathオブジェクトを非難し、ガベージコレクトまたは何らかの形でそれらを破壊しようとします。

1

あなたは古い java.io.File.listFilesを使用アパッチのfileutilsライブラリを使用することができる内部的に機能:.closeに呼ばれるまで

Iterator<File> it = FileUtils.iterateFiles(folder, null, true); 
while (it.hasNext()) 
{ 
    File fileEntry = (File) it.next(); 
} 
関連する問題