2016-05-17 63 views
3

我有以下代码:Files.newOutputStream(路径,CREATE_NEW,DELETE_ON_CLOSE)不写入文件

import java.io.IOException; 
import java.io.OutputStream; 
import java.nio.file.Files; 
import java.nio.file.Paths; 

import static java.nio.file.StandardOpenOption.CREATE_NEW; 
import static java.nio.file.StandardOpenOption.DELETE_ON_CLOSE; 

public class Test { 
    public static void main(String[] args) throws IOException { 
     try (OutputStream outputStream = Files.newOutputStream(Paths.get("test"), CREATE_NEW, DELETE_ON_CLOSE)) { 
      outputStream.write(123); 
      outputStream.flush(); 
      System.out.println("done"); 
     } 
    } 
} 

我把一个破发点上的呼叫以System.out.println和检查我的工作目录。没有文件叫做test。为什么输出流不写入文件?

+0

嗯......对我的作品(使用'Thread.sleep'而不是断点)。你在运行什么操作系统? –

+0

OSX。如果我删除'DELETE_ON_CLOSE',它对我也有用。 – Max

+0

我认为发生的事情是基于Unix的操作系统立即删除该文件,因为具有打开文件句柄的已删除文件仍然可以被访问。虽然这似乎违反了API。 – Max

回答

3

原因是,在Linux上,即使文件已打开,也可以从目录中删除文件(适当的权限在此默默承担)。在Windows下,这是不可能的。

sun.nio.fs.UnixChannelFactory

//源立即断开链接文件,如果在关闭删除。该规范明确指出:
//当攻击者打开后,攻击者可以用
代替执行程序。
如果(flags.deleteOnClose){ ...

如果你作为

for (int i = 0; i < 10; i++) { 
    outputStream.write(123); 
    outputStream.flush(); 
    System.out.println("flush..."); 
    Thread.sleep(10_000); 
} 

你都能够看到该文件是开放的,但已经删除

# assumed that the code write to Paths.get("/tmp/test") 
lsof | grep "/tmp/test" 
... /tmp/test (deleted) 
修改代码

编辑如果您只想确保在应用程序退出时删除临时文件,请查看sn下面的ippet。

import java.io.File; 
import java.io.OutputStream; 
import java.nio.file.Files; 
import static java.nio.file.StandardOpenOption.CREATE_NEW; 
public class Main { 
    public static void main(String[] args) throws Exception { 
     File file = new File("/tmp/test"); 
     file.deleteOnExit(); 
     System.out.println("tempFile = " + tempFile); 
     try (OutputStream outputStream = Files.newOutputStream(file.toPath(), 
       CREATE_NEW)) { 
      outputStream.write(123); 
      outputStream.flush(); 
      System.out.println("done"); 
     } 
     System.out.printf("%s exists: %s%n", file, file.exists()); 
    } 
} 

文件/tmp/test将在应用程序完成时被删除。

输出(文件此时仍然存在)

/tmp/test exists: true 

,如果你现在的控制台

$ ls /tmp/test 
ls: cannot access '/tmp/test': No such file or directory 

对检查如果你甚至不关心你可能会考虑的文件名使用随机生成的一个。

File tempFile = File.createTempFile("foo_", ".tmp", new File("/tmp")); 

编辑另一种解决办法是。

  1. 创建文件(喜欢使用一个随机的临时文件名)
  2. 打开InputStream
  3. 打开OutputStreamDELETE_ON_CLOSE

的顺序做它,你期望它会工作。

查找以下工作片段。

import java.io.IOException; 
import java.io.InputStream; 
import java.io.OutputStream; 
import static java.nio.charset.StandardCharsets.UTF_8; 
import java.nio.file.Files; 
import java.nio.file.Path; 
import java.nio.file.Paths; 
import static java.nio.file.StandardOpenOption.APPEND; 
import static java.nio.file.StandardOpenOption.DELETE_ON_CLOSE; 
import static java.nio.file.StandardOpenOption.READ; 

public class DeleteOnClose { 

    public static void main(String[] args) throws IOException { 
     Path path = Paths.get("/tmp/test"); 
     System.out.println("before create: " + Files.exists(path)); 
     Files.createFile(path); 
     System.out.println("after create: " + Files.exists(path)); 
     try (InputStream in = Files.newInputStream(path, READ); 
       OutputStream out = Files.newOutputStream(path, APPEND, 
         DELETE_ON_CLOSE)) { 
      out.write("Hello file!".getBytes(UTF_8)); 
      out.flush(); 

      for (int c = in.read(); c >= 0; c = in.read()) { 
       System.out.print((char) c); 
      } 
      System.out.println(); 
     } 
     System.out.println("after close: " + Files.exists(path)); 
    } 
} 

输出

before create: false 
after create: true 
Hello file! 
after close: false 
+0

'deleteOnExit'不适用于我,因为这是一个长期运行的过程(服务)。在JVM存在之前,使用'deleteOnExit'可能会导致磁盘变满。 – Max

+0

@Max您能否提供有关如何使用此文件的更多信息。由于目前您只能创建一个“只写”文件,因此要在关闭时删除。在目前的情况下似乎没有任何意义。是否有另一个从该文件读取的进程/任务?你能否提供一个代码片段,你想从那个文件中读取。 – SubOptimal

+0

当然。我接受一个文件作为休息服务中的上传文件。我最终会将该文件作为流传递给另一个服务,但我需要先评估上传文件的内容。鉴于该文件相当大,我不想将它全部存储在内存中。现在我只是在'finally'块中删除文件。这是好的,它只是看起来像'DELETE_ON_CLOSE'会是一个更好的贴合,但显然不是。 – Max

相关问题