通过Unix样式路径:为什么这段Java代码在Windows机器上工作

huangapple go评论74阅读模式
英文:

Passing Unix Like Path: Why This Java Code Working on Windows Machine

问题

我对一段代码感到困惑,顺便说一下,它是有效的,但我的问题是为什么它有效?请查看下面的代码:

public String GetQuery(int QueryIndex) throws IOException {
    String realPath = (FileHelper.class.getResource("FileHelper.class")).toString().replace("lib/FileHelper.class", "conf/").replace("file:/", "").replace("%20", " ");

    // 打印realPath的值
    System.out.println(realPath);
    
    // 创建一个文件对象,但在路径之前添加斜杠
    // 由于某种原因,对于Windows和Linux机器都有效
    File QueryFile = new File("/" + realPath + "cygnus.dll");

    BufferedReader brReader = new BufferedReader(new FileReader(QueryFile));
    String TempContent;
    while ((TempContent = brReader.readLine()) != null) {
        if (TempContent.split(Config.COLSEP)[0].equals("Query" + QueryIndex)) {
            brReader.close();
            return TempContent.replace("Query" + QueryIndex + Config.COLSEP, "");
        }
    }
    brReader.close();
    return TempContent;
}

System.out.println(realPath)的控制台输出

D:/eclipse/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp1/wtpwebapps/cygnus/WEB-INF/classes/com/technobee/cygnus/conf/

传递给File构造函数的完整文件路径

/D:/eclipse/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp1/wtpwebapps/cygnus/WEB-INF/classes/com/technobee/cygnus/conf/cygnus.dll

现在我们可以看到路径之前有斜杠,但功能仍然有效。这是否是预期行为?

英文:

I am confused with a piece of code which is by the way working, but my question is why it is working? Have a look at below code

public String GetQuery(int QueryIndex) throws IOException {
		String realPath = (FileHelper.class.getResource("FileHelper.class")).toString().replace("lib/FileHelper.class", "conf/").replace("file:/", "").replace("%20", " ");

        //--->Printing value of realPath
		System.out.println(realPath);
        
        //-->Creating an object of file but adding Slash before path
        //--->Works with both Widnows and Linux machine for some reason.
		File QueryFile = new File("/"+realPath + "cygnus.dll");

		BufferedReader brReader = new BufferedReader(new FileReader(QueryFile));
		String TempContent;
		while ((TempContent = brReader.readLine()) != null) {
			if (TempContent.split(Config.COLSEP)[0].equals("Query"+QueryIndex)) {
				brReader.close();
				return TempContent.replace("Query"+QueryIndex+Config.COLSEP, "");
			}
		}
		brReader.close();
		return TempContent;
	}

Console Output of System.out.println(realPath)

D:/eclipse/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp1/wtpwebapps/cygnus/WEB-INF/classes/com/technobee/cygnus/conf/

Complete path of file passed in File constructor

/D:/eclipse/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp1/wtpwebapps/cygnus/WEB-INF/classes/com/technobee/cygnus/conf/cygnus.dll

Now we can see that the we have this slash before the path and the functionality is still working. So is this an expected behavior?

答案1

得分: 1

代码看起来非常脆弱,您应该修复它,而不是继续使用这种技巧,特别是如果您还有其他类似的地方需要更改。该技巧仅在您的类/资源在文件系统中找到并且您使用File时才有效。

如果部署到应用服务器的是war/jar文件,而不是解压的文件系统,那么getResource()返回的路径无法使用FilePath正确解释,因为它将包含URI的额外部分,如“jar:”和“!”,用于存档内部的路径。

相反,很容易切换到使用属性来读取位置/其他资源,或者您可以使用InputStream / getResourceAsStream来查找资源,根据搜索类FileHelper.class.getPackageName()的包名进行一些字符串操作,如下所示:

InputStream in = FileHelper.class.getResourceAsStream("/packagea/packageb/conf/cygnus.dll");

在Windows上,File将路径解析为"/C:/abc",与new File("C:\\abc")相同。然而,使用Path.of("/C:/abc")的相同技巧失败:

异常 java.nio.file.InvalidPathException: 在索引2处的非法字符<:>:/C:/abc
英文:

The code looks very brittle and you should fix it rather than passing on the hack especially if you have other places to change in similar manner. The technique will only work if your classes / resources are found in a file system and you use File.

If you deployed to app server with war/jar rather than exploded filesystem, the path returned by returned by getResource() cannot be interpreted correctly with File or Path as it will contain extra parts for the URI such as "jar:" and "!" for paths inside an archive.

Instead, its very easy fix to switch to properties for the locations / other resources to read, or you can locate the resource using InputStream / getResourceAsStream with some String manipulation based upon the package name of the search class FileHelper.class.getPackageName(), leading to:

 InputStream in = FileHelper.class.getResourceAsStream(&quot;/packagea/packageb/conf/cygnus.dll&quot;)`.

On Windows, File resolves paths like &quot;/C:/abc&quot; to be same as new File(&quot;C:\\abc&quot;). However the same trick with Path.of(&quot;/C:/abc&quot;) fails:

Exception java.nio.file.InvalidPathException: Illegal char &lt;:&gt; at index 2: /C:/abc

答案2

得分: 0

/ 表示文件根目录(在任何合理的平台上),所以在Windows上执行 /somePath/someOtherPath 会被理解为 C:\somePath\someOtherPath。如果在 / 后面指定了另一个驱动器,那么将使用该驱动器。

英文:

/ denotes the file root (on any sensible platform), so doing /somePath/someOtherPath on windows assumes that you mean C:\somePath\someOtherPath. If you specify another drive after the /, that drive gets used instead.

答案3

得分: 0

"…现在我们可以看到在路径之前有这个斜杠,功能仍然正常。那么这是一种预期的行为吗?"

系统中的路径仅仅是一种表示法,而不是一种语法。

这并没有一个用于表示法的标准化,因为表示法本身就是标准。

有一个关于“文件URI方案”的RFC,它将定义其“路径”元素的语法。
RFC 8089 – "file" URI Scheme

从这里,我们至少可以看到包含路径表示法的抽象所使用的内容。

这是“ABNF”(增强后巴科斯-诺尔范式),“第2节,语法”中的内容,

file-URI       = file-scheme ":" file-hier-part
file-scheme    = "file"
file-hier-part = ( "//" auth-path )
               / local-path
auth-path      = [ file-auth ] path-absolute
local-path     = path-absolute
file-auth      = "localhost"
               / host

而且,如从RFC 3986继承的“path-absolute”,在“第3.3节,路径”下,

path-absolute = "/" [ segment-nz *( "/" segment ) ]
segment       = *pchar
segment-nz    = 1*pchar
pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"

似乎它只是一组由正斜杠分隔的值,起始处需要一个正斜杠。

因此,您应该期望从不同的应用程序中看到试图通过提供的路径表示法派生数据的不同结果。

路径的语法值留给解析程序或过程,因为它不包含在字符串中,仅仅是一种表示法。

这类似于为什么一些应用程序允许正斜杠和反斜杠互换使用,例如,“C:/value”和“C:\value”都可以工作,而其他应用程序会引发错误。

英文:

> "... Now we can see that the we have this slash before the path and the functionality is still working. So is this an expected behavior?"

A system path is just a notation&mdash;it's not a syntax.

There is not a standardization for a notation&mdash;as the notation is, in and of itself, the standard.

There is an RFC for the file URI scheme, which will define the grammar of its path element.
RFC 8089 &ndash; The "file" URI Scheme.

From here, we can at least see what is used by an abstraction that encloses a path notation.

Here is the ABNF, from "Section 2, Syntax",

file-URI       = file-scheme &quot;:&quot; file-hier-part
file-scheme    = &quot;file&quot;
file-hier-part = ( &quot;//&quot; auth-path )
               / local-path
auth-path      = [ file-auth ] path-absolute
local-path     = path-absolute
file-auth      = &quot;localhost&quot;
               / host

And, path-absolute, as inherited by RFC 3986, under "Section 3.3, Path",

path-absolute = &quot;/&quot; [ segment-nz *( &quot;/&quot; segment ) ]
segment       = *pchar
segment-nz    = 1*pchar
pchar         = unreserved / pct-encoded / sub-delims / &quot;:&quot; / &quot;@&quot;

It would appear that it is simply a forward-slash delimited set of values, with a required forward-slash at the start.

So, you should expect to see different results from different applications that are attempting to derive data via a provided path notation.

The syntactic value of the path is left to the resolving program, or procedure, as it is not contained within the string, and is just a notation.

This is similar to why some applications will allow for interchangeable forward and backward slashes&mdash;e.g., "C:/value", and "C:\value" both work&mdash;and others will throw an error.

huangapple
  • 本文由 发表于 2023年6月22日 13:59:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/76528952.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定