我正在尝试通过socket传输更大的文件。我将以块的形式传输文件。如代码中所示。link
int count;
byte[] buffer = new byte[8192];
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
在发送此文件之前,我想发送一个包含文件详细信息的对象。我应该使用哪个流发送Object + File。
我是溪流的新手,我可以获得任何示例代码。
我可以先发送对象的字节长度来读取对象,保存并发送文件数据。是否可以使用任何示例代码?
由于 421
答案 0 :(得分:0)
我不确定使用Java的序列化机制是否是进行简单文件传输的最佳方式。正如您的问题所示,您尝试避免随时将整个文件保留在内存中。这可以通过使用代理模式的对象来完成,但如果您只想传输文件,这可能不是最直接的解决方案。 (此外,它还可以有效地将您的对等体绑定在Java中实现。)
相反,为什么不看看一个非常成功的协议,它完全符合你的需要:HTTP。
Content-Type: application/octet-stream
Content-Length: 542183
542183 bytes of data follow...
为元数据头编写解析器应该不会太难。
答案 1 :(得分:0)
您需要确保写/读的顺序。如果客户端上为write an object -> write raw bytes
,则服务器上为read an object -> read raw bytes
。阅读时,ObjectInputStream
应该能够找到序列化对象数据的边界。
如果你想长时间保持套接字连接并多次使用它的流,那么将套接字Output/InputStream
包裹在ObjectOutput/InputStream
中并不是一个好主意IMO。关闭对象流时,它也会关闭基础流。
因此,您可能希望首先编写序列化对象数据的长度(文件长度包含在对象中,因此您不需要明确地写入它),例如4个字节的BigEndian编码int
。然后将对象序列化为ByteArrayOutputStream
,并在其缓冲区中写入字节。在服务器上,首先读取4个字节,将字节解码回int
,然后将多个字节读入byte[]
,用ByteArrayInputStream
包装字节数组,并从中反序列化对象它
像这样写:
......
OutputStream out = socket.getOutputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(fileInfoObject);
oos.close();
byte[] header = encodeInteger(baos.size());
out.write(header, 0, 4);
baos.writeTo(out);
// write the file to out just as your question shows
在接收方: ...... InputStream in = socket.getInputStream();
// read the int
byte[] header = new byte[4];
in.read(header, 0, 4);
int size = decodeInteger(header);
// read the object
byte[] objectbuf = new byte[size];
int count;
while((count += in.read(objectbuf)) < size); // not sure if this works...
ObjectInputStram ois = new ObjectInputStream(new ByteArrayInputStream(objectbuf));
Object fileInfoObject = ois.readObject();
ois.close();
// read the file
FileOutputStream fos = new FileOutputStream(new File("somefile"));
byte[] buffer = new byte[8192];
count = 0;
long left = castedFileInfoObject.fileSize;
// also not sure if this works, not tested.
int maxRead = buffer.length;
while (true) {
count = in.read(buffer, 0, maxRead);
left -= count;
if (left < 8192) {
maxRead = (int)left;
}
fos.write(buffer, 0, count);
if (left == 0) {
break;
}
}
我没有在我的答案中测试示例代码..只是为了表明这个想法。
答案 2 :(得分:-1)
类MyClass应该实现Serializable接口。然后,可以使用writeObject和readObject方法将此类的对象写入ObjectOutputStream并从ObjectInputStream中读回(参见下文)。
在客户端:
Socket socket = new Socket(url, port);
OutputStream os = socket.getOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(os);
MyClass obj = new Myclass();
oos.writeObject(obj);
int count;
byte[] buffer = new byte[8192];
while ((count = in.read(buffer)) > 0) {
out.write(buffer, 0, count);
}
在服务器上:
ServerSocket sSocket = new ServerSocket(port);
Socket socket = sSocket.accept();
InputStream is = socket.getInputStream();
ObjectInputStream ois = new ObjectInputStream(is);
MyClass obj = (MyClass)ois.readObject();
byte arr[];
try {
while(arr = (byte[])ois.readObject()) {
//do something with arr
}
} catch(java.io.EOFException) {
// End of data
}
如果您需要在文件完成后发送更多数据,则需要一种方法来确定文件所包含的字节数。然后,您可以预先通过套接字将字节数发送到服务器。在服务器上,只读取该文件的许多字节信息,然后对要发送的其余数据执行相同操作。建议使用此预发送文件大小的策略,主要用于进行任何数据传输。如果您可以这样做,则不必依赖捕获java.io.EOFException
来检测数据结尾。