Java Servlet:删除临时文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17877118/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java Servlet: delete temporary file
提问by Iordan Iordanov
I am working on a Java Servlet which creates a temporary file to use in a session. At the end of the session (ie, user "logout"), I need to remove the temporary file, and then redirect the user to the initial ("login") page. The redirection works fine, but the temporary file remains intact.
我正在开发一个 Java Servlet,它创建一个临时文件以在会话中使用。在会话结束时(即用户“注销”),我需要删除临时文件,然后将用户重定向到初始(“登录”)页面。重定向工作正常,但临时文件保持不变。
I presume it has something to do with the path to the file, but I am not quite sure as to what. I create the file when the session initiates:
我认为它与文件路径有关,但我不太确定是什么。我在会话启动时创建文件:
String path = request.getSession().getServletContext().getRealPath("/");
File file = File.createTempFile("getter", ".html", new File(path + "/tmp/"));
Then, when closing the session, I do:
然后,在关闭会话时,我会这样做:
file.delete();
I know about file.deleteOnExit()
, but... when do I exit a servlet? Perhaps I am confused, but I would surely appreciate any help! :)
我知道file.deleteOnExit()
,但是...我什么时候退出 servlet?也许我很困惑,但我肯定会感谢任何帮助!:)
Thank you in advance!
先感谢您!
EDIT
编辑
So, here come some details:
所以,这里有一些细节:
I am using a servlet, as I said, for the time being without handling sessions. I agree with @Joop that I will need to implement sessions, but for the time being just wanted to do some simple testing.
正如我所说,我正在使用 servlet,暂时不处理会话。我同意@Joop 的观点,我需要实现会话,但目前只想做一些简单的测试。
So, my servlet hagles GET
and POST
requests. I use a flag in the POST
request to call an internal function which instantiates the file (declared in the class as private File file;
) to a new temp file. On consecutive calls, the file gets populated and saved. In the page the user sees, I have an anchor referring to the servlet (to 'this', that is), passing a flag as a parameter, a flag that indicates the 'logout'. Then I call another internal function which deletes the file previously instantiated.
所以,我的 servlet 讨价还价GET
和POST
请求。我在POST
请求中使用一个标志来调用一个内部函数,该函数将文件(在类中声明为private File file;
)实例化为一个新的临时文件。在连续调用时,文件被填充并保存。在用户看到的页面中,我有一个引用 servlet 的锚点(即“this”),传递一个标志作为参数,一个指示“注销”的标志。然后我调用另一个内部函数来删除先前实例化的文件。
If it is a matter of sesions, I will implement the manager and post my findings.
如果是会话问题,我将实施经理并发布我的发现。
EDIT 2
编辑 2
I implemented an HttpSessionListener
, and all seems to work fine. Now, on creating the session, I instantiate a file in my previously declared directory (note that it is not a temp file, I use File file = new File(path + "/tmp/" + req.getSession().getId() + ".html");
so the name of the file equals the session ID). Then I add an attribute to the session, whose value is the full path to the file. I proceed to populate my file as always, and when the user selects to log out, I invalidate the session. Then, inside the listener, I retrieve the path to the file, hence I can acquire the pointer to it:
我实现了一个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();
So, now the messages I am getting are positive, I mean f.delete()
returns true, and after this I do f.exists()
and I get false
. So it should be OK. However, the files physically exist, that is they are still present on the disk.
所以,现在我得到的消息是肯定的,我的意思是f.delete()
返回 true,然后我做了f.exists()
,我得到false
. 所以应该没问题。但是,文件物理上存在,即它们仍然存在于磁盘上。
I can try the example so kindly provided by @A4L. Have I done something wrong..?
我可以尝试@A4L 提供的示例。我做错了什么..?
回答by BalusC
Please stop writing arbitrary files to deploy folder during runtime. Just write to a real temp folder instead. Get rid of the following line altogether:
请停止在运行时将任意文件写入部署文件夹。只需写入一个真正的临时文件夹即可。完全摆脱以下行:
path = request.getSession().getServletContext().getRealPath("/");
and just use
只需使用
File file = File.createTempFile("getter", ".html");
Your concrete problem is likely caused because the files in the deploy folder are usually locked by the servletcontainer. You can't delete files therein.
您的具体问题可能是因为 deploy 文件夹中的文件通常被 servletcontainer 锁定。您不能删除其中的文件。
A hint for the future: whenever you occur to think that the getRealPath()
could solve a problem, you should immediately stop writing code and think twice about whether it's the right tool to fix the concrete problem. In the decade I developed Servlet based web applications, there was no onesensible real world use case for that method. See also What does servletcontext.getRealPath("/") mean and when should I use it
对未来的提示:每当您认为它getRealPath()
可以解决问题时,您应该立即停止编写代码并三思它是否是解决具体问题的正确工具。在我开发基于 Servlet 的 Web 应用程序的十年中,该方法没有一个合理的现实世界用例。另请参阅servletcontext.getRealPath("/") 是什么意思,我应该什么时候使用它
I know about file.deleteOnExit(), but... when do I exit a servlet?
我知道 file.deleteOnExit(),但是……我什么时候退出 servlet?
You don't. The container does. The "exit" here basically means the shutdown of the whole JVM. This is even literally mentioned in the javadoc(emphasis mine).
你没有。容器可以。这里的“退出”基本上意味着整个 JVM 的关闭。这甚至在javadoc(强调我的)中逐字地提到。
Requests that the file or directory denoted by this abstract pathname be deleted when the virtual machine terminates.
请求在虚拟机终止时删除此抽象路径名表示的文件或目录。
回答by A4L
Make sure you have closed the file before attempting to delete it when the user logs out and check what File#delete()
returns.
在用户注销并检查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
}
With File#deleteOnExit()the file will be deleted twhen the VM exits, this happen when your tomcat is shutdown. So it won't help on user logout.
使用File#deleteOnExit()文件将在 VM 退出时被删除,这发生在您的 tomcat 关闭时。所以它对用户注销没有帮助。
EDIT
编辑
Make sure you have only one file per user and across mutiple requests. I suggest you use a SessionListener
as Joop suggested, create the file when HttpSessionListener#sessionCreatedis called and put it into the session with a well known key, you can get the session object using HttpSessionEvent#getSession(). When you logout call HttpSession.#invalidate(), the Listner method HttpSessionListener#sessionDestroyedwill be called, then you can get the file from the session and delete it.
确保每个用户和多个请求只有一个文件。我建议您使用SessionListener
Joop 建议的方法,在调用HttpSessionListener#sessionCreated时创建文件,并使用众所周知的密钥将其放入会话中,您可以使用HttpSessionEvent#getSession()获取会话对象。当您注销调用HttpSession.#invalidate() 时,Listner 方法HttpSessionListener#sessionDestroyed将被调用,然后您可以从会话中获取文件并将其删除。
Simple example, (doGet only and without SessionListener)
简单示例,(仅 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>");
}
}
回答by Joop Eggen
Every call to createTempFile
gives another path, so the path has to be stored.
每次调用createTempFile
都会给出另一条路径,因此必须存储该路径。
See SessionListener. Example- if session timeout is involved.
请参阅SessionListener。示例- 如果涉及会话超时。
Maybe use the JSESSIONID as directory with temp files and delete the directory.
也许使用 JSESSIONID 作为带有临时文件的目录并删除该目录。
BTW I presume you invalidate the session afterfile.delete()
as otherwise getSession()
would create a new session. I would log file.getPath()
.
顺便说一句,我认为您会在之后使会话无效file.delete()
,否则getSession()
会创建一个新会话。我会登录file.getPath()
。
回答by saurav
You can also use the deleteOnExit() method ... please have a look at the java doc of the createTempFile() -
您还可以使用 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.