Java - 无法在 Windows 上删除 Process 的临时输出文件

Java - Unable to delete temporary output file for Process on Windows

提问人:user12345 提问时间:10/20/2023 更新时间:10/20/2023 访问量:78

问:

在 Windows 上,我通过 .如果我的调用函数中断,在尝试清理进程及其标准输出日志文件时,我收到错误“进程无法访问该文件,因为它正在被另一个进程使用”。我确保先销毁子进程,然后删除日志文件。java.lang.ProcessBuilder

问题 - 在清理与平台无关的进程和日志文件时,是否有任何最佳实践?

下面是 Windows 的可重现示例。

下面的代码片段正在创建一个子进程。

public class UndeletableFileExample {
    public static void func() throws IOException {
        ProcessBuilder pb = null;
        Path stdout = null;
        Process p = null;
        long bufferTimeSecs = 30L;
        try {
            stdout = Files.createTempFile("example", ".log");
            pb = new ProcessBuilder("loop.cmd");
            pb.redirectErrorStream(true);
            pb.redirectOutput(stdout.toFile());
            p = pb.start();
            p.waitFor(bufferTimeSecs, TimeUnit.SECONDS);
            p.destroy();
            p.waitFor(bufferTimeSecs, TimeUnit.SECONDS);
            p.destroyForcibly();
            String out = Files.readString(stdout);
            int exitcode = p.exitValue();
            if(exitcode != 0) {
                throw new RuntimeException("Exited with code " + exitcode);
            }
            System.out.println(out);
        }
        catch(InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new RuntimeException("interrupted!");
        }
        finally {
            if(p != null) {
                p = p.destroyForcibly();
                while(p.isAlive()); // Is this while loop a potential problem?
                System.out.println(p.exitValue());
            }
            if(stdout != null) {
                Files.delete(stdout);
            }
        }
    }
}

下面的代码片段是 for 循环文件“loop.cmd”。它将打印从 1 到 1e5 的数字。这在我的机器上需要 20-30 秒。

FOR /L %%i IN (1,1,100000) DO echo %%i

以下代码片段是执行模拟的主程序。

public class Demo {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread() {
            @Override
            public void run() {
                try {
                    UndeletableFileExample.func();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        };
        t.start();
        Thread.sleep(2000L);
        t.interrupt();
        t.join();
    }
}

我还可以访问 MacOS 计算机。在清理进程和线程中断上的日志文件时,我没有遇到任何问题。

MacOS 的循环示例更改为 -

for i in `seq 1 1000000`; do echo $i; done

Windows 上的确切错误如下 -

Exception in thread "Thread-0" java.lang.RuntimeException: java.nio.file.FileSystemException: <...>\example1234.log: The process cannot access the file because it is being used by another process. 
Java 进程 inputstream outputstream

评论

0赞 VGR 10/21/2023
你应该改变 while(p.isAlive());自。Thread.onSpinWait 正是为此目的而存在的。while (p.isAlive()) { Thread.onSpinWait(); }
0赞 DuncG 10/21/2023
删除每次都对我有用。您使用哪个 JDK 进行了测试?
0赞 user12345 10/21/2023
@DuncG,在 Windows 上运行11.0.19+9
0赞 user12345 10/21/2023
@Computable我注意到,即使我有一个简单的 for 循环,删除也始终成功。这样for(int i = 0; i < 1000000; i++);Files.delete(stdout);

答: 暂无答案