磁带的存储是按照块进行的,所以对磁带的读写都是以块为单位的,这是和磁盘文件最大的不同之处。
每次用read读的时候,必须指定读的大小是块的大小。而在写磁带的时候也要尽量按照块的大小进行。
比如,一个磁带的块大小是10K,那么如果read调用是这样的
n = read(fd, buf, 100);
那么将返回错误:Cannot allocate memory,这显然是一个莫名其妙的错误提示。
但是如果这样调用
n = read(fd, buf, 10*1024+100);
那么只能读出一块10K的数据,而后面的100字节将不会被读出
显然对于高层应用,这种束缚是极为不爽的。
所以,对磁带进行读写缓存是必要的。
给个我刚刚写的利用缓存读磁带的示例,写的部分类似
Tape类包括几个成员变量:
char* read_buf; // 读的缓冲区
unsigned int rbuf_ptr; // 当前的读指针在缓冲区内的位置
unsigned int rbuf_len; // 缓冲区内已经读入的数据长度
unsigned int block_size; // 磁带的块大小
int Tape::read(char* buffer, int size)
{
if (!is_open()) {
if (!open()) {
return -1;
}
}
int nread = 0;
int ntodo = size;
while (1) {
// see if there're enough chars we can provide in read_buf,
// instead of reading from tape.
int nremain = rbuf_len - rbuf_ptr;
if (nremain >= ntodo) {
// yes, how happy we are.
memcpy(buffer + nread, read_buf + rbuf_ptr, ntodo);
rbuf_ptr += ntodo;
nread += ntodo;
break;
}
// not enough? okay, let's bring out what we have, firstly
if (nremain) {
memcpy(buffer + nread, read_buf + rbuf_ptr, nremain);
nread += nremain;
ntodo -= nremain;
}
// and then, we read a block more from tape.
int n = ::read(fd, read_buf, block_size);
if (n < 0) {
ok = false;
err = string("Tape::read() ") + strerror(errno);
return -1;
}
rbuf_len = n;
rbuf_ptr = 0;
if (n == 0) // read nothing, hopefully an EOF meeted.
break;
}
return nread;
}
如何获取磁带块大小,是个容易的问题,因为一般磁带块的大小最大值是256K,
所以只要按照这个最大值,读出一块,查看一下读出的数据长度就好了
n = read(fd, buf, 256*1024);
或者更简单的,用下面的命令
dd if=/dev/tape of=/tmp/blk bs=256K count=1
ls -lh /tmp/blk
这个文件的大小就是了