Java - FTP程序在传输过程中损坏文件

时间:2014-02-06 15:05:25

标签: java sockets ftp

我使用套接字创建了一个基本的客户端服务器FTP程序,但由于某些原因,文件在传输过程中被破坏了。在下面的例子中,我正在从客户端将文件推送到服务器。它几乎可以工作,因为一些文件(如.png)传输和打开罚款,但其他文件(.docx)则不然。我传输的任何文件都与我发送的MD5不同。

客户代码:

File file = null;
            FTPDataBlock transferBlock;
            int numBytesRead = 0;
            int blockNumber = 1;
            int blockSize = 1024;
            byte[] block = new byte[blockSize];
            fc = new JFileChooser();

            // select file to upload
            int returnVal = fc.showOpenDialog(Client.this);
            if (returnVal == JFileChooser.APPROVE_OPTION) {
                file = fc.getSelectedFile();

                try {
                    // get total number of blocks and send to server
                    int totalNumBlocks = (int)Math.ceil((file.length()*1.0) / blockSize);
                    System.out.println("File length is: " + file.length());
                    FTPCommand c = new FTPCommand("PUSH", Integer.toString(totalNumBlocks));
                    oos = new ObjectOutputStream(sock.getOutputStream());
                    oos.writeObject(c);
                    oos.flush();

                    // send to server block by block
                    FileInputStream fin = new FileInputStream(file);
                    while ((numBytesRead = fin.read(block)) != -1){
                        transferBlock = new FTPDataBlock(file.getName(), blockNumber, block);
                        blockNumber++;
                        System.out.println("Sending block " + transferBlock.getBlockNumber() + " of " + totalNumBlocks);
                        oos = new ObjectOutputStream(sock.getOutputStream());
                        oos.writeObject(transferBlock);
                        oos.flush();
                    }

                    fin.close();
                    System.out.println("PUSH Complete");

                    // get response from server
                    ois = new ObjectInputStream(sock.getInputStream());
                    FTPResponse response = (FTPResponse)ois.readObject();
                    statusArea.setText(response.getResponse());


                } catch (IOException | ClassNotFoundException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }
            }

服务器代码:

else if (cmd.getCommand().equals("PUSH")){
                    // get total number of file blocks
                    int totalNumBlocks = Integer.parseInt(cmd.getParameters());

                    // get first block
                    in = new ObjectInputStream(sock.getInputStream());
                    FTPDataBlock currentBlock = (FTPDataBlock)in.readObject();

                    // create file and write first block to file
                    File file = new File (workingDirectory + File.separator + currentBlock.getFilename());
                    FileOutputStream fOut = new FileOutputStream(file);
                    fOut.write(currentBlock.getData());
                    fOut.flush();

                    // get remaining blocks
                    while(currentBlock.getBlockNumber()+1 <= totalNumBlocks){
                        in = new ObjectInputStream(sock.getInputStream());
                        currentBlock = (FTPDataBlock)in.readObject();
                        fOut.write(currentBlock.getData());
                        fOut.flush();
                    }

                    fOut.close();

                    // send response
                    FTPResponse response = new FTPResponse("File Received OK");
                    out = new ObjectOutputStream(sock.getOutputStream());
                    out.writeObject(response);
                }

FTPDataBlock类:

public class FTPDataBlock implements Serializable{

    private static final long serialVersionUID = 1L;
    private String filename;
    private int blockNumber; // current block number
    private byte[] data;
    //constructors & accessors
}

我确定这是我在这里失踪的小事。有什么想法吗?

2 个答案:

答案 0 :(得分:1)

这是因为服务器正在将整个1024字节块写入文件,即使实际写入块的字节少于1024个字节。

解决方案(感谢@kdgregory)是使用FileInputStream.read()的返回值来填充我的FTPDataBlock类int bytesWritten中的新属性。

然后在服务器端我可以使用:

FileOutputStream.write(currentBlock.getData(), 0, currentBlock.getBytesWritten());

将精确的字节数写入文件,而不是每次都写入整个块。

答案 1 :(得分:-1)

我认为文件扩展名可能存在问题。在客户端提供选项:

FILE_TO_RECEIVED = JOptionPane.showInputDialog("Please enter the Drive followed                                  by the file name to be saved. Eg: D:/xyz.jpg");  

它可以帮助您提供正确的文件扩展名。

然后我认为您还应该在客户端提供文件大小,如:

   public final static int FILE_SIZE = 6022386; 

然后在你使用的数组块中你可以进行以下更改:

 try {
  sock = new Socket(SERVER, SOCKET_PORT);

  byte [] mybytearray  = new byte [FILE_SIZE];
  InputStream is = sock.getInputStream();
  fos = new FileOutputStream(FILE_TO_RECEIVED);
  bos = new BufferedOutputStream(fos);
  bytesRead = is.read(mybytearray,0,mybytearray.length);
  current = bytesRead;

  do {
     bytesRead =
        is.read(mybytearray, current, (mybytearray.length-current));
     if(bytesRead >= 0) current += bytesRead;
  } while(bytesRead > -1);

  bos.write(mybytearray, 0 , current);
  bos.flush();

}