gpt4 book ai didi

java - 上下文 getRealPath() 用于不存在的文件

转载 作者:行者123 更新时间:2023-12-01 14:27:52 26 4
gpt4 key购买 nike

谁能解释一下在 Tomcat 中对 ServletContext getRealPath() 的以下两次调用之间的区别是什么:

  • context.getRealPath("/") + "\\songModified.wav";
  • context.getRealPath("/"+ "\\songModified.wav");

我在服务器上有一个非常简单的 GET 方法,它读取服务器上的文件并将字节复制到上述调用返回的位置的新文件中。

在客户端,我有一个引用服务器上音频文件的音频标签,调用此方法创建一个新文件并将音频标签的引用更改为这个新文件。问题是,在 javascript 回调中,如果我将文件存储到从上述 getRealPath 调用的第二种情况返回的路径,则不能立即引用这个新文件。基本上它返回一个 404。如果我将它存储到第一个调用案例的返回路径中,那么它立即可引用并且音频标签通常引用新文件。

这两个对 getRealPath() 的调用都返回完全相同的字符串:

C:\Users\Mihael\apache-tomcat-9.0.31\wtpwebapps\AudioSimulator\songModified.wav

我将这个返回的字符串进一步传递给代码中的 FileOutputStream 构造函数。

这里要注意的是,在调用 getRealPath() 时该文件不存在,所以我很困惑为什么在调用的第二种情况下它根本不返回任何内容。

我知道这不是推荐的文件存储方式,所以我是从纯粹的教育角度提问的。如果第二次调用此方法都向其余代码返回完全相同的字符串,怎么会破坏我的功能?

编辑:

这是一个非常简单的 Javascript 和 Java 代码,供任何想要测试它的人使用。

Javascript:

<body>
<script>

function modifyRequest() {
var xhttp = new XMLHttpRequest();

xhttp.onload = function() {
var audio = document.getElementById("player");
var currentTime = audio.currentTime;
audio.src = "http://localhost:8080/AudioSimulator/bluesModified.wav";
audio.currentTime = currentTime;
audio.play();
};

xhttp.open("GET", "http://localhost:8080/AudioSimulator/rest/Test/testPath");
xhttp.send();
}

</script>

<audio id="player" src="http://localhost:8080/AudioSimulator/blues.wav"
controls>
Your browser does not support the
<code>audio</code> element.
</audio>

<button onclick="modifyRequest()">Test</button>

</body>

java :

    @Path("/Test")
public class Test {

@Context
ServletContext context;

@GET
@Path("/testPath")
public Response testPath() {
File fileIn = new File(context.getRealPath("/") + "\\blues.wav");
File fileOut = new File(context.getRealPath("/" + "\\bluesModified.wav"));
//if i write it like this it would work
//File fileOut = new File(context.getRealPath("/") + "\\bluesModified.wav");

FileInputStream fis = null;
FileOutputStream fos = null;

try {
fis = new FileInputStream(fileIn);
fos = new FileOutputStream(fileOut);
byte[] inArray = new byte[(int) fileIn.length()];
try {
fis.read(inArray);
fos.write(inArray);
} catch (IOException e) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}

return Response
.ok()
.entity("Success")
.header("Access-Control-Allow-Origin", "null")
.build();
}

}

最佳答案

我已花时间深入 Tomcat 源代码以找出造成这种情况的原因。事实证明,getRealPath 除了为给定的虚拟 路径检索系统路径外,还可以与 Tomcat 缓存一起使用。

注意:

我知道我的文件分隔符使用不当,但 Tomcat 足够聪明,可以验证上述调用以生成 /bluesModified.wav。因此,即使我像评论中提到的 @rickz 那样调用它,结果也是一样的,因此这不是问题所在。

在以下调用的情况下我无法引用该文件的问题

context.getRealPath("/" + "\\bluesModified.wav")

事实上,在这种情况下,我们将文件路径传递给方法,而在可行的情况下,我们将传递目录路径。

调用 getRealPath() 首先检查缓存中是否存在由 webapppath /bluesModified.wav 标识的资源。由于在调用时它不存在,Tomcat 将创建一个 EmptyResource 类的实例,它基本上是 File 类的包装器,代表一个不存在的文件存在,然后它会将对该文件的引用存储在其缓存中。

这里的问题是,即使我创建了一个具有正确虚拟路径的文件,Tomcat 仍然会在其缓存中拥有代表不存在文件的空资源。换句话说,如果我像这样从客户端引用文件

http://localhost:8080/AudioSimulator/bluesModified.wav

Tomcat 将返回表示空文件的缓存资源,这实际上意味着一个404 给客户端,即使该文件存在。

等待 5 秒,这是 Tomcat 缓存条目的生存时间,然后尝试引用该文件将重新验证缓存条目并生成 FileResource 而不是 EmptyResource 在这种情况下引用将正常工作。

在这种情况下有效

context.getRealPath("/") + "\\bluesModified.wav"

因为被缓存的路径是一个目录,文件名只是简单地连接在一起。所以我这里的字符串只是我要创建的文件的绝对路径,没有缓存条目与之冲突。

我的错误是假设 getRealPath() 只是一些“纯”方法,它将返回一个字符串,我可以用它来创建文件,但实际上它有一些副作用。这些副作用没有记录在案,即使我可能做错了一些事情,但底线是这种方法在执行文件 IO 时使用起来并不那么可预测。

关于java - 上下文 getRealPath() 用于不存在的文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60554328/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com