[英]send large files over socket java
我正在嘗試通過套接字傳輸較大的文件,我將分塊傳輸文件,如代碼所示。 鏈接
int count;
byte[] buffer = new byte[8192];
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
發送此文件之前,我要發送一個保存文件詳細信息的對象。我應該使用哪個流發送“對象+文件”。
我是流媒體新手,可以獲取任何示例代碼。
我可以先發送對象的字節長度以讀取對象,保存對象並發送文件數據嗎,有可能示例代碼嗎?
謝謝421
我不確定使用Java的序列化機制是否是進行簡單文件傳輸的最佳方法。 如您的問題所建議,您嘗試避免隨時將整個文件保留在內存中。 可以使用代理模式使用對象來完成此操作,但是如果您只想傳輸文件,則這可能不是最簡單的解決方案。 (此外,它也將有效地與您的同行緊密聯系,以Java來實現。)
取而代之的是,為什么不看一下能完全滿足您需求的非常成功的協議:HTTP。
Content-Type: application/octet-stream
Content-Length: 542183
542183 bytes of data follow...
為元數據標頭編寫解析器應該不難。
您需要確保寫作/閱讀的順序。 如果在客戶端上write an object -> write raw bytes
,則在服務器上read an object -> read raw bytes
。 讀取時, ObjectInputStream
應該能夠找到序列化對象數據的邊界。
如果要使套接字連接保持長期生存並多次使用其流,則將IMO的套接字的Output/InputStream
包裝在ObjectOutput/InputStream
中不是一個好主意。 關閉對象流時,它也會同時關閉基礎流。
因此,您可能要首先寫入序列化對象數據的長度(對象中包含文件長度,因此您無需顯式寫入),例如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;
}
}
我沒有在答案中測試示例代碼。
類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
來檢測數據結束。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.