Điều này nên thực sự đơn giản. Nếu tôi có một Chuỗi như thế này:
_../Test?/sample*.txt
_
vậy thì cách nào được chấp nhận chung để có được danh sách các tệp khớp với mẫu này? (ví dụ: nó phải khớp với _../Test1/sample22b.txt
_ và _../Test4/sample-spiffy.txt
_ nhưng không phải là _../Test3/sample2.blah
_ hoặc _../Test44/sample2.txt
_)
Tôi đã xem org.Apache.commons.io.filefilter.WildcardFileFilter
và có vẻ như đúng là con thú nhưng tôi không chắc làm thế nào để sử dụng nó để tìm tệp trong đường dẫn thư mục tương đối.
Tôi cho rằng tôi có thể tìm nguồn cho kiến vì nó sử dụng cú pháp ký tự đại diện, nhưng tôi phải thiếu một cái gì đó khá rõ ràng ở đây.
( chỉnh sửa : ví dụ trên chỉ là một trường hợp mẫu. Tôi đang tìm cách phân tích các đường dẫn chung có chứa ký tự đại diện khi chạy. Tôi đã tìm ra cách để làm điều đó dựa trên đề xuất của mmyer nhưng thật khó chịu. Chưa kể rằng Java JRE dường như tự động phân tích các ký tự đơn giản trong các đối số chính (Chuỗi []) từ một đối số duy nhất để "lưu "Tôi có thời gian và rắc rối ... Tôi rất vui vì tôi không có các đối số không phải là tệp trong hỗn hợp.)
Hãy xem xét DirectoryScanner từ Apache Ant:
DirectoryScanner scanner = new DirectoryScanner();
scanner.setIncludes(new String[]{"**/*.Java"});
scanner.setBasedir("C:/Temp");
scanner.setCaseSensitive(false);
scanner.scan();
String[] files = scanner.getIncludedFiles();
Bạn sẽ cần tham khảo ant.jar (~ 1,3 MB cho ant 1.7.1).
Hãy thử FileUtils
từ Apache commons-io (phương thức listFiles
và iterateFiles
):
File dir = new File(".");
FileFilter fileFilter = new WildcardFileFilter("sample*.Java");
File[] files = dir.listFiles(fileFilter);
for (int i = 0; i < files.length; i++) {
System.out.println(files[i]);
}
Để giải quyết vấn đề của bạn với các thư mục TestX
, trước tiên tôi sẽ lặp qua danh sách các thư mục:
File[] dirs = new File(".").listFiles(new WildcardFileFilter("Test*.Java");
for (int i=0; i<dirs.length; i++) {
File dir = dirs[i];
if (dir.isDirectory()) {
File[] files = dir.listFiles(new WildcardFileFilter("sample*.Java"));
}
}
Khá là một giải pháp 'vũ phu' nhưng sẽ hoạt động tốt. Nếu điều này không phù hợp với nhu cầu của bạn, bạn luôn có thể sử dụng RegexFileFilter .
Dưới đây là ví dụ về liệt kê các tệp theo mẫu được cung cấp bởi Java 7 nioglobalbing và Java 8 lambdas:
try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(
Paths.get(".."), "Test?/sample*.txt")) {
dirStream.forEach(path -> System.out.println(path));
}
hoặc là
PathMatcher pathMatcher = FileSystems.getDefault()
.getPathMatcher("regex:Test./sample\\w+\\.txt");
try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(
new File("..").toPath(), pathMatcher::matches)) {
dirStream.forEach(path -> System.out.println(path));
}
Bạn có thể chuyển đổi chuỗi ký tự đại diện của mình thành biểu thức chính quy và sử dụng chuỗi đó với phương thức matches
của String. Theo ví dụ của bạn:
String original = "../Test?/sample*.txt";
String regex = original.replace("?", ".?").replace("*", ".*?");
Điều này làm việc cho các ví dụ của bạn:
Assert.assertTrue("../Test1/sample22b.txt".matches(regex));
Assert.assertTrue("../Test4/sample-spiffy.txt".matches(regex));
Và ví dụ ngược lại:
Assert.assertTrue(!"../Test3/sample2.blah".matches(regex));
Assert.assertTrue(!"../Test44/sample2.txt".matches(regex));
Có thể không giúp bạn ngay bây giờ, nhưng JDK 7 được dự định có khớp tên tệp toàn cầu và regex như một phần của "Các tính năng NIO khác".
Vì Java 8, bạn có thể sử dụng phương thức Files#find
trực tiếp từ Java.nio.file
.
public static Stream<Path> find(Path start,
int maxDepth,
BiPredicate<Path, BasicFileAttributes> matcher,
FileVisitOption... options)
Files.find(startingPath,
Integer.MAX_VALUE,
(path, basicFileAttributes) -> path.toFile().getName().matches(".*.pom")
);
Thư viện ký tự đại diện có hiệu quả khớp cả tên tệp toàn cầu và regex:
http://code.google.com.vn/p/wildcard/
Việc thực hiện ngắn gọn - JAR chỉ có 12,9 kilobyte.
Cách đơn giản mà không sử dụng bất kỳ nhập khẩu bên ngoài là sử dụng phương pháp này
Tôi đã tạo các tệp csv có tên là billing_201208.csv, billing_201209.csv, billing_201210.csv và có vẻ như nó hoạt động tốt.
Đầu ra sẽ như sau nếu các tệp được liệt kê ở trên tồn tại
found billing_201208.csv
found billing_201209.csv
found billing_201210.csv
[.__.] // Sử dụng Nhập -> nhập Java.io.File [.__.] Chuỗi đích_file; // fileThatYouWantToFilter [.__.] Tệp thư mụcToScan = new File (pathToScan); [.__.] [.__.]
File[] listOfFiles = folderToScan.listFiles();
for (int i = 0; i < listOfFiles.length; i++) {
if (listOfFiles[i].isFile()) {
target_file = listOfFiles[i].getName();
if (target_file.startsWith("billing")
&& target_file.endsWith(".csv")) {
//You can add these files to fileList by using "list.add" here
System.out.println("found" + " " + target_file);
}
}
}
}
Như được đăng trong một câu trả lời khác, thư viện ký tự đại diện hoạt động cho cả khớp tên tệp toàn cầu và regex: http://code.google.com.vn/p/wildcard/
Tôi đã sử dụng mã sau đây để khớp với các mẫu toàn cầu bao gồm tuyệt đối và tương đối trên các hệ thống tệp kiểu * nix:
String filePattern = String baseDir = "./";
// If absolute path. TODO handle windows absolute path?
if (filePattern.charAt(0) == File.separatorChar) {
baseDir = File.separator;
filePattern = filePattern.substring(1);
}
Paths paths = new Paths(baseDir, filePattern);
List files = paths.getFiles();
Tôi đã dành một chút thời gian để cố gắng có được các phương thức FileUtils.listFiles trong thư viện Apache commons io (xem câu trả lời của Vladimir) để làm điều này nhưng không thành công (tôi nhận ra bây giờ/nghĩ rằng nó chỉ có thể xử lý mô hình khớp với một thư mục hoặc tệp tại một thời điểm) .
Ngoài ra, sử dụng các bộ lọc regex (xem câu trả lời của Fabian) để xử lý các mẫu toàn cầu loại tuyệt đối do người dùng cung cấp mà không cần tìm kiếm toàn bộ hệ thống tệp sẽ yêu cầu một số tiền xử lý của quả cầu được cung cấp để xác định tiền tố không phải regex/global lớn nhất.
Tất nhiên, Java 7 có thể xử lý tốt chức năng được yêu cầu, nhưng tiếc là hiện tại tôi đang bị mắc kẹt với Java 6. Thư viện tương đối rất nhỏ với kích thước 13,5kb.
Lưu ý cho người đánh giá: Tôi đã cố gắng thêm câu trả lời ở trên vào câu trả lời hiện có đề cập đến thư viện này nhưng bản chỉnh sửa đã bị từ chối. Tôi cũng không có đủ đại diện để thêm nhận xét này. Không có cách nào tốt hơn ...
Bạn sẽ có thể sử dụng WildcardFileFilter
. Chỉ cần sử dụng System.getProperty("user.dir")
để có được thư mục làm việc. Thử đi:
public static void main(String[] args) {
File[] files = (new File(System.getProperty("user.dir"))).listFiles(new WildcardFileFilter(args));
//...
}
Bạn không cần thay thế *
bằng [.*]
, giả sử bộ lọc ký tự đại diện sử dụng Java.regex.Pattern
. Tôi chưa thử nghiệm điều này, nhưng tôi thường xuyên sử dụng các mẫu và bộ lọc tệp.
Bộ lọc Apache được xây dựng để lặp các tệp trong một thư mục đã biết. Để cho phép ký tự đại diện trong thư mục, bạn sẽ phải chia đường dẫn trên '\
' hoặc '/
' và thực hiện một bộ lọc trên từng phần riêng biệt.
Tại sao không sử dụng làm một cái gì đó như:
File myRelativeDir = new File("../../foo");
String fullPath = myRelativeDir.getCanonicalPath();
Sting wildCard = fullPath + File.separator + "*.txt";
// now you have a fully qualified path
Sau đó, bạn sẽ không phải lo lắng về các đường dẫn tương đối và có thể thực hiện ký tự đại diện khi cần thiết.
Phương pháp sử dụng:
public static boolean isFileMatchTargetFilePattern(final File f, final String targetPattern) {
String regex = targetPattern.replace(".", "\\."); //escape the dot first
regex = regex.replace("?", ".?").replace("*", ".*");
return f.getName().matches(regex);
}
kiểm tra jUnit:
@Test
public void testIsFileMatchTargetFilePattern() {
String dir = "D:\\repository\\org\my\\modules\\mobile\\mobile-web\\b1605.0.1";
String[] regexPatterns = new String[] {"_*.repositories", "*.pom", "*-b1605.0.1*","*-b1605.0.1", "mobile*"};
File fDir = new File(dir);
File[] files = fDir.listFiles();
for (String regexPattern : regexPatterns) {
System.out.println("match pattern [" + regexPattern + "]:");
for (File file : files) {
System.out.println("\t" + file.getName() + " matches:" + FileUtils.isFileMatchTargetFilePattern(file, regexPattern));
}
}
}
Đầu ra:
match pattern [_*.repositories]:
mobile-web-b1605.0.1.pom matches:false
mobile-web-b1605.0.1.war matches:false
_remote.repositories matches:true
match pattern [*.pom]:
mobile-web-b1605.0.1.pom matches:true
mobile-web-b1605.0.1.war matches:false
_remote.repositories matches:false
match pattern [*-b1605.0.1*]:
mobile-web-b1605.0.1.pom matches:true
mobile-web-b1605.0.1.war matches:true
_remote.repositories matches:false
match pattern [*-b1605.0.1]:
mobile-web-b1605.0.1.pom matches:false
mobile-web-b1605.0.1.war matches:false
_remote.repositories matches:false
match pattern [mobile*]:
mobile-web-b1605.0.1.pom matches:true
mobile-web-b1605.0.1.war matches:true
_remote.repositories matches:false
Path testPath = Paths.get("C:\");
Stream<Path> stream =
Files.find(testPath, 1,
(path, basicFileAttributes) -> {
File file = path.toFile();
return file.getName().endsWith(".Java");
});
// Print all files found
stream.forEach(System.out::println);
Thực hiện giao diện JDK FileVisitor. Dưới đây là một ví dụ http://wildderator.com/list-files-matching-a-naming-potype-Java/