缓冲输入流在文件中进行随机查找时不起作用

3
我的文件写入过程如下(在我称之为非聚集的模式下):
  1. 将一个对象写入文件的当前位置。在另一个文件(称为索引文件)中记录写入的位置,以便知道我放置了哪些对象。
  2. 通过写入零字节留出一些空间(随机1/2/3/4 KB的空间)
  3. 重复步骤1和2
现在我决定从文件中读取对象。但是我想使用BufferedInputStream。然而,当我将BufferedInputStream封装在ObjectInputStream中时,读取一些对象后会出现错误。我猜测这是发生在一次缓冲读取之后(即一次读取尽可能多的对象,下一次就会出现错误)。
另一方面,直接将FileInputStream封装在ObjectInputStream中没有任何问题。
如果需要,我也可以提供文件写入代码。如果对下面的代码有任何问题,请随意询问。
public class RecordsFileReader {
    RecordsFile rFile;
    Iterator itr;
    FileInputStream fis;
    ObjectInputStream ois;
// The constructor
public RecordsFileReader(RecordsFile rFile) throws IOException, ClassNotFoundException {
    this.rFile = rFile;
    fis = new FileInputStream(rFile.getFileName());


    ObjectInputStream ois2 = new ObjectInputStream(new FileInputStream(rFile.getFileName() + ".index"));



    rFile.recordsLocationList =  (ArrayList <Long>) ois2.readObject();
    itr = rFile.recordsLocationList.iterator();
   /**********************************************************/
   /*          HERE IS THE PROBLEM.                          */
   /* Doesnt work when I additionally use BufferedInputStream*/
   /**********************************************************/

    ois = new ObjectInputStream(fis);

   /**********************************************************/     
}

public Tuple readNext() throws IOException, ClassNotFoundException {
    if(!itr.hasNext())
        return null;
    Long nextRecordPosition = itr.next();
    fis.getChannel().position(nextRecordPosition);
    //System.out.println((Tuple) ois.readObject());
    return ((Tuple) ois.readObject());
}

public void close() throws IOException {
    ois.close();
    fis.close();



}

public boolean hasNext() {
    return itr.hasNext();

}

}

public class RecordsFile {

boolean clustered;
private String fileName;

public RecordsFile(String fileName, boolean clustered) throws IOException {
    this.fileName = fileName;
    this.clustered = clustered;
}

/*
The byte positions at which the records are located in the file.
*/
ArrayList<Long> recordsLocationList= new ArrayList<Long>();

public String getFileName() {
    return fileName;
}

以下是导致错误的更改:

ois = new ObjectInputStream(new BufferedInputStream(fis, 4096));而不是ois = new ObjectInputStream(fis);

错误是java.io.StreamCorruptionException: invalid type code : 00

编辑:

我现在已经找到了问题所在。尽管我的fis被定位到了一个新位置,但我的bis没有跳到那个新位置。相反,bis仅尝试从旧位置读取,因此出现异常。


使用BufferedInputStream时出现了什么错误?从技术上讲,添加BIS不应该会导致问题(因为它的缓冲读取方式是一种实现细节)。另外,您能展示一下如何将OIS包装成BIS并导致错误吗? - Bhaskar
我本可以调查导致错误的确切原因,但如果您觉得合适,您可以关闭这个问题。 - Bhaskar
@Bha ois = new ObjectInputStream(new BufferedInputStream(fis, 4096)); 替代 ois = new ObjectInputStream(fis); - AnkurVj
@Bha 我在问题中也添加了我遇到的错误。(我错误地将BIS添加到了错误的文件中,因此它可以运行而没有错误。但是,错误仍然存在) - AnkurVj
1个回答

2

这表明从流(和文件)读回的字节被解释为对象(由OIS),但实际上这些字节是其他东西(不是实际对象的字节表示)。这可能是因为显式指定了缓冲区大小(再加上您手动设置位置的事实)。

我建议尝试不显式指定缓冲区大小。

ois = new ObjectInputStream(new BufferedInputStream(fis))


即使没有明确设置缓冲区大小,我仍然会收到相同的错误。我理解这是因为我在手动设置位置,而bis不知道底层fc已经重新定位所导致的。 - AnkurVj
1
现在我开始思考,BIS不是基于自定义逻辑(每个对象)进行缓冲,它只能基于原始字节进行缓冲,而这种用例需要缓冲一个或多个(但不是其中的一部分)对象字节。我越来越倾向于认为您需要编写一个自定义的BIS来实现这个目的。 - Bhaskar
Java真的很差劲。我只是想能够在文件中的不同位置写入对象,并且能够一次读取多个对象,而不是逐个读取。在C++中,我可以简单地使用read((sizeof)object * 20)来读取,并使用我的索引解析读取的字节。在Java中,我浪费了3天的时间试图弄清楚这个问题,但还是一无所获。所谓的易用性到底在哪里?非常感谢你的努力。 - AnkurVj
1
@AnkurVj,我不同意你对Java表现不佳的看法。如果你注意到,在你的C++代码中,你正在编写代码来告诉它如何缓冲字节(通过指定sizeof和*20);在Java中也是一样的-您需要在代码中指定BIS应该如何缓冲-每个对象(您需要扩展一个类并覆盖一些方法来实现这一点-但这是另一个问题)。相反,Java通过IO库提供了许多功能-您需要在C++中编写类似的代码,会有更陡峭的曲线。 - Bhaskar
当我使用指定字节数的文件输入流进行读取或写入时,每个字节是使用单独的系统调用写入还是所有字节都使用单个系统调用写入? - AnkurVj

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接