2

我正在尝试在 java 上编写客户端和服务器端。服务器端没问题(检查了几个客户端)。

所以,问题出在客户端。我为它分配内存bytearray、读取BufferedInputStream和写入bytearray。然后从bytearrayFileOutputStream 写入。一切正常,但可用空间bytearray被 NULL 填充,因此接收到的文件不正确(例如图像)。

我发现了该问题的两个决定:

  1. 读到bytearray文件末尾(但我不知道文件末尾在哪里)
  2. BufferedInputStream从to读取FileInputStream,但它不起作用:

我实际上需要接收头和文件。将标头输出到控制台并将文件写入光盘。

完整来源

public class SClient {
private static int bufferSize = 8192;
/**
 * @param args the command line arguments
 */
public static void main(String[] args) {
    System.out.println("Enter the address:");
    BufferedReader bufferRead = new BufferedReader
                (new InputStreamReader(System.in));

    try {
        String address = bufferRead.readLine();
        System.out.println("Enter the extention of receiving file:");
        String fileExt = bufferRead.readLine();
        // TODO code application logic here
        Socket socket = new Socket(address,4040);
        BufferedInputStream bis = new BufferedInputStream
                (socket.getInputStream());

        BufferedOutputStream bout = new BufferedOutputStream
                (socket.getOutputStream());
        System.out.println("Enter the request:");
        String message = bufferRead.readLine();// GET /index.html HTTP/1.0

        System.out.println("Header read");
        if(message!=null){
            bout.write(message.getBytes());
        }
        FileOutputStream fout = new FileOutputStream("out"+fileExt);
        String s1 = "\r\n\r\n";
        bout.write(s1.getBytes());
        bout.flush();
        System.out.println("Header sent");

        byte[] res = new byte[bufferSize];
        int got;
        while((got = bis.read(res))!=-1){
            fout.write(res,0,got);
        }
        fout.close();
        bout.flush();
        socket.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
  }
}

服务器端源码:

    String endLine = "\r\n";
    File f = new File(fileName);
    FileInputStream fstream;
    fstream = new FileInputStream(f);
    response = "HTTP/1.0 200 OK" + endLine;
    header = "Content-type: "+ contentType + endLine + "Content-length: " + f.length() + endLine + endLine;
    bout.write(response.getBytes());
    bout.write(header.getBytes());
    while(fstream.read(buffer) != -1) {
        bout.write(buffer);
    }
    System.out.println("Message sent");
    bout.flush();
    socket.close();
4

3 回答 3

4

您必须记住读入缓冲区的字节数,并且只能将这些字节写回。像这里这样:

int got;
while ((got = bis.read(res)) != -1) {

    fout.write(res, 0, got);
}
于 2013-09-13T06:38:27.107 回答
3

不是答案,而是建议...

这看起来不对。基本上,您正在读取一个最多为 的字节数组bufferSize,但随后只需将一个字节写入byte输出流。您还冒着索引超出范围错误的风险,因为您i在每个未绑定的循环上增加...

while (bis.read(res) != -1) {
    fout.write(res[i]);
    i++;
}

相反,您应该使用更像...

int bytesRead = -1;
while ((bytesRead = bis.read(res)) != -1) {
    fout.write(res, 0, bytesRead);
}

它将写入一个字节数组,直到读取的字节数......

下一个问题是,您需要某种方式来知道何时到达文件末尾。

现在,您可以输入某种终止符,但这可能会损坏输出文件。

现在,因为我是一名 UI 开发人员,所以我想知道我下载了多少。因此,首先您可以向下发送流是期望的字节数,然后您可以简单地记录读取的字节数并在达到限制时停止...

这将需要对您的服务器进行轻微更改,它需要能够发送一个long值,指示要读取的图像的大小(以字节为单位)和\n

BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String header = br.readLine();
long expectedBytes = Long.parseLong(header);

然后你会简单地循环,直到你有所需的字节数......

int bytesRead = 0;
int totalBytes = 0;
while (totalBytes < expectedBytes) {
    bytesRead = bis.read(res);
    fout.write(res, 0, bytesRead);
    totalBytes += expectedBytes;
}

// Flush and close your steams as required.

我为屏幕共享问题做了一些类似的事情

于 2013-09-13T06:39:08.137 回答
1

记住在 Java 中复制流的规范方法:

while ((count = in.read(buffer)) > 0)
{
    out.write(buffer, 0, count);
}

使用任何大于零的缓冲区大小,通常为 4k 或 8k。

于 2013-09-13T06:38:56.310 回答