簡體   English   中英

通過套接字Java發送大文件

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM