我必须使用SFTP从ZIP存档(只有一个文件,我知道它的名称)中获取文件内容。我唯一拥有的是ZIP InputStream
。大多数示例显示如何使用此语句获取内容:
ZipFile zipFile = new ZipFile("location");
但正如我所说,我的本地机器上没有ZIP文件,我也不想下载它。 InputStream
是否足以阅读?
UPD:我就是这样做的:
import java.util.zip.ZipInputStream;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
public class SFTP {
public static void main(String[] args) {
String SFTPHOST = "host";
int SFTPPORT = 3232;
String SFTPUSER = "user";
String SFTPPASS = "mypass";
String SFTPWORKINGDIR = "/dir/work";
Session session = null;
Channel channel = null;
ChannelSftp channelSftp = null;
try {
JSch jsch = new JSch();
session = jsch.getSession(SFTPUSER, SFTPHOST, SFTPPORT);
session.setPassword(SFTPPASS);
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect();
channel = session.openChannel("sftp");
channel.connect();
channelSftp = (ChannelSftp) channel;
channelSftp.cd(SFTPWORKINGDIR);
ZipInputStream stream = new ZipInputStream(channelSftp.get("file.zip"));
ZipEntry entry = zipStream.getNextEntry();
System.out.println(entry.getName); //Yes, I got its name, now I need to get content
} catch (Exception ex) {
ex.printStackTrace();
} finally {
session.disconnect();
channelSftp.disconnect();
channel.disconnect();
}
}
}
答案 0 :(得分:17)
下面是一个关于如何提取ZIP文件的简单示例,您需要检查该文件是否是目录。但这是最简单的。
您缺少的步骤是读取输入流并将内容写入写入输出流的缓冲区。
// Expands the zip file passed as argument 1, into the
// directory provided in argument 2
public static void main(String args[]) throws Exception
{
if(args.length != 2)
{
System.err.println("zipreader zipfile outputdir");
return;
}
// create a buffer to improve copy performance later.
byte[] buffer = new byte[2048];
// open the zip file stream
InputStream theFile = new FileInputStream(args[0]);
ZipInputStream stream = new ZipInputStream(theFile);
String outdir = args[1];
try
{
// now iterate through each item in the stream. The get next
// entry call will return a ZipEntry for each file in the
// stream
ZipEntry entry;
while((entry = stream.getNextEntry())!=null)
{
String s = String.format("Entry: %s len %d added %TD",
entry.getName(), entry.getSize(),
new Date(entry.getTime()));
System.out.println(s);
// Once we get the entry from the stream, the stream is
// positioned read to read the raw data, and we keep
// reading until read returns 0 or less.
String outpath = outdir + "/" + entry.getName();
FileOutputStream output = null;
try
{
output = new FileOutputStream(outpath);
int len = 0;
while ((len = stream.read(buffer)) > 0)
{
output.write(buffer, 0, len);
}
}
finally
{
// we must always close the output file
if(output!=null) output.close();
}
}
}
finally
{
// we must always close the zip file.
stream.close();
}
}
代码摘录来自以下网站:
答案 1 :(得分:14)
好吧,我已经做到了:
zipStream = new ZipInputStream(channelSftp.get("Port_Increment_201405261400_2251.zip"));
zipStream.getNextEntry();
sc = new Scanner(zipStream);
while (sc.hasNextLine()) {
System.out.println(sc.nextLine());
}
它帮助我阅读ZIP的内容,而无需写入另一个文件。
答案 2 :(得分:8)
ZipInputStream
本身就是InputStream
,并在每次调用getNextEntry()
后传递每个条目的内容。必须特别小心,不要关闭读取内容的流,因为它与ZIP流相同:
public void readZipStream(InputStream in) throws IOException {
ZipInputStream zipIn = new ZipInputStream(in);
ZipEntry entry;
while ((entry = zipIn.getNextEntry()) != null) {
System.out.println(entry.getName());
readContents(zipIn);
zipIn.closeEntry();
}
}
private void readContents(InputStream contentsIn) throws IOException {
byte contents[] = new byte[4096];
int direct;
while ((direct = contentsIn.read(contents, 0, contents.length)) >= 0) {
System.out.println("Read " + direct + "bytes content.");
}
}
将阅读内容委托给其他逻辑时,可能需要用ZipInputStream
包裹FilterInputStream
以仅关闭条目而不是整个流,如下所示:
public void readZipStream(InputStream in) throws IOException {
ZipInputStream zipIn = new ZipInputStream(in);
ZipEntry entry;
while ((entry = zipIn.getNextEntry()) != null) {
System.out.println(entry.getName());
readContents(new FilterInputStream(zipIn) {
@Override
public void close() throws IOException {
zipIn.closeEntry();
}
});
}
}
答案 3 :(得分:0)
OP接近了。只需要读取字节。调用getNextEntry positions the stream at the beginning of the entry data
(docs)。如果这是我们想要的条目(或唯一的条目),则InputStream在正确的位置。我们所需要做的就是读取该条目的解压缩字节。
byte[] bytes = new byte[(int) entry.getSize()];
int i = 0;
while (i < bytes.length) {
// .read doesn't always fill the buffer we give it.
// Keep calling it until we get all the bytes for this entry.
i += zipStream.read(bytes, i, bytes.length - i);
}
因此,如果这些字节确实是文本,那么我们可以将这些字节解码为String。我只是假设使用utf8编码。
new String(bytes, "utf8")
旁注:我个人使用apache commons-io IOUtils来减少此类较低级别的内容。 ZipInputStream.read的文档似乎暗示着读取将在当前zip条目的末尾停止。如果是这样,那么读取当前文本条目就是使用IOUtils的一行。
String text = IOUtils.toString(zipStream)
答案 4 :(得分:0)
这里是使用BiConsumer处理zip输入流的更通用的解决方案。这几乎与haui使用的解决方案相同
private void readZip(InputStream is, BiConsumer<ZipEntry,InputStream> consumer) throws IOException {
try (ZipInputStream zipFile = new ZipInputStream(is);) {
ZipEntry entry;
while((entry = zipFile.getNextEntry()) != null){
consumer.accept(entry, new FilterInputStream(zipFile) {
@Override
public void close() throws IOException {
zipFile.closeEntry();
}
});
}
}
}
您可以通过调用
来使用它readZip(<some inputstream>, (entry, is) -> {
/* don't forget to close this stream after processing. */
is.read() // ... <- to read each entry
});
答案 5 :(得分:0)
将包含文件结构的压缩文件(zip)解压缩到给定目录中。 注意;该代码在“ org.apache.commons.io.IOUtils”上使用deps,但您可以将其替换为您的自定义“读取流”代码
public static void unzipDirectory(File archiveFile, File destinationDir) throws IOException
{
Path destPath = destinationDir.toPath();
try (ZipInputStream zis = new ZipInputStream(new FileInputStream(archiveFile)))
{
ZipEntry zipEntry;
while ((zipEntry = zis.getNextEntry()) != null)
{
Path resolvedPath = destPath.resolve(zipEntry.getName()).normalize();
if (!resolvedPath.startsWith(destPath))
{
throw new IOException("The requested zip-entry '" + zipEntry.getName() + "' does not belong to the requested destination");
}
if (zipEntry.isDirectory())
{
Files.createDirectories(resolvedPath);
} else
{
if(!Files.isDirectory(resolvedPath.getParent()))
{
Files.createDirectories(resolvedPath.getParent());
}
try (FileOutputStream outStream = new FileOutputStream(resolvedPath.toFile()))
{
IOUtils.copy(zis, outStream);
}
}
}
}
}
答案 6 :(得分:0)
如果ZIP的内容包含1个文件(例如,HTTP响应的压缩内容),则可以使用Kotlin读取文本内容,如下所示:
@Throws(IOException::class)
fun InputStream.readZippedContent() = ZipInputStream(this).use { stream ->
stream.nextEntry?.let { stream.bufferedReader().readText() } ?: String()
}
此扩展功能可解压缩Zip文件的第一个ZIP条目,并以纯文本格式读取内容。
用法:
val inputStream: InputStream = ... // your zipped InputStream
val textContent = inputStream.readZippedContent()