如何使用JSch进行原子SFTP文件传输,以便在写入过程完成之前该文件不可访问?

时间:2014-08-04 12:49:05

标签: java sftp jsch

我编写了一个小型Java程序,它使用Jsch将多个文本文件传输到远程服务器。 由于单个文件可能会变得很大,因此传输最多需要20秒。

在远程服务器上,将在我无法控制的各个时间点访问(读取)生成的文件。我已经测试过在服务器上的SFTP传输过程中复制文件。复制的文件没有完整的数据,因为它在复制命令时完全不可用。

如何确保只有在传输完成后才能访问该文件,以便可以完全读取该文件? 由于我无法控制远程服务器上的文件访问,因此我需要一种方法从我的Java程序中执行此操作。

以下是我写的代码的相关部分:

InputStream contentInputStream = null;
try {
    contentInputStream = new ByteArrayInputStream(Files.readAllBytes(Paths.get("test1.txt")));
} catch (IOException e) {
    e.printStackTrace();
}
sftpChannel.put(contentInputStream, "abc.txt");

3 个答案:

答案 0 :(得分:3)

您将文件写入远程服务器上的目录,远程服务器上的某些进程正在监视文件是否出现在那里。在文件完全写入服务器之前,您不希望远程进程对文件执行操作。

设置此系统的任何人都应该考虑到这个问题而设计它。在服务器之间传输文件需要时间,传输也可能在完成之前失败。需要有一种设计方式将文件传输到服务器,然后使它们可用于此远程进程。

有三种常见的方法可以做到这一点:

将文件写入另一个文件夹:将文件写入"临时文件"或者"工作"远程服务器上的目录,不受远程进程监视。文件传输完成后,将文件从临时目录移动到实际目标目录。将文件从一个目录移动到另一个目录应该是一个瞬时操作。 SFTP允许在远程服务器上将文件从一个目录移动到另一个目录。

将文件写入特殊文件名:将文件写入远程系统上的目标目录,但使用远程进程将忽略的特殊文件名。文件传输完成后,将文件重命名为具有正确的名称。例如,如果远程进程正在查找以" .xml"结尾的文件名,则您将创建一个名为" foo.xml.tmp"的文件。在远程服务器上,将数据写入其中,然后将其重命名为" foo.xml.tmp" to" foo.xml"。 SFTP允许重命名远程服务器上的文件。

使用修改时间戳:远程进程可以检查要处理的文件的最后修改时间戳,并忽略在最后一分钟左右修改过的文件。此行为必须内置到远程进程中。 SFTP有一个操作来设置远程文件的修改时间戳,JSCH支持它,但你通常不会明确地调用这个函数。通常,您依赖远程文件的最后修改时间戳来反映您的进程写入文件。

答案 1 :(得分:1)

  

你不能。

     

远程服务器上的文件访问纯属"远程服务器事物"。如果   无论SFTP服务器应用程序没有将文件标记为   无法访问,然后默认可访问。

     

您可以在几乎所有SFTP服务器应用中设置此类默认权限   我知道,所以这是你应该搜索的解决方案。

我给出的完全错误的答案......留下来"记录"。

答案是sftp.chmod()方法。您可以删除对该文件的所有访问权限,直到将其上传。

答案 2 :(得分:0)

SFTP协议仅支持从版本5开始的显式锁定。虽然JSch仅支持协议的版本3(大多数服务器也是如此)。

所以你必须自己以某种方式破解它。例如。比如@Xabster建议。