我的
readData()
方法是一个程序的一部分,该程序是在UDP之上工作的可靠传输协议(RFT),它应该保证客户端/服务器之间文件的可靠传输。
关于我上一篇关于
readData()
方法的问题的文章,我尝试再次使用 FileInputStream
,它导致了一个容易重现的错误,导致仅读取第一段数据。另外,如果需要,我可以为该程序的其他课程提供更多上下文。
重要提示:我不允许创建新的变量/方法,也不允许编辑现有的方法签名。我不擅长编程,所以任何帮助将不胜感激。
input.txt 文件也仅包含此字符串:Computer Networks 2025。
该方法的工作原理如下:
public int readData()
:
maxPayload
中的属性 Protocol.java
中指定)读取到数据段 (dataSeg) 的有效负载中。以下是
readData()
方法中使用的相关代码,不断产生仅重复读取第一段的错误。
import java.io.*;
public class Protocol {
private File inputFile;
private long fileSize;
private int maxPayload;
private long remainingBytes;
private Segment dataSeg;
private int totalSegments;
public Protocol(String inputFileName, int maxPayload) {
this.inputFile = new File(inputFileName);
this.fileSize = this.inputFile.length();
this.remainingBytes = this.fileSize;
this.maxPayload = maxPayload;
this.dataSeg = new Segment();
this.totalSegments = 0;
}
public int readData() {
if (remainingBytes <= 0) {
System.out.println("No more bytes to read.");
return -1;
}
int bytesToRead = (int) Math.min(maxPayload, remainingBytes);
byte[] segmentBuffer = new byte[bytesToRead];
// FileInputStream is opened every time readData() is called
try (FileInputStream fileIn = new FileInputStream(inputFile)) {
long bytesToSkip = fileSize - remainingBytes;
fileIn.getChannel().position(bytesToSkip); // Set the position each time
int bytesRead = fileIn.read(segmentBuffer, 0, bytesToRead);
if (bytesRead == -1) {
System.out.println("Unexpected end of file.");
return -1;
}
dataSeg.setPayLoad(new String(segmentBuffer, 0, bytesRead));
dataSeg.setSize(bytesRead);
dataSeg.setSq(totalSegments % 2);
remainingBytes -= bytesRead;
totalSegments++;
return 0; // More data is available
} catch (IOException e) {
System.out.println("Error reading data: " + e.getMessage());
return -1;
}
}
public static void main(String[] args) {
Protocol protocol = new Protocol("input.txt", 4);
while (protocol.readData() == 0) {
System.out.println("Read segment: " + protocol.dataSeg.getPayLoad());
}
}
}
class Segment {
private String payLoad;
private int size;
private int sq;
public void setPayLoad(String payLoad) { this.payLoad = payLoad; }
public void setSize(int size) { this.size = size; }
public void setSq(int sq) { this.sq = sq; }
public String getPayLoad() { return payLoad; }
}
运行以下命令将在客户端产生此输出(仅读取第一个段):
Read segment: Comp
Read segment: Comp
Read segment: Comp
Read segment: Comp
Read segment: Comp
Read segment: Comp
当下面的示例输出应该是客户端应显示的内容时(作为输入发送 6 个段,每个段将按 4 个字母发送):
Read segment: Comp
Read segment: uter
Read segment: Net
Read segment: work
Read segment: s 20
Read segment: 25.
readData() 方法的问题在于,每次调用它时都会打开一个新的 FileInputStream,这会将读取位置重置为文件的开头。因此,您总是读取相同的第一段数据。要解决此问题,您需要将 FileInputStream 维护为类成员,以便其状态在多次调用 readData() 时保持不变。
import java.io.*;
public class Protocol {
private File inputFile;
private long fileSize;
private int maxPayload;
private long remainingBytes;
private Segment dataSeg;
private int totalSegments;
private FileInputStream fileIn; // Add this member variable
public Protocol(String inputFileName, int maxPayload) {
this.inputFile = new File(inputFileName);
this.fileSize = this.inputFile.length();
this.remainingBytes = this.fileSize;
this.maxPayload = maxPayload;
this.dataSeg = new Segment();
this.totalSegments = 0;
// Initialize FileInputStream once
try {
this.fileIn = new FileInputStream(inputFile);
} catch (FileNotFoundException e) {
System.out.println("File not found: " + e.getMessage());
}
}
public int readData() {
if (remainingBytes <= 0) {
System.out.println("No more bytes to read.");
return -1;
}
int bytesToRead = (int) Math.min(maxPayload, remainingBytes);
byte[] segmentBuffer = new byte[bytesToRead];
try {
long bytesToSkip = fileSize - remainingBytes;
fileIn.getChannel().position(bytesToSkip); // Set the position for reading
int bytesRead = fileIn.read(segmentBuffer, 0, bytesToRead);
if (bytesRead == -1) {
System.out.println("Unexpected end of file.");
return -1;
}
dataSeg.setPayLoad(new String(segmentBuffer, 0, bytesRead));
dataSeg.setSize(bytesRead);
dataSeg.setSq(totalSegments % 2);
remainingBytes -= bytesRead;
totalSegments++;
return 0; // More data is available
} catch (IOException e) {
System.out.println("Error reading data: " + e.getMessage());
return -1;
}
}
// Ensure to close the FileInputStream when done
public void close() {
try {
if (fileIn != null) {
fileIn.close();
}
} catch (IOException e) {
System.out.println("Error closing the file: " + e.getMessage());
}
}
public static void main(String[] args) {
Protocol protocol = new Protocol("input.txt", 4);
while (protocol.readData() == 0) {
System.out.println("Read segment: " + protocol.dataSeg.getPayLoad());
}
protocol.close(); // Close the stream after use
}
}
class Segment {
private String payLoad;
private int size;
private int sq;
public void setPayLoad(String payLoad) { this.payLoad = payLoad; }
public void setSize(int size) { this.size = size; }
public void setSq(int sq) { this.sq = sq; }
public String getPayLoad() { return payLoad; }
}