我使用itext 5和java生成pdf文件,并将它们保存在本地,然后将这些本地保存的文件保存在awss3上。有没有一种方法可以直接将它们发送到s3,而不必在本地保存它们。我见过一些例子,但没有一个对我有用。
这就是我生成pdf文件的方式
String path = //local directory on my computer
Document document = new Document();
PdfWriter pdfWriter = PdfWriter.getInstance(document, new FileOutputStream(path));
document.open();
// add text to document
document.close();
我就是这样把它保存在s3上的
public void saveFileToS3(String pathLocal, String pathAws) {
// init aws
PutObjectRequest objectRequest = PutObjectRequest.builder()
.bucket(bucketName)
.key(folderName + "/" + pathAws)
.build();
CompletableFuture<PutObjectResponse> future = s3Client.putObject(objectRequest,
AsyncRequestBody.fromFile(Paths.get(pathLocal))
);
future.whenComplete((resp, err) -> {
try {
if (resp != null) {
System.out.println("Object uploaded. Details: " + resp);
} else {
err.printStackTrace();
}
} finally {
s3Client.close();
}
});
future.join();
}
string pathlocal是我在本地保存文件的路径,而string pathaws是s3上保存文件的路径。
2条答案
按热度按时间iyfamqjs1#
首先是旁注:
new FileOutputStream(path)
你的代码是错误的;如果不通过try-with-resources保护资源,就不能创建新资源(比如表示实际资源的流/读/写器:网络上的套接字、磁盘上的文件等等)。不过,一般来说,你不希望这里有一个fos。您希望有一个流,使任何字节产生的pdf生成代码和发送通过
thatOutputStream.write
直接放到网络上。这有点可能,但在这种情况下并不容易。
首先,让我解释一下这些库所关心的问题,以便您完全理解为什么这不太容易,并且您可以因此判断各种解决方案是否适合您的特定项目。
问题的核心是,您有两个独立的进程,每个进程都依赖于另一个进程。
pdf gen代码想要生成pdf字节,并且想要完全的自由:如果它需要查询数据库作为工作的一部分,它希望能够做到这一点。但是,它受到输出通道的限制:理论上,它可能每秒生成许多GB:如果输出通道“已满”,它希望最终停止自己(阻止其线程,或者将控制权放弃给正在处理其输出的任何对象,以便可以处理一堆输出)。例如,如果您的磁盘可以以1gb/s的速度存储,而您的pdf代码正在生成无限大小的pdf,并且可以以2gb/s的速度进行存储,则pdf代码需要减慢速度。
输出通道代码(在本例中是awss3 putobject代码)也希望有阻塞的自由:如果网络缓冲区已满,它必须等待:毕竟,它将数据包从计算机背面推出的速度是有限的。它还受到输入的限制:如果pdf gen代码以1gb/s的速度生成,但是aws s3 putobject代码可以以2gb/s的速度发送,那么putobject代码必须减慢自己的速度;如果没有要发送的字节,它将无法发送更多的字节。
通常在java代码中,模型非常简单:一方(生产者或消费者)被认为是控制的,而不是瓶颈。例如,如果您有生成无限个零并将其写入磁盘的代码:
非常简单的代码。但是,请注意,这里控制的“生产者”一方实际上是有障碍的。这个
write
方法块—如果磁盘正忙于处理,则write
方法不会立即返回。当磁盘忙于处理所有数据时,cpu处于空闲状态。它本可以花时间制造更多的零!在这个例子中,这是愚蠢的-中央处理器可以产生零难以置信的快,生产代码是许多数量级快于'消费'代码,这是有道理的生产方只是冷静了一点,因为消费者正忙于处理这一切。
但是想象一下工作方式有点不同的代码:与其编写源源不断的零,不如想象一下挖掘比特币的代码,并编写挖掘块(每个块价值数千美元,这应该表明它们生成的速度有多慢)。一个月一次已经非常令人印象深刻了)。很明显,这个障碍在这个意义上是愚蠢的:cpu应该忙于挖掘比特币,而不是在等待磁盘时摆弄拇指。在这种情况下,您希望两个进程(或者至少是较慢的进程,在本例中是生产者)永远不要等待另一方。不应该让瓶颈等待。
忙于生成pdf数据的代码在希望将数据发送到putobject代码时正在进行for循环,而putobject代码在希望获得更多pdf数据时正在计算数据段上的哈希。如果任何一方都不应该在另一方忙的时候转动拇指,那么除了拥有2根光纤(有效的是stacktraces)并让这些光纤互相传递数据之外,就没有别的出路了。在java中,这必须通过线程来完成——ProjectLoom即将面世,它将为您提供有趣的单核选项,但是ProjectLoom还不是java的一部分。
PutObjectCode就是围绕这个想法专门设计的;通常,输出通过返回
OutputStream
;Files.newOutputStream
返回1,也返回1new FileOutputStream()
,也是socket.getOutputStream
,也一样servletHttpResponse.getOutputStream()
. 但不是对象:它不返回任何东西;它需要一个输入流。类似地,pdf代码也不返回任何内容,它需要一个outputstream。因此,困境。
不过,线程解决方案非常简单。你需要一个线程来生成pdf,一个线程来发送给aws。你用管道把两者连接起来。
另一种解决方案是回到模型中,一方只需等待一段时间,然后摆弄自己的大拇指,但awsapi不支持它。下面是一个要点,它试图通过使用multipart特性来提供给您。
k75qkfdt2#
所以我找到了一种方法,我把itext文件转换成字节数组,然后把pdf文件上传成字节数组
当上传到s3时,我传递的是字节,而不是像以前那样传递文件路径