我花了好几个小时寻找答案而我无法弄清楚,我正在尝试复制我的资源文件夹,其中包含我正在处理的游戏的所有图像和数据文件运行的罐子进入 E:/ Program Files / mtd /它在我运行eclipse时运行正常,但是当我导出jar并尝试它时,我得到NoSuchFileException
`JAR
Installing...
file:///C:/Users/Cam/Desktop/mtd.jar/resources to file:///E:/Program%20Files/mtd
/resources
java.nio.file.NoSuchFileException: C:\Users\Cam\Desktop\mtd.jar\resources
at sun.nio.fs.WindowsException.translateToIOException(Unknown Source)
at sun.nio.fs.WindowsException.rethrowAsIOException(Unknown Source)
at sun.nio.fs.WindowsException.rethrowAsIOException(Unknown Source)
at sun.nio.fs.WindowsFileAttributeViews$Basic.readAttributes(Unknown Sou
rce)
at sun.nio.fs.WindowsFileAttributeViews$Basic.readAttributes(Unknown Sou
rce)
at sun.nio.fs.WindowsFileSystemProvider.readAttributes(Unknown Source)
at java.nio.file.Files.readAttributes(Unknown Source)
at java.nio.file.FileTreeWalker.walk(Unknown Source)
at java.nio.file.FileTreeWalker.walk(Unknown Source)
at java.nio.file.Files.walkFileTree(Unknown Source)
at java.nio.file.Files.walkFileTree(Unknown Source)
at me.Zacx.mtd.main.Game.<init>(Game.java:94)
at me.Zacx.mtd.main.Game.main(Game.java:301)`
这是我正在使用的代码:
if (!pfFolder.exists()) {
pfFolder.mkdir();
try {
URL url = getClass().getResource("/resources/");
URI uri = null;
if (url.getProtocol().equals("jar")) {
System.out.println("JAR");
JarURLConnection connect = (JarURLConnection) url.openConnection();
uri = new URI(connect.getJarFileURL().toURI().toString() + "/resources/");
} else if (url.getProtocol().equals("file")) {
System.out.println("FILE");
uri = url.toURI();
}
final Path src = Paths.get(uri);
final Path tar = Paths.get(System.getenv("ProgramFiles") + "/mtd/resources/");
System.out.println("Installing...");
System.out.println(src.toUri() + " to " + tar.toUri());
Files.walkFileTree(src, new SimpleFileVisitor<Path>() {
public FileVisitResult visitFile( Path file, BasicFileAttributes attrs ) throws IOException {
return copy(file);
}
public FileVisitResult preVisitDirectory( Path dir, BasicFileAttributes attrs ) throws IOException {
return copy(dir);
}
private FileVisitResult copy( Path fileOrDir ) throws IOException {
System.out.println("Copying " + fileOrDir.toUri() + " to " + tar.resolve( src.relativize( fileOrDir ) ).toUri());
Files.copy( fileOrDir, tar.resolve( src.relativize( fileOrDir ) ) );
return FileVisitResult.CONTINUE;
}
});
System.out.println("Done!");
} catch (IOException e) {
e.printStackTrace();
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
答案 0 :(得分:1)
已编辑(为清晰起见而完全重写,示例代码)
这里的问题是不同的文件系统。 C:/Users/Cam/Desktop/mtd.jar
是File
中的WindowsFileSystem
。由于它是文件而不是目录,因此您无法访问文件中的子目录;如果C:/Users/Cam/Desktop/mtd.jar/resources
实际上是目录而不是文件,Path
只是有效mtd.jar
。
要访问其他文件系统上的内容,必须使用该文件系统根目录中的路径。例如,如果您在D:\dir1\dir2\file
中有一个文件,则无法使用以C:\
开头的路径(符号链接不可用)到达该文件;您必须使用从该文件系统D:\
的根目录开始的路径。
jar文件只是一个文件。它可以位于文件系统中的任何位置,并且可以像任何常规文件一样移动,复制或删除。但是,它本身包含自己的文件系统。没有窗口路径可用于引用jar文件系统中的任何文件,就像从C:\
开始的路径不能引用D:\
文件系统中的任何文件一样。
要访问 jar 的内容,您必须以ZipFileSystem
打开jar。
// Autoclose the file system at end of try { ... } block.
try(FileSystem zip_fs = FileSystems.newFileSystem(pathToZipFile, null)) {
}
获得zip_fs
后,您可以使用zip_fs.getPath("/path/in/zip");
为其中的文件获取Path
。这个Path
对象实际上是ZipFileSystemProvider
路径对象,而不是WindowsFileSystemProvider
路径对象,但是它是一个Path
对象,可以打开,读取等。 ,至少在ZipFileSystem
关闭之前。最大的区别是path.getFileSystem()
将返回ZipFileSystem
,resolve()
和relativize()
无法使用getFileSystem()
返回不同文件系统的路径对象。
当你的项目从Eclipse运行时,所有资源都在WindowsFileSystem
,所以走文件系统树并复制资源是直截了当的。当您的项目从jar运行时,资源不在默认文件系统中。
这是一个将资源复制到安装目录的Java类。它将在Eclipse中工作(所有资源都作为单独的文件),以及将应用程序打包到jar中时。
public class Installer extends SimpleFileVisitor<Path> {
public static void installResources(Path dst, Class<?> cls, String root) throws URISyntaxException, IOException {
URL location = cls.getProtectionDomain().getCodeSource().getLocation();
if (location.getProtocol().equals("file")) {
Path path = Paths.get(location.toURI());
if (location.getPath().endsWith(".jar")) {
try (FileSystem fs = FileSystems.newFileSystem(path, null)) {
installResources(dst, fs.getPath("/" + root));
}
} else {
installResources(dst, path.resolve(root));
}
} else {
throw new IllegalArgumentException("Not supported: " + location);
}
}
private static void installResources(Path dst, Path src) throws IOException {
Files.walkFileTree(src, new Installer(dst, src));
}
private final Path target, source;
private Installer(Path dst, Path src) {
target = dst;
source = src;
}
private Path resolve(Path path) {
return target.resolve(source.relativize(path).toString());
}
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
Path dst = resolve(dir);
Files.createDirectories(dst);
return super.preVisitDirectory(dir, attrs);
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Path dst = resolve(file);
Files.copy(Files.newInputStream(file), dst, StandardCopyOption.REPLACE_EXISTING);
return super.visitFile(file, attrs);
}
}
被称为:
Path dst = Paths.get("C:\\Program Files\\mtd");
Installer.installResources(dst, Game.class, "resources");
答案 1 :(得分:1)
我想的更难,但这是怎么做的。
这是我的复制方法参考https://examples.javacodegeeks.com/core-java/io/file/4-ways-to-copy-file-in-java/
public void copyFile(String inputPath, String outputPath ) throws IOException
{
InputStream inputStream = null;
OutputStream outputStream = null;
try {
inputStream = getClass().getResourceAsStream(inputPath);
outputStream = new FileOutputStream(outputPath);
byte[] buf = new byte[1024];
int bytesRead;
while ((bytesRead = inputStream.read(buf)) > 0) {
outputStream.write(buf, 0, bytesRead);
}
}
finally {
inputStream.close();
outputStream.close();
}
请注意此图片{Jarge}中项目的结构Project structure
现在我需要阅读Jar文件。这是此解决方案How can I get a resource "Folder" from inside my jar File?的变体。这两种方法共同起作用以产生结果。我测试了这个并且它有效。
public class Main {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
final String pathPartOne = "test/com";
final String pathPartTwo = "/MyResources";
String pathName = "C:\\Users\\Jonathan\\Desktop\\test.jar";
JarTest test = new JarTest();
final File jarFile = new File(pathName);
if(jarFile.isFile()) { // Run with JAR file
final JarFile jar = new JarFile(jarFile);
final Enumeration<JarEntry> entries = jar.entries(); //gives ALL entries in jar
while(entries.hasMoreElements()) {
final String name = entries.nextElement().getName();
if (name.startsWith(pathPartOne+pathPartTwo + "/")) { //filter according to the path
if(name.contains("."))//has extension
{
String relavtivePath = name.substring(pathPartOne.length()+1);
String fileName = name.substring(name.lastIndexOf('/')+1);
System.out.println(relavtivePath);
System.out.println(fileName);
test.copyFile(relavtivePath, "C:\\Users\\Jonathan\\Desktop\\" + fileName);
}
}
}
jar.close();
}
}
}
希望有所帮助。
答案 2 :(得分:-1)
我最终找到了回答 我不想输出一个很长很长的解释,但对于任何寻找解决方案的人来说,这都是
`
//on startup
installDir("");
for (int i = 0; i < toInstall.size(); i++) {
File f = toInstall.get(i);
String deepPath = f.getPath().replace(f.getPath().substring(0, f.getPath().lastIndexOf("resources") + "resources".length() + 1), "");
System.out.println(deepPath);
System.out.println("INSTALLING: " + deepPath);
installDir(deepPath);
System.out.println("INDEX: " + i);
}
public void installDir(String path) {
System.out.println(path);
final URL url = getClass().getResource("/resources/" + path);
if (url != null) {
try {
final File apps = new File(url.toURI());
for (File app : apps.listFiles()) {
System.out.println(app);
System.out.println("copying..." + app.getPath() + " to " + pfFolder.getPath());
String deepPath = app.getPath().replace(app.getPath().substring(0, app.getPath().lastIndexOf("resources") + "resources".length() + 1), "");
System.out.println(deepPath);
try {
File f = new File(resources.getPath() + "/" + deepPath);
if (getExtention(app) != null) {
FileOutputStream resourceOS = new FileOutputStream(f);
byte[] byteArray = new byte[1024];
int i;
InputStream classIS = getClass().getClassLoader().getResourceAsStream("resources/" + deepPath);
//While the input stream has bytes
while ((i = classIS.read(byteArray)) > 0)
{
//Write the bytes to the output stream
resourceOS.write(byteArray, 0, i);
}
//Close streams to prevent errors
classIS.close();
resourceOS.close();
} else {
System.out.println("new dir: " + f.getPath() + " (" + toInstall.size() + ")");
f.mkdir();
toInstall.add(f);
System.out.println(toInstall.size());
}
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (URISyntaxException ex) {
// never happens
}
}
}`