读取InputStream并写入文件

时间:2014-04-20 15:26:51

标签: java serversocket

这与我之前提出的问题有关 - DataInputStream giving java.io.EOFException

在该客户端 - 服务器应用程序中,有一种方法可以检索从服务器发送的文件并保存到文件中。

Client.java -

 public void receiveFile(InputStream is, String fileName) throws Exception {
        int filesize = 6022386;
        int bytesRead;
        int current = 0;
        byte[] mybytearray = new byte[filesize];

        System.out.println("Receving File!");
        FileOutputStream fos = new FileOutputStream("RECEIVED_"+fileName);
        BufferedOutputStream bos = new BufferedOutputStream(fos);
        bytesRead = is.read(mybytearray, 0, mybytearray.length);
        current = bytesRead; 
        System.out.println(bytesRead);
        do {
            bytesRead = is.read(mybytearray, current,
                    (mybytearray.length - current));
            System.out.println(bytesRead);
            if (bytesRead >= 0)
                current += bytesRead;
        } while (bytesRead > -1);
        System.out.println("Loop done");
        bos.write(mybytearray, 0, current);
        bos.flush();
        bos.close();
    }
}

Server.Java

public void sendFile(OutputStream os, String fileName) throws Exception {
    File myFile = new File(fileName);
    byte[] mybytearray = new byte[(int) myFile.length() + 1];
    FileInputStream fis = new FileInputStream(myFile);
    BufferedInputStream bis = new BufferedInputStream(fis);
    bis.read(mybytearray, 0, mybytearray.length);
    System.out.println("Sending File!");
    os.write(mybytearray, 0, mybytearray.length);
    os.flush();
    bis.close();
}

正如您所看到的,客户端receiveFile方法中有几个搁浅的出局。这是我收到的输出。

enter image description here

问题是该方法没有完成其任务,也从未到达System.out.println("Loop done");

问题是什么?

3 个答案:

答案 0 :(得分:1)

我稍后会遇到循环错误。

源头上有一个小字节:

public void sendFile(OutputStream os, String fileName) throws Exception {
    File myFile = new File(fileName);
    if (myFile.length() > Integer.MAX_VALUE) {
        throw new IllegalStateException();
    }

无论

    byte[] mybytearray = Files.readAllBytes(myFile.toPath());

或者

    byte[] mybytearray = new byte[(int) myFile.length()]; // No +1.
    // BufferedInputStream here not needed.
    try (BufferedInputStream bis = new BufferedInputStream(
            new FileInputStream(myFile))) {
        bis.read(mybytearray);
    } // Always closed.

然后

    System.out.println("Sending File!");
    os.write(mybytearray);
    os.flush();
}

或者我添加了java 7 Files.readAllBytes。使用Files.copy甚至可以更简单。

我刚看到已经提到了主要错误。基本上存在一种误解:您可能完整地读取一个字节数组。它会阻塞直到读完为止。如果读取的内容较少("文件结束"到达),则返回字节数。因此,出于各种目的,您可以将其全部阅读。

人们常常看到类似的代码来读取重复写入输出流的固定大小(2的幂)块(比如说4096)。

再一次java 7 Files简化了所有:

    Files.copy(is, Paths.get("RECEIVED_" + fileName));

简而言之:

public void receiveFile(InputStream is, String fileName) throws Exception {
    Files.copy(is, Paths.get("RECEIVED_" + fileName),
        StandardCopyOption.REPLACE_EXISTING);
}

public void sendFile(OutputStream os, String fileName) throws Exception {
    Files.copy(Paths.get(fileName), os);
}

答案 1 :(得分:0)

你可能希望你的病情如下:

} while (bytesRead > -1 && current < mybytearray.length);
//                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

目前,当您读取整个文件时,您的read语句将继续读取零字节(mybytearray.length - current),该字节成功并返回零,因此您的循环永远不会终止。

答案 2 :(得分:0)

不继续添加到输入缓冲区

会简单得多
public void receiveFile(InputStream istream, String fileName) throws Exception {
  System.err.println("Receving File!");
  try (BufferedOutputStream ostream = new BufferedOutputStream(
      new FileOutputStream("RECEIVED_" + fileName))) {
    int bytesRead;
    byte[] mybytearray = new byte[1024];

    do { 
      bytesRead = istream.read(mybytearray);
      if (bytesRead > 0) {
        ostream.write(mybytearray, 0, bytesRead);
      }
    } while (bytesRead != -1);
    System.err.println("Loop done");
    ostream.flush();
  }
}

如果您可以使用Guava,则可以使用ByteStreams.copy(java.io.InputStream, java.io.OutputStream)Javadoc