我正在使用Sockets在Java中创建一个程序。我可以将命令发送到客户端,从客户端发送到服务器。要阅读命令,我使用BufferedReader
。要编写它们,PrintWriter
但现在我想通过 套接字(不仅仅是创建第二个连接)来传输文件。
首先我写入输出流文件包含多少字节。例如40000字节。所以我通过套接字写了数字40000
,但是连接的另一边是78
。
所以我在想:BufferedReader
读取的不仅仅是行(通过调用readLine()
),这样我就会从文件数据中丢失一些字节。因为它们位于BufferedReader
的缓冲区中
所以数字78
是我要传输的文件的一个字节。
这种思维方式是否合适。如果是这样,如何解决这个问题。
我希望我解释得很好。
这是我的代码,但我的默认语言是荷兰语。所以一些变量名称听起来很棒。
public void flushStreamToStream(InputStream is, OutputStream os, boolean closeIn, boolean closeOut) throws IOException {
byte[] buffer = new byte[BUFFERSIZE];
int bytesRead;
if ((!closeOut) && closeIn) { // To Socket from File
action = "Upload";
os.write(is.available()); // Here I write 400000
max = is.available();
System.out.println("Bytes to send: " + max);
while ((bytesRead = is.read(buffer)) != -1) {
startTiming(); // Two lines to compute the speed
os.write(buffer, 0, bytesRead);
stopTiming(); // Speed compution
process += bytesRead;
}
os.flush();
is.close();
return;
}
if ((!closeIn) && closeOut) { // To File from Socket
action = "Download";
int bytesToRead = -1;
bytesToRead = is.read(); // Here he reads 78.
System.out.println("Bytes to read: " + bytesToRead);
max = bytesToRead;
int nextBufferSize;
while ((nextBufferSize = Math.min(BUFFERSIZE, bytesToRead)) > 0) {
startTiming();
bytesRead = is.read(buffer, 0, nextBufferSize);
bytesToRead -= bytesRead;
process += nextBufferSize;
os.write(buffer, 0, bytesRead);
stopTiming();
}
os.flush();
os.close();
return;
}
throw new IllegalArgumentException("The only two boolean combinations are: closeOut == false && closeIn == true AND closeOut == true && closeIn == false");
}
以下是解决方案:
感谢James的建议
我认为 laginimaineb anwser是解决方案的一部分。
阅读命令。
DataInputStream in = new DataInputStream(is); // Originally a BufferedReader
// Read the request line
String str;
while ((str = in.readLine()) != null) {
if (str.trim().equals("")) {
continue;
}
handleSocketInput(str);
}
现在是flushStreamToStream:
public void flushStreamToStream(InputStream is, OutputStream os, boolean closeIn, boolean closeOut) throws IOException {
byte[] buffer = new byte[BUFFERSIZE];
int bytesRead;
if ((!closeOut) && closeIn) { // To Socket from File
action = "Upload";
DataOutputStream dos = new DataOutputStream(os);
dos.writeInt(is.available());
max = is.available();
System.out.println("Bytes to send: " + max);
while ((bytesRead = is.read(buffer)) != -1) {
startTiming();
dos.write(buffer, 0, bytesRead);
stopTiming();
process += bytesRead;
}
os.flush();
is.close();
return;
}
if ((!closeIn) && closeOut) { // To File from Socket
action = "Download";
DataInputStream dis = new DataInputStream(is);
int bytesToRead = dis.readInt();
System.out.println("Bytes to read: " + bytesToRead);
max = bytesToRead;
int nextBufferSize;
while ((nextBufferSize = Math.min(BUFFERSIZE, bytesToRead)) > 0) {
startTiming();
bytesRead = is.read(buffer, 0, nextBufferSize);
bytesToRead -= bytesRead;
process += nextBufferSize;
os.write(buffer, 0, bytesRead);
stopTiming();
}
os.flush();
os.close();
return;
}
throw new IllegalArgumentException("The only two boolean combinations are: closeOut == false && closeIn == true AND closeOut == true && closeIn == false");
}
马亭。
答案 0 :(得分:4)
我不确定我是否按照你的解释。
但是,是的 - 您无法真正控制BufferedReader实际读取的数量。这样一个读者的意思是它乐观地根据需要读取底层资源的块以补充其缓冲区。因此,当您第一次调用readLine
时,它会看到其内部缓冲区不足以为您提供请求,并且会关闭并读取其缓冲区中的许多字节来自潜在的来源,这通常会比你刚才要求的要多得多。填充缓冲区后,它将从缓冲的内容中返回您的行。
因此,一旦将输入流包装在BufferedReader中,您应该确保只通过相同的缓冲读取器读取该流。如果你不这样做,你将最终丢失数据(因为一些字节将被消耗,现在位于BufferedReader的缓存等待服务)。
答案 1 :(得分:1)
DataInputStream很可能是您想要使用的。另外,不要使用available()方法,因为它通常是无用的。
答案 2 :(得分:0)
这里只是一个狂野的刺 - 40000是二进制的1001110001000000。现在,这里的前七位是1001110,即78.意思是,你写的是2个字节的信息但是读了7位。
答案 3 :(得分:0)
BufferedReader假定它是从底层输入流中读取的唯一一个。
它的目的是最小化从底层流中读取的数量(这些数据很昂贵,因为它们可以非常深入地委托)。为此,它保留了一个缓冲区,它通过在对基础流的单次调用中将尽可能多的字节填充到其中来填充。
是的,您的诊断准确无误。