我正在尝试提取.tar.bz文件(或任何实际的.tar.what文件),并且还能够获得xx%进度报告。到目前为止,我有这个:
pub fn extract_file_with_progress<P: AsRef<Path>>(&self, path: P) -> Result<()> {
let path = path.as_ref();
let size = fs::metadata(path)?;
let mut f = File::open(path)?;
let decoder = BzDecoder::new(&f);
let mut archive = Archive::new(decoder);
for entry in archive.entries()? {
entry?.unpack_in(".")?;
let pos = f.seek(SeekFrom::Current(0))?;
}
Ok(())
}
这个想法是使用pos/size
来获取百分比,但是编译上面的函数会得到错误cannot borrow f as mutable because it is also borrowed as immutable
。
我知道错误的含义,但我并没有真正使用f
作为可变变量。我只使用seek函数来获取当前位置。
是否有一种解决方法,可以通过强制编译器忽略可变借用或以某种不可变的方式获取位置?
答案 0 :(得分:8)
文件有点特殊。常用的read()
和seek()
和write()
方法(在Read
,Seek
和Write
特征上定义)采用self
可变参考:
fn read(&mut self, buf: &mut [u8]) -> Result<usize>
fn seek(&mut self, pos: SeekFrom) -> Result<u64>
fn write(&mut self, buf: &[u8]) -> Result<usize>
但是,所有提到的特征也都针对&File
实现,即针对文件的不可变引用:
因此,即使您只有对该文件的只读引用,也可以修改该文件。对于这些实现,Self
类型为&File
,因此通过可变引用接受self
实际上意味着接受&mut &File
,即对文件引用的可变引用。 / p>
您的代码将&f
传递给BzDecoder::new()
,从而创建了一个不变的借位。稍后您调用f.seek(SeekFrom::Current(0))
,它通过可变引用将f
传递给seek
。但是,这是不允许的,因为您已经拥有文件的不可变借项。解决方案是改为在Seek
上使用&File
实现:
(&mut &f).seek(SeekFrom::Current(0))
或更简单
(&f).seek(SeekFrom::Current(0))
这只会创建第二个不可变的借用,Rust的规则允许引用。
我创建了一个playground example demonstrating that this works。如果将(&f)
替换为f
,则会得到最初的错误。