我正在开发一个webapp(用于手机)。有一个xhtml页面,我想要显示一张图片,它本地存储在我的硬盘上(例如:D:\ pictures \ test.jpg)。 由于浏览器在位于本地硬盘上时会阻止图像,因此我在javabean中编写了一个方法,当用户进入xhtml页面时,存储在localHD上的图片被复制到webApp目录。用户离开页面后,应删除webapp中复制的文件。 因此,当我运行我的应用程序时,复制工作完美,图片显示正确。但是,当文件被删除时,我会收到此错误消息:
java.nio.file.FileSystemException:D:\ WebAppPath \ src \ main \ webapp \ resources \ pics \ test.jpg: 无法访问该进程,因为该文件正由另一个进程使用。
奇怪的是,在停止并重新启动应用程序后,如果它仍在webApp目录中,我可以删除相同的图像。 (但只有一次;重新复制后,我再次收到错误消息。)
此外,如果我想手动删除文件,使用Windows资源管理器,我会收到错误消息,该文件无法删除,因为它由Java(TM)Platform SE Binary使用。
因此,要删除文件(手动或通过bean),我必须等待重新启动应用程序,这当然不是最终用户可接受的解决方案。
我正在使用带有Primefaces和Primefaces Mobile组件的JSF2.0。我的IDE是Netbeans,我使用Spring Webflow框架来导航和触发xhtml页面之间的动作/方法。
以下是我的JavaBean中复制方法的代码:
public void copyFotoToLocalhost() {
if (fotoList.size() > 0) {
for (int i = 0; i < fotoList.size(); i++) {
Foto tempPic = fotoList.get(i);
String tempItemName = tempPic.getItemName();
String originalFile = "D:\\localFilepath\\" + tempItemName;
String tempFileName = "D:\\WebAppPath\\src\\main\\webapp\\resources\\pics\\" + tempItemName;
File existTest = new File(tempFileName);
if (existTest.exists() == false) {
try {
File orFile = new File(originalFile);
File tempFile = new File(tempFileName);
InputStream in = new FileInputStream(orFile);
OutputStream out = new FileOutputStream(tempFile);
byte[] buf = new byte[8192];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.close();
tempFile.setWritable(true);
System.out.println("File copied.");
} catch (FileNotFoundException ex) {
System.out.println(ex.getMessage() + " in the specified directory.");
System.exit(0);
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
}
}
}
以下是删除方法的代码:
public void deleteFotos() {
if (fotoList.size() > 0) {
for (int i = 0; i < fotoList.size(); i++) {
Foto tempPic = fotoList.get(i);
String tempItemName = tempPic.getItemName();
Path tempLocation = Paths.get("D:\\webAppPath\\src\\main\\webapp\\resources\\pics\\" + tempItemName);
fotoList.remove(i);
i--;
try {
Files.deleteIfExists(tempLocation);
System.out.println("sucessfully deleted" + tempPic.getItemName());
} catch (IOException ex) {
Logger.getLogger(WundDokuBean.class.getName()).log(Level.SEVERE, null, ex);
System.out.println("Fail @ " + tempPic.getItemName());
}
}
fotoList.clear();
}
你有什么想法,如何解决这个问题?
我希望你理解我的问题,如果没有,请告诉我你需要哪些信息,我会尽力提供。
答案 0 :(得分:1)
有一个xhtml页面,我想要显示一张图片,它本地存储在我的硬盘上(例如:D:\ pictures \ test.jpg)。由于浏览器在图像位于本地硬盘(...)
时会阻止图像
我想首先清除一个概念上的误解:你似乎期望它在浏览器没有阻止它时能正常工作。这完全是不真实的。您似乎期望图像在HTML输出中内联。不,它们是单独下载并独立于HTML页面下载的。如果您继续使用本地磁盘文件系统路径,那么它只会起作用,并且只有当您的网页访问者完全同一文件完全同一位置时他们的磁盘文件系统。实际上,情况显然并非如此。只有当webbrowser和webserver都在同一台机器上运行时,它才会起作用。
回到你无法删除文件的具体问题,这是因为servletcontainer通常将文件锁定在扩展的WAR文件夹中。我无法确切地说出原因,但这并不重要,因为无论如何这整个方法都是错误的。如果部署的WAR文件未在磁盘文件系统上展开,而是在服务器的内存中展开,则此方法将失败。此外,硬编码环境特定的磁盘文件系统路径是一个坏主意。每次更改环境时,您都需要编辑,重写,重新编译,重建整个WAR。换句话说,您的网络应用程序不可移植。
您需要将文件保留在原始位置,并通过真实URL公开提供。这可以通过两种一般方式实现:
将虚拟主机添加到服务器配置,指向D:\localFilepath\
。如何实现这取决于所使用的服务器。您没有说明使用的服务器make /版本,但是使用Spring表明您无法使用完整的Java EE堆栈,并且可能正在使用诸如Tomcat之类的准系统JSP / Servlet容器。在这种情况下,需要在/conf/server.xml
添加以下行:
<Context docBase="D:\localFilepath" path="/fotos" />
这种方式可以http://localhost:8080/fotos/*
使用。
创建一个servlet,它从D:\localFilepath
读取文件并写入HTTP响应。使用Servlet 3.0和Java 7,它真的很轻松。这是一个启动示例(为了简洁省略了nullchecks / file-exist-checks / doHead()
/缓存/恢复):
@WebServlet("/fotos/*")
public class FotosServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletExcpetion, IOException {
File file = new File("D:/localFilepath", request.getPathInfo().substring(1));
response.setHeader("Content-Type", getServletContext().getMimeType(file.getName()));
response.setHeader("Content-Length", String.valueOf(file.length()));
Files.copy(file.toPath(), response.getOutputStream());
}
}
基本上就是这样。这样,它们就可以在http://localhost:8080/contextname/fotos/*
上找到。