我有以下代码来下载通过 TCP 传输的文件:
try (OutputStream out = new FileOutputStream(path); InputStream is = socket.getInputStream();) {
byte[] bytes = new byte[1024];
int count, xp = 0;
while ((count = is.read(bytes)) > 0) { // TODO after upload the service doesn't leave while loop
out.write(bytes, 0, count);
}
System.out.println("hello");
...
上传代码:
if (ready.equalsIgnoreCase(CdnResponse.READY.getContext())){
int read = 0;
byte[] bytes = new byte[1024];
while ((read = inputStream.read(bytes)) != -1) {
out.write(bytes, 0, read);
}
}
上传退出循环正常。
一旦处理完所有字节(它们总是被成功处理,但是循环永远不会退出),就会创建文件,没有任何问题,但是循环不会退出。
TCP/IP 连接被设计为长期流连接(建立在无序、无保证、基于数据包的 IP 协议之上)。
这意味着is.read(bytes)
它完全符合规范所说的:它将等待至少 1 个字节可用,或者“流结束”信号进来。只要两者都不发生(没有字节到达,但流不是关闭),它将尽职尽责地阻止。如果必须的话,永远。
解决方案是 [A] 预先发送文件的大小,然后调整循环以在收到该数量的字节后退出,或者 [B] 关闭流。
要关闭流,请关闭套接字。听起来你不想这样做(你在流上多路复用多个东西,即在传输文件后,你可以发送其他命令)。
所以,选项A,听起来更好。但是,选项 A 的先决条件是您知道将从inputStream
. 如果它是一个文件,那很简单,只需询问它的大小。如果它是流式数据,则需要在“上传代码方面”首先将整个内容流式传输到文件中,然后才将其通过网络流式传输,这很笨拙且可能效率低下。
如果你知道大小,它看起来会像(我将在这里使用更新的 API,你使用的是一些过时的、有 20 年历史的过时的东西):
// upload side
void upload() {
Path p = Paths.get("/path/to/file/you/want/to/send");
long fileSize = Files.size(p);
out.write(longToBytes(fileSize);
try (InputStream in = Files.newInputStream(p)) {
in.transferTo(out);
}
}
public static byte[] longToBytes(long x) {
ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);
buffer.putLong(x);
return buffer.array();
}
此代码具有以下属性:
java.nio.file
API。transferTo
InputStream 中的新方法,避免了必须声明一个字节数组作为缓冲区和 while 循环的繁琐。然后在下载端:
void download() {
long size = bytesToLong(in.readNBytes(8));
Path p = Paths.get("/file/to/store/data/at");
// Generally network transfer sizes are a bit higher than 1k;
// up to 64k in fact. Best to declare a larger buffer!
byte[] bb = new byte[65536];
try (OutputStream out = Files.newOutputStream(p)) {
while (size > 0) {
int count = in.read(bb);
if (count == -1) throw new IOException("Unexpected end of stream");
out.write(bb, 0, count);
size -= count;
}
}
}
public static long bytesToLong(byte[] bytes) {
ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);
buffer.put(bytes);
buffer.flip();//need flip
return buffer.getLong();
}
这段代码:
readNBytes
方法读取该大小。如果你不知道传入的数据有多大,你需要写一个小协议。例如:
0
),这表示文件已完成。如果这是您需要的,我将把它作为练习让您实现上传和下载端。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句