Java mappedByteBuffer和flip()和position()
我对Java mappedByteBuffer和flip()和position(),java,buffer,nio,Java,Buffer,Nio,我对java.nio.Buffer有一些问题。基本上,我的问题是,是否总是需要调用flip()来在读和写之间切换,或者只需要调用来实现缓慢的I/O,例如,在先写后读的情况下,以确保数据在读取之前完全写入。我特别要问的是mappedByteBuffer。看起来,如果文件存在并且大小与我所知道的相同,我可以使用position(int newPosition)调用导航到文件的任何部分,并执行读或写操作,即基本上使用缓冲区作为内存块,忘记标记或限制的概念。这是真的吗 考虑下面的例子。如果我有一个包含整
java.nio.Buffer
有一些问题。基本上,我的问题是,是否总是需要调用flip()
来在读和写之间切换,或者只需要调用来实现缓慢的I/O,例如,在先写后读的情况下,以确保数据在读取之前完全写入。我特别要问的是mappedByteBuffer。看起来,如果文件存在并且大小与我所知道的相同,我可以使用position(int newPosition)
调用导航到文件的任何部分,并执行读或写操作,即基本上使用缓冲区作为内存块,忘记标记或限制的概念。这是真的吗
考虑下面的例子。如果我有一个包含整数1的文件,那么从一开始就是2,我似乎可以将另一个整数3放在位置0,倒带并从缓冲区读取3和2。这个限制不应该像在正常的非mmap缓冲区中那样阻止我执行第二个getInt吗?我什么时候需要调用flip()在mappedByteBuffer的写入和读取之间切换?谢谢
final int FILESIZE = 1024;
RandomAccessFile fileHandle;
FileChannel fileChannel;
File testFile = new File("c:/temp/testbbrw.dat");
fileHandle = new RandomAccessFile(testFile, "rw");
fileChannel = fileHandle.getChannel();
MappedByteBuffer mbb = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, FILESIZE);
int pos, data;
mbb.position(0);
mbb.putInt(3);
mbb.position(0);
data=mbb.getInt(); //I get 3
data=mbb.getInt(); //I get 2, which was written to the file before this program runs
mbb.force();
fileHandle.close();
这就是Buffer.flip的作用
347 public final Buffer flip() {
348 limit = position;
349 position = 0;
350 mark = -1;
351 return this;
352 }
它正在准备缓冲区,以便缓冲区上的下一次读取操作从位置0开始,在当前限制结束。意味着你告诉它,你已经完成了对缓冲区的更改,并准备将其移动或复制到其他地方(这意味着读取它)
我的问题首先是,是否总是需要flip()调用来在读和写之间切换,还是仅在I/O速度较慢时才需要,例如,在先写后读的情况下,以确保数据在读取之前完全写入
缓冲区
都是在一种状态下开始的,在这种状态下,您可以读入或放入缓冲区,这是相同的flip()
将它置于一种状态,您可以从中写入,也可以从中获取,这是相同的flip()
不是flip()
的反义词。它唯一的反面是compact()
和clear()
缓冲区保持在可读状态,并且只在需要时将其翻转到可写状态,然后立即将其恢复为可读状态
这是用于I/O的
如果你只是做get()
和put()
我不确定我会使用flip()
,因为这是一个MappedByteBuffer
我肯定不会调用clear()
或compact()
,这两种方法都会对文件造成可怕的影响,而且也排除了使用flip()的可能性
与典型的循环有限缓冲区相比,Java中缓冲区的设计既混乱又违反直觉。更糟糕的是,文档中的术语选择不当,再加上读/写和put/get术语的使用模棱两可,前者指的是外部操作(通常通过通道)使用a缓冲区,后者指的是a缓冲区提供的操作
Java缓冲区
创建时,新缓冲区为“空”,准备填充。构造函数中可能会立即提供一些内容,但它仍处于“填充”状态
flip()
方法将缓冲区的逻辑状态从填充状态“翻转”为清空状态。相当愚蠢的是,flip()
不会自动反转,即使在普通英语中它通常描述逻辑上可逆的动作。事实上,查看代码,在不进行干预的情况下调用两次clear
或compact
会将缓冲区设置为无效状态,导致其他方法返回无意义。[1]
clear()
和compact()
方法是flip()
的逻辑逆,将缓冲区恢复为“填充”状态,前者同时清空缓冲区,后者保留剩余内容
一般建议使用try/finally将任何给定的缓冲区始终保持在一致状态;例如:
ByteBuffer wrap(ByteBuffer src, ByteBuffer tgt) {
// assume buffers are *always* kept in the "filling" state
try {
src.flip(); // change `src` to "emptying"; assume tgt already filling
// transfer some or all of `src` to `tgt`
}
finally {
if(src.remaining()) { src.compact(); } // revert `src` to "filling" without discarding remaining data
else { src.clear(); } // compact() is (usually) less efficient than clearing
}
511 final int nextPutIndex() { // package-private
512 if (position >= limit)
513 throw new BufferOverflowException();
514 return position++;
515 }
516
517 final int nextPutIndex(int nb) { // package-private
518 if (limit - position < nb)
519 throw new BufferOverflowException();
520 int p = position;
521 position += nb;
522 return p;
523 }
524
525 /**
526 * Checks the given index against the limit, throwing an {@link
527 * IndexOutOfBoundsException} if it is not smaller than the limit
528 * or is smaller than zero.
529 */
530 final int checkIndex(int i) { // package-private
531 if ((i < 0) || (i >= limit))
532 throw new IndexOutOfBoundsException();
533 return i;
534 }
典型的有限循环缓冲器
Java缓冲区最不直观的原因是,大多数循环缓冲区实现都具有并发读/写能力,因此它们保持三个值,头
,尾
和容量
(如果语言允许,最后一个值通常从支持数组推断)和它们只允许将值包装起来。head
是读取数据的地方,tail
是写入数据的地方。当到达基础数组的末尾时,head/tail的值被简单地设置为零(即它循环)
当head==tail
时,缓冲区为空。当inc(tail)==head
时,缓冲区已满,当前内容长度由head=limit)得出
513抛出新的BufferOverflowException();
514返回位置++;
515 }
516
517最终int nextPutIndex(int nb){//包专用
518如果(极限位置=极限))
532抛出新IndexOutOfBoundsException();
533返回i;
534 }
在运行程序之前,文件中是否可能有多个2?很抱歉,应首先阅读:)您使用覆盖文件中的1