Java 文件传输客户端不读取所有字节

标签 java sockets file-io

<分区>

我有一个文件发送者和接收者。从我在互联网上找到的 10 篇左右的帖子来看,这是通过 Java 套接字发送文件的正确方法。看看下面的代码片段。

发件人:

OutputStream bos = clientSocket.getOutputStream();
FileInputStream fis = new FileInputStream(sendingFile);
BufferedInputStream bis = new BufferedInputStream(fis);

int n;
int total = 0;
byte[] buffer = new byte[8192];

while ((n = bis.read(buffer)) > 0) {
    bos.write(buffer, 0, n);
    System.out.println("Sending File... ");
    total += n;
    System.out.println(total);
}

接收者:

InputStream bis = clientSocket.getInputStream();
FileOutputStream fos = new FileOutputStream(fileOut);
BufferedOutputStream bos = new BufferedOutputStream(fos);

int n;
int total = 0;
byte[] buffer = new byte[8192];
while ((n = bis.read(buffer)) > -1) {
    bos.write(buffer, 0, buffer.length);
    System.out.println("Writing File... ");
    total += n;
    System.out.println(total);
    if (total == fileSize) {
        break;
    }
}
System.out.println("File Received");

这是发件人的输出

Sending File: D:\Users\Administrator\Documents\AAAAAAAAAAAAAAAAAAAAAAAAAAA.avi
File Size: 54236160
Sending File...
8192
Sending File...
16384
....................some time later
Sending File...
54231040
Sending File...
54236160
File Sent

最后一个数字 54236160 是要发送的文件的确切大小。现在这是接收端的最后一行。

Writing file...
54234710

所以对于这个特定的文件,它总是停在这个大小,所以因为没有发送整个文件,接收者永远不会停止等待数据。我不明白发件人如何发送正确数量的数据,但收件人并没有全部收到。我从未在接收方看到“已接收文件”,并且接收方读取的数据量永远不会等于发送的数据量。

我发送的任何文件都会出现此问题,如果我发送非常小的文件,例如那些以字节为单位而不是 kb 的文件,我在接收方根本看不到任何“写入文件...”,几乎就像它一样只是忽略流。

然而互联网上的每个帖子都说这是发送文件的正确方式。哦,如果我关闭发送套接字和/或流,这是我不想做的,因为客户端和服务器还需要做其他事情,它仍然无法解决问题。

我注意到的另一件事是,虽然发送方似乎总是指示其将全部金额写入缓冲区(“总计”始终为 8192 的倍数),但接收方却没有。

下面是获取文件大小和文件名的代码。也许这就是错误所在?我不知道如何在我们开始发送和接收文件之前完成所有操作。

System.out.println("Receiving File");
try {
    clientScanner.nextLine();
    String fileName = clientScanner.nextLine();
    int fileSize = clientScanner.nextInt();
    System.out.println("File: " + fileName + " Size: " + fileSize);
    File fileOut = new File("C:\\Users\\owner\\AppData\\Local\\temp\\" + fileName);

    InputStream bis = clientSocket.getInputStream();
    FileOutputStream fos = new FileOutputStream(fileOut);
    BufferedOutputStream bos = new BufferedOutputStream(fos);

最佳答案

您不应尝试读取比预期更多的数据。你的循环应该是:

int n;
int bytesLeft = fileSize;
byte[] buffer = new byte[8192];
while (bytesLeft > 0) {
    int n = bis.read(buffer, 0, Math.min(buffer.length, bytesLeft));
    if (n < 0) {
        throw new EOFException("Expected " + bytesLeft + " more bytes to read");
    }
    bos.write(buffer, 0, n);
    System.out.println("Writing File... ");
    bytesLeft -= n;
    System.out.println(total " bytes left to read");
}

(如果需要,您可以调整输出以显示已读取的字节数,而不是还剩多少字节要读取,但我认为这种方法更简单。)

如果这仍然不能为您提供所有数据,您应该在编写代码时刷新输出流 - 我不认为您必须这样做,但如果您没有关闭套接字,我猜它可能永远缓冲它。

如果循环终止但文件似乎不完整,请确保在所有这一切之后关闭 bos

如果that 都没有帮助,那么在您进入此循环之前,其他东西可能已经读取了您的数据的开头。您应该将输出文件中的数据与原始文件进行比较。查看输出文件中的前(比方说)16 个字节,并检查它们是否位于输入文件的开头。如果不是,则表明问题出在您在向我们展示代码之前对连接所做的操作。 (例如,用于发送和接收预期文件大小的代码。)

现在我们可以看到您是如何发送/接收文件大小的,这肯定是问题所在。扫描仪正在读取一些文件数据。要解决此问题,只需在发送端使用 DataOutputStream 并在接收端使用 DataInputStream:

DataOutputStream output = new DataOutputStream(clientSocket.getOutputStream());
output.writeUTF(fileName);
output.writeInt(fileSize);
// Write the data as before, to output

在接收方:

DataInputStream input = new DataOutputStream(clientSocket.getInputStream());
String fileName = input.readUTF(name);
int fileSize = input.readInt();
// Read the data before, as above, from input

关于Java 文件传输客户端不读取所有字节,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31642202/

相关文章:

java - 应用程序强制关闭

java - 在 TestNG 中与 @Factory 并行运行测试类

Java进程等待

Java Sockets - 从客户端向服务器发送数据

java - java中socket的连接问题

java - 使用 JavaFX 创建托盘图标

javascript - Totaljs websocket 模块与 socket.io

C将文件读入二维数组

linux - 使用 Bash 脚本读取文件求平均值

c - 使用 fread 在 C 中读取 ASCII 文件