我们如何知道记录是否已被读取?我们如何关注记录指针?

时间:2013-11-17 17:58:23

标签: java file file-io io nio

我对与处理文件相关的算法感到困惑 根据我的在线研究,表示可变长度记录的标准方法是沿数据放置元数据,例如记录的长度。另外,如果我们想以某种顺序保留记录,我们还可以将指针存储到下一条记录中作为记录字段的一部分。
我们以一个文件为例,我们有<length,data,next_record_ptr>形式的记录,这与我上面描述的一致。
我看到的代码片段通常在内存缓冲区中读取文件的一部分,这是有道理的。示例:

ByteBuffer copy = ByteBuffer.allocate(SIZE);  
FileChannel fc = FileChannel.open(file, READ, WRITE);  
int nread;  
do {  
   nread = fc.read(copy);  
} while (nread != -1 && copy.hasRemaining());  

我认为这或多或少是一种读取内存中文件部分的方法。 SIZE可以是包含多个记录的大小。

问题:当我们在内存中有X个记录时,我们怎么知道我们想要读取的特定记录是否在我们的缓冲区中?示例:如果我有指向下一条记录的指针,我如何知道此特定记录已作为缓冲区的一部分加载,或者我必须从文件中读取更多数据?
这部分在教科书中被提及为简单但我对如何实际实现这一点感到困惑。

要明确:用Java提供示例代码真的很棒!!!但是使用伪代码或清晰算法对这个暗点的清晰解释也很棒!

更新
更清楚:
如果我在数组[N]中读取了N条记录。如果我读取记录array[0],然后获取array[0].pointerToNext,例如文件中的0x123A。我怎么知道:
1)如果已在缓冲区中读取位置0x123A中的记录,即array[n] 2)缓冲区中该记录的索引是什么?

2 个答案:

答案 0 :(得分:1)

在文件中,记录指针通常存储为记录索引或文件位置。因此,您可以根据文件中的当前位置推断您是否已经读取了特定记录。

在您的示例中,您可以使用变量pos跟踪文件位置:

int pos = 0;
int nread;  
do {  
   nread = fc.read(copy);
   if(nread == -1) {
      break;
   } else {
      pos += nread;
   }
} while (copy.hasRemaining());  

答案 1 :(得分:1)

您需要随时阅读数据并将其与读数相关联。这是解决这个问题的一种方式,也许我会这样做。

// read a made up database
// untested

public class SimpleDatabaseRead {

    public void main(String[] args) {
        if (args == null || args.length == 0) {
            System.out.println("no file");
            return;
        }

        try {
            File file = new File(args[0]);
            FileInputStream in = null;

            try {
                in = new FileInputStream(file);

                // rec length will be 16-bit unsigned
                // large array OK, only 64KiB in mem
                byte[] bytes = new byte[65536];

                int bread = 0;
                long fpos = 0, next = 0;

                char[][] rec;

                while ((bread = in.read(bytes, 0, 4)) != -1) {
                    fpos += bread;

                    // length of this rec in bytes
                    int len = ((bytes[0] & 0xFF) << 8) | (bytes[1] & 0xFF);

                    // num entries in rec, for convenience
                    int entries = ((bytes[2] & 0xFF) << 8) | (bytes[3] & 0xFF);

                    if (in.read(bytes, 0, len) != len)
                        break;
                    fpos += len;

                    rec = new char[entries][];

                    for (int i = 0, k = 0, h; i < entries; i++) {
                        rec[i] = new char[
                            ((bytes[k++] & 0xFF) << 8) | (bytes[k++] & 0xFF)];

                        for (h = 0; h < rec[i].length && k < len; h++)
                            rec[i][h] = ((bytes[k++] & 0xFF) << 8) | (bytes[k++] & 0xFF);
                    }

                    for (char[] rec : recs)
                        System.out.println("record: " + new String(rec));

                    if (in.read(bytes, 0, 4) != len)
                        break;
                    fpos += bread;

                    // 48-bit file marker of next rec
                    next = ((bytes[0] & 0xFF) << 32)
                         | ((bytes[1] & 0xFF) << 24)
                         | ((bytes[2] & 0xFF) << 24)
                         |  (bytes[3] & 0xFF);

                    if (next < fpos) {
                        in.close();
                        in = new FileInputStream(file);
                        in.skip(fpos = next);
                    }
                }

            } finally {
                if (in != null) in.close();
            }
            System.out.println("read ended");

        } catch (IOException e) {
            System.out.println(e.getMessage());
        } catch (FileNotFoundsException e) {
            System.out.println(e.getMessage());
        }
    }
}

在Java中寻找我所知道的并不是一个好方法。 Seeking a ByteArrayInputStream using java.io有一些想法,但它的要点是基本上你要么:

  • 创建一个新的InputStream,如示例或
  • 所示
  • 使用RandomAccessFile,据报道通常较慢(自己测试)。

换句话说,您最好使用可以按顺序读取的数据。

而不是像你所建议的那样以块的方式读取块,我猜想将缓冲区大小设置为任意长度并随时制定记录。要判断下一个点是否在“缓冲区”中,您将读取指针并基本上使用条件pointer < fpos + buffer.length。我不认为我会推荐这种方法,因为缓冲区可能小于记录的长度。在这种情况下,您最终会在新数组中制作录音,以便您可以阅读整个内容。除非它们非常非常大,否则你必须部分地阅读这些块。