我正在进行集成测试,我的代码的一部分在SVN下创建目录树。这需要我测试目录结构和文件是否符合我的期望。
一方面,我有预期的目录树和我想要的文件,另一方面,从SVN导出文件(更喜欢svn export
而不是svn co
以避免.svn
噪声)。
但是,是否有任何库可以断言两个目录树?我想到的最后一招是我自己进行迭代比较。
基本上我正在寻找一个可以接受两个目录并告诉我它们是否相等的API。
的内容
boolean areDirectoriesEqual(File dir1, File dir2)
答案 0 :(得分:9)
我没有使用第三方lib,而是使用标准的jdk lib。
>>> print counts
1 2
0 1
注意:这只是比较两个文件夹下的实际文件。如果你想要比较空文件夹等,你可能需要做一些额外的事情。
答案 1 :(得分:3)
我不知道任何areDirsEqual
库;我能想到的最接近的是Commons FileUtils
中的listFiles方法。
如果将结果集合放在HashSet
中,您应该能够有效地比较这两个集合。它可以在2行中完成,甚至可以是单行。
这一行:
public static boolean areDirsEqual(File dir, File dir2) {
return (new HashSet<File>(FileUtils.listFiles(dir1,..))).
containsAll(FileUtils.listFiles(dir2, ..))
}
答案 2 :(得分:3)
我有同样的问题,跟着Patrick和LorenzoDematté我发现了一个适合我的解决方案。以下代码遍历文件夹并:
我在linux上测试过它。
private static void verifyDirsAreEqual(File expected, File generated)
throws IOException {
// Checks parameters
assertTrue("Generated Folder doesn't exist: " + generated,generated.exists());
assertTrue("Generated is not a folder?!?!: " + generated,generated.isDirectory());
assertTrue("Expected Folder doesn't exist: " + expected,expected.exists());
assertTrue("Expected is not a folder?!?!: " + expected,expected.isDirectory());
Files.walkFileTree(expected.toPath(), new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(Path dir,
BasicFileAttributes attrs)
throws IOException {
FileVisitResult result = super.preVisitDirectory(dir, attrs);
// get the relative file name from path "expected"
Path relativize = expected.toPath().relativize(dir);
// construct the path for the counterpart file in "generated"
File otherDir = generated.toPath().resolve(relativize).toFile();
log.debug("=== preVisitDirectory === compare " + dir + " to " + otherDir);
assertEquals("Folders doesn't contain same file!?!?",
Arrays.toString(dir.toFile().list()),
Arrays.toString(otherDir.list()));
return result;
}
@Override
public FileVisitResult visitFile(Path file,
BasicFileAttributes attrs)
throws IOException {
FileVisitResult result = super.visitFile(file, attrs);
// get the relative file name from path "expected"
Path relativize = expected.toPath().relativize(file);
// construct the path for the counterpart file in "generated"
File fileInOther = generated.toPath().resolve(relativize).toFile();
log.debug("=== comparing: " + file + " to " + fileInOther);
String expectedContents = FileUtils.readFileToString(file.toFile());
String generatedContents = FileUtils.readFileToString(fileInOther);
assertEquals("("+fileInOther+") csv standard doesn't match expected ("+file+")!", expectedContents, generatedContents);
return result;
}
});
}
答案 3 :(得分:1)
好的,所以我不知道任何准备好的代码那样做,搜索也没有帮助。所以这就是我如何实现它
如果您只想将树标记为已更改/未更改,则可以保存每个文件的哈希值,然后需要哈希图而不是哈希集,其中每个文件内容的哈希值是哈希值的值
希望这会有所帮助
答案 4 :(得分:1)
这是一个使用Java NIO包的简单迭代解决方案(不使用Visitor模式,因此它也可以适用于早期的Java版本。)
当然可以调整它,但是现在这是一个简单的解决方案,可以从两个目录的视图中检查每个文件是否出现,并可选择使用Apache Commons FileUtils比较文件内容。
/**
* checks if the directory file lists and file content is equal
*
* @param directory
* the directory
* @param compareDirectory
* the directory to compare with
* @param checkFileContent
* also compare file content
* @return true if directory and compareDirectory are equal
* @throws IOException
*/
public static boolean isEqualDirectories(Path directory, Path compareDirectory, boolean checkFileContent) throws IOException {
boolean check = isEverythingInCompareDirectory(directory, compareDirectory, checkFileContent);
boolean checkOpposite = check && isEverythingInCompareDirectory(directory, compareDirectory, checkFileContent);
return check && checkOpposite;
}
/**
* checks if the directory file lists and file content is equal
*
* @param directory
* the directory
* @param compareDirectory
* the directory to compare with
* @param checkFileContent
* also compare file content
* @return true if directory and compareDirectory are equal
* @throws IOException
*/
public static boolean isEverythingInCompareDirectory(Path directory, Path compareDirectory, boolean checkFileContent)
throws IOException {
try {
LOGGER.info("checking directory " + directory);
File directoryFile = directory.toFile();
File compareFile = compareDirectory.toFile();
// check, if there is the same number of files/subdirectories
File[] directoryFiles = directoryFile.listFiles();
File[] compareFiles = compareFile.listFiles();
if (directoryFiles.length == compareFiles.length) {
return compareDirectoryContents(directory, compareDirectory, checkFileContent);
} else {
LOGGER.info("number of files in directory are different " + directoryFiles.length + " vs compareDirectory: " + compareFiles.length);
return false;
}
} catch (IOException e) {
throw new RuntimeException("Failed to assert that all files are equal", e);
}
}
public static boolean compareDirectoryContents(Path directory, Path compareDirectory, boolean checkFileContent) throws IOException {
try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(directory)) {
for (Path directoryFilePath : directoryStream) {
// search for directoryFile in the compareDirectory
Path compareFilePath = compareDirectory.resolve(directoryFilePath.getFileName());
if (compareFilePath != null) {
File directoryFile = directoryFilePath.toFile();
if (directoryFile.isFile()) {
LOGGER.info("checking file " + directoryFilePath);
if (checkFileContent && !FileUtils.contentEquals(compareFilePath.toFile(), directoryFile)) {
LOGGER.info("files not equal: compare: " + compareFilePath.toFile() + ", directory: " + directoryFilePath.getFileName() + "!");
return false;
}
} else {
LOGGER.info("going into recursion with directory " + directoryFilePath);
boolean result = isEverythingInCompareDirectory(directoryFilePath, compareFilePath, checkFileContent);
// cancel if not equal, otherwise continue processing
if (!result) {
return false;
}
}
} else {
LOGGER.info(directoryFilePath.toString() + ": compareFilepath not found");
return false;
}
}
}
return true;
}
答案 5 :(得分:0)
我在Kotlin写了这个小代码。它不会检查文件的内容,但完全依赖于apache中的md5。
import org.apache.commons.codec.digest.DigestUtils
fun File.calcMD5() = DigestUtils.md5Hex(FileUtils.readFileToByteArray(this))
fun compareTwoDirs(dir1: File, dir2: File): Boolean {
val files1 = dir1.listFiles().sorted()
val files2 = dir2.listFiles().sorted()
if (files1.size != files2.size) return false
return files1.zip(files2).all { equate(it.first, it.second) }
}
fun equate(fl: File, fl2: File): Boolean {
if (fl.isFile && fl2.isFile) return fl.calcMD5() == fl2.calcMD5()
if (fl.isDirectory && fl2.isDirectory) return compareTwoDirs(fl, fl2)
return false
}
答案 6 :(得分:0)
对我来说Patrick的解决方案似乎是一个很好的解决方案,但是与camel(Fuse ESB)结合使用时,我遇到的问题是最后一个父文件夹仍被Fuse进程阻止=&gt;对我来说,以下解决方案是更好的方式。我通过SimpleVistor迭代目录并制作了一套可比较的展位目录
public boolean compareFolders(final Path pathOne, final Path pathSecond) throws IOException {
// get content of first directory
final TreeSet<String> treeOne = new TreeSet();
Files.walkFileTree(pathOne, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Path relPath = pathOne.relativize(file);
String entry = relPath.toString();
treeOne.add(entry);
return FileVisitResult.CONTINUE;
}
});
// get content of second directory
final TreeSet<String> treeSecond = new TreeSet();
Files.walkFileTree(pathSecond, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Path relPath = pathSecond.relativize(file);
String entry = relPath.toString();
treeSecond.add(entry);
return FileVisitResult.CONTINUE;
}
});
return treeOne.equals(treeSecond);
}
答案 7 :(得分:0)
我知道这是一个老问题,但我会尽力解决。 这是一个打开2个目录并比较其内容的代码。 如果在一个文件中找到的文件在另一个文件中丢失或内容不同,则返回false。 为此,我浏览了两个目录的内容,并递归比较了找到的文件和目录(按字母顺序)。
<ui:composition template="WEB-INF/templates/main.xhtml">
<ui:define name="content">
<h:form id="form">
<p:dataTable id="table">
<f:event type="postAddToView" listener="#{myBean.populateDatatable}" />
<p:column>
<p:inputText value="#{myBean.testField}">
</p:inputText>
</p:column>
</p:dataTable>
</h:form>
<h:form id="form2">
<f:event type="postAddToView" listener="#{myBean.populateForm}" />
</h:form>
</ui:define>
</ui:composition>
答案 8 :(得分:-5)
import java.io.File;
/**
*
* FileUtils is a collection of routines for common file system operations.
*
* @author Dan Jemiolo (danj)
*
*/
public final class FileUtils {
/**
*
* This is a convenience method that calls find(File, String, boolean) with
* the last parameter set to "false" (does not match directories).
*
* @see #find(File, String, boolean)
*
*/
public static File find(File contextRoot, String fileName) {
return find(contextRoot, fileName, false);
}
/**
*
* Searches through the directory tree under the given context directory and
* finds the first file that matches the file name. If the third parameter is
* true, the method will also try to match directories, not just "regular"
* files.
*
* @param contextRoot
* The directory to start the search from.
*
* @param fileName
* The name of the file (or directory) to search for.
*
* @param matchDirectories
* True if the method should try and match the name against directory
* names, not just file names.
*
* @return The java.io.File representing the <em>first</em> file or
* directory with the given name, or null if it was not found.
*
*/
public static File find(File contextRoot, String fileName, boolean matchDirectories) {
if (contextRoot == null)
throw new NullPointerException("NullContextRoot");
if (fileName == null)
throw new NullPointerException("NullFileName");
if (!contextRoot.isDirectory()) {
Object[] filler = { contextRoot.getAbsolutePath() };
String message = "NotDirectory";
throw new IllegalArgumentException(message);
}
File[] files = contextRoot.listFiles();
//
// for all children of the current directory...
//
for (int n = 0; n < files.length; ++n) {
String nextName = files[n].getName();
//
// if we find a directory, there are two possibilities:
//
// 1. the names match, AND we are told to match directories.
// in this case we're done
//
// 2. not told to match directories, so recurse
//
if (files[n].isDirectory()) {
if (nextName.equals(fileName) && matchDirectories)
return files[n];
File match = find(files[n], fileName);
if (match != null)
return match;
}
//
// in the case of regular files, just check the names
//
else if (nextName.equals(fileName))
return files[n];
}
return null;
}
}