readData() 方法在使用 FileInputStream 时仅读取文本文件的第一段

问题描述 投票:0回答:1

我的

readData()
方法是一个程序的一部分,该程序是在UDP之上工作的可靠传输协议(RFT),它应该保证客户端/服务器之间文件的可靠传输。

关于我上一篇关于

readData()
方法的问题的文章,我尝试再次使用
FileInputStream
,它导致了一个容易重现的错误,导致仅读取第一段数据。另外,如果需要,我可以为该程序的其他课程提供更多上下文。

重要提示:我不允许创建新的变量/方法,也不允许编辑现有的方法签名。我不擅长编程,所以任何帮助将不胜感激。

input.txt 文件也仅包含此字符串:Computer Networks 2025

该方法的工作原理如下:

public int readData()

  • 从给定的输入文件流中将下一个固定大小的数据块(在
    maxPayload
    中的属性
    Protocol.java
    中指定)读取到数据段 (dataSeg) 的有效负载中。
  • 除了填充数据段的有效负载之外,该方法还设置数据段的正确类型以及正确的序列号 sq。它还将数据段的大小字段设置为从文件中读取的字节数(最终段的有效负载大小可能较小,因为文件大小可能不是有效负载字段中存储的每个数据块大小的倍数)。
  • 此方法不设置数据段的校验和。
  • 该方法一次仅读取一个段。不要一次读取整个文件。读取有效负载的适当数据大小(即,除非文件大小小于数据段有效负载大小,否则不得一次读取整个文件)。
  • 如果该数据段是最后一个数据段(没有更多数据要读取),则该方法返回-1,否则返回0。

以下是

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.
java sockets
1个回答
0
投票

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; }
}
© www.soinside.com 2019 - 2024. All rights reserved.