我正在开发一个Java Servlet,它创建一个在会话中使用的临时文件。在会话结束时(即用户“注销”),我需要删除临时文件,然后将用户重定向到初始(“登录”)页面。重定向工作正常,但临时文件保持不变。
我认为它与文件的路径有关,但我不确定是什么。我在会话启动时创建文件:
String path = request.getSession().getServletContext().getRealPath("/");
File file = File.createTempFile("getter", ".html", new File(path + "/tmp/"));
然后,在结束会话时,我这样做:
file.delete();
我知道file.deleteOnExit()
,但是...什么时候退出servlet?也许我很困惑,但我肯定会感激任何帮助! :)
提前谢谢!
修改
所以,这里有一些细节:
我正在使用servlet,就像我说的那样暂时没有处理会话。我同意@Joop我需要实现会话,但暂时只是想做一些简单的测试。
因此,我的servlet处理GET
和POST
个请求。我在POST
请求中使用一个标志来调用一个内部函数,该函数将文件(在类中声明为private File file;
)实例化为新的临时文件。在连续调用时,将填充并保存文件。在用户看到的页面中,我有一个引用servlet的锚(对于'this',即),传递一个标志作为参数,一个标志指示'注销'。然后我调用另一个内部函数来删除先前实例化的文件。
如果这是一个问题,我会实施经理并发布我的发现。
编辑2
我实施了HttpSessionListener
,似乎一切正常。现在,在创建会话时,我在先前声明的目录中实例化一个文件(请注意,它不是临时文件,我使用File file = new File(path + "/tmp/" + req.getSession().getId() + ".html");
,因此文件名等于会话ID)。然后我向会话添加一个属性,其值是文件的完整路径。我一如既往地继续填充我的文件,当用户选择注销时,我使会话无效。然后,在侦听器内部,我检索文件的路径,因此我可以获取指向它的指针:
String fname = ev.getSession().getAttribute("filename").toString();
File f = new File(fname);
f.delete();
所以,现在我收到的消息是肯定的,我的意思是f.delete()
返回true,然后我f.exists()
得到false
。所以应该没问题。但是,文件实际存在,即它们仍然存在于磁盘上。
我可以试试@ A4L友好提供的例子。我做错了什么..?
答案 0 :(得分:7)
请在运行时停止编写任意文件以部署文件夹。只需写入真正的临时文件夹即可。完全摆脱以下几行:
path = request.getSession().getServletContext().getRealPath("/");
然后使用
File file = File.createTempFile("getter", ".html");
您可能会遇到具体问题,因为deploy文件夹中的文件通常由servletcontainer锁定。你无法删除其中的文件。
对未来的暗示:每当您认为getRealPath()
可以解决问题时,您应该立即停止编写代码并三思而后行,以确定它是否是解决具体问题的正确工具。在这十年中我开发了基于Servlet的Web应用程序,该方法有没有人明智的真实世界用例。另请参阅What does servletcontext.getRealPath("/") mean and when should I use it
我知道file.deleteOnExit(),但是...什么时候退出servlet?
你没有。容器呢。这里的“退出”基本上意味着关闭整个JVM。甚至在the javadoc(强调我的)中也提到了这一点。
请求在虚拟机终止时删除此抽象路径名表示的文件或目录。
答案 1 :(得分:0)
确保在用户注销时尝试删除文件并关闭文件并检查File#delete()
返回的内容时,已关闭该文件。
@Test
public void createTempFile() throws IOException {
File tf = File.createTempFile("hello", ".tmp", new File("."));
FileOutputStream fos = new FileOutputStream(tf);
fos.write("Hello, Temp!".getBytes());
Assert.assertTrue(tf.delete()); // fails because the file could not be deleted
// and delete() returns false
}
<强> VS 强>
@Test
public void createTempFile() throws IOException {
File tf = File.createTempFile("hello", ".tmp", new File("."));
FileOutputStream fos = new FileOutputStream(tf);
fos.write("Hello, Temp!".getBytes());
fos.close();
Assert.assertTrue(tf.delete()); // passes, file deleted
}
使用File#deleteOnExit()文件将在VM退出时被删除,这会在您的tomcat关闭时发生。所以它对用户注销无济于事。
修改强>
确保每个用户只有一个文件和多个请求。我建议您使用SessionListener
作为Joop建议,在调用HttpSessionListener#sessionCreated时创建文件并使用众所周知的密钥将其放入会话中,您可以使用HttpSessionEvent#getSession()获取会话对象。当您注销呼叫HttpSession.#invalidate()时,将调用Listner方法HttpSessionListener#sessionDestroyed,然后您可以从会话中获取该文件并将其删除。
简单示例,(仅限doGet且没有SessionListener)
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@WebServlet(urlPatterns = "/ptf.html")
public class PopulateTempFile extends HttpServlet {
private static final long serialVersionUID = -144949663400032218L;
private static class TempFilePopulator {
private File tf = null;
public TempFilePopulator(String rootDir) throws IOException {
tf = File.createTempFile("hello", ".tmp", new File(rootDir));
}
public void populate(String line) throws IOException {
FileWriter fw = new FileWriter(tf, true);
fw.write(line + "\n");
fw.close();
}
public List<String> getContent() throws IOException {
List<String> lines = new ArrayList<String>();
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(tf)));
String line;
while(null != (line = br.readLine())) {
lines.add(line);
}
br.close();
return lines;
}
public boolean deleteTempFile() { return tf.delete(); }
public String toString() { return tf.getAbsolutePath(); }
}
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
HttpSession session = request.getSession();
TempFilePopulator tfp = (TempFilePopulator) session.getAttribute("tempfilepopulator");
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<a href=\"" + request.getServletContext().getContextPath()
+ request.getServletPath() + "\">Refresh</a>");
out.println(" | ");
out.println("<a href=\"" + request.getServletContext().getContextPath()
+ request.getServletPath() + "?logout=true\">Logout</a>");
String logout = request.getParameter("logout");
if("true".equals(logout)) {
if(tfp != null) {
if(tfp.deleteTempFile()) {
log("Temp file '" + tfp + "' deleted.");
} else {
log("Unable to delete temp file '" + tfp + "'");
}
}
session.invalidate();
} else {
if(tfp == null) {
tfp = new TempFilePopulator(request.getServletContext().getRealPath("/"));
log("Temp file '" + tfp + "' created.");
session.setAttribute("tempfilepopulator", tfp);
}
tfp.populate(new Date().toString());
out.println("<p>Content of temp file</p>");
List<String> lines = tfp.getContent();
for(String line : lines) {
out.write(line);
out.write("<br/>");
}
}
out.println("</html>");
}
}
答案 2 :(得分:0)
每次调用createTempFile
都会给出另一条路径,因此必须存储路径。
见SessionListener。 Example - 如果涉及会话超时。
也许使用JSESSIONID作为临时文件的目录并删除目录。
BTW我认为你在 file.delete()
之后使会话无效,否则getSession()
会创建一个新会话。我会记录file.getPath()
。
答案 3 :(得分:0)
你也可以使用deleteOnExit()方法...请看一下createTempFile()的java文档 -
Creates a new empty file in the specified directory, using the given prefix and
suffix strings to generate its name. If this method returns successfully then
it is guaranteed that:
The file denoted by the returned abstract pathname did not exist before this
method was invoked and ,
Neither this method nor any of its variants will return the same abstract
pathname again in the current invocation of the virtual machine.
This method provides only part of a temporary-file facility. To arrange
for a file created by this method to be deleted automatically, use the
deleteOnExit() method.