0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

如何在Rust中高效地操作文件

科技绿洲 来源:TinyZ 作者:TinyZ 2023-09-19 11:51 次阅读

Rust语言是一种系统级、高性能的编程语言,其设计目标是确保安全和并发性。
Rust语言以C和C++为基础,但是对于安全性和并发性做出了很大的改进。

在Rust语言中,操作文件是非常重要的一个功能,本教程将介绍如何在Rust中高效地操作文件,并提供多个实际应用示例。

文件读取

Rust语言中操作文件的第一步就是文件读取,使用Rust内置的std::fs::File类型即可。使用File类型可以打开一个文件,并且从中读取数据。

use std::fs::File;
use std::io::prelude::*;

fn main() - > std::io::Result< () > {
  let mut f = File::open("file.txt")?;
  let mut contents = String::new();
  f.read_to_string(&mut contents)?;
  println!("{}", contents);
  Ok(())
}

上面的代码中调用File::open()函数打开文件,然后向其中读取数据。读取的数据存储在contents变量中,并使用println!()函数将其输出到控制台。

注意,read_to_string()函数是阻塞式的,因此当文件非常大时,应该使用每次读取一小块数据这种方式读取,而不是将整个文件读入内存。

文件追加写入

在Rust语言中,将数据写入文件的方法是使用write_all()函数。write_all()函数的作用是写入一个字节数组或字符串到文件中。但是使用此函数写入,是直接覆盖文件内容,即覆盖原有文件内容。如果要进行文件追加写入,应该使用Rust内置的std::fs::OpenOptions类型。

use std::fs::OpenOptions;
use std::io::prelude::*;

fn main() - > std::io::Result< () > {
  let mut file = OpenOptions::new()
        .append(true)
        .create(true)
        .open("file.txt")?;
  file.write_all(b"Hello, world!")?;
  Ok(())
}

上面的代码中,使用OpenOptions打开文件,并使用append()函数将文件的打开方式设置为追加。使用create()函数则用于创建不存在的文件,如果文件存在,仍然可以正常打开。然后使用write_all()函数将数据写入文件中。

注意:文件追加写入是在原文件内容后追加,而不是从文件尾部开始写入。因此,如果在追加写入数据时需要将数据写入最后,应该先使用seek()函数将指针移动到文件尾部。

文件写入

要在Rust语言中进行文件写入,首先需要创建一个新文件或覆盖现有文件内容。这可以通过std::fs::File类型和std::fs::OpenOptions类型中的create()函数实现。另外,要将数据写入文件中,write_all()函数是不错的选择。

use std::fs::OpenOptions;
use std::io::prelude::*;

fn main() - > std::io::Result< () > {
  let mut file = OpenOptions::new()
        .write(true)
        .create(true)
        .open("file.txt")?;
  file.write_all(b"Hello, world!")?;
  Ok(())
}

上面的代码中使用OpenOptions打开文件,并使用write()函数将文件的打开方式设置为写入(即覆盖原有内容)。使用create()函数则用于创建不存在的文件,如果文件存在,仍然可以正常打开。然后使用write_all()函数将数据写入文件中。

文件复制

Rust语言中可以使用std::fs::copy()函数将一个文件复制到另一个文件中。

use std::fs;

fn main() - > std::io::Result< () >{
  fs::copy("file.txt", "file_copy.txt")?;
  Ok(())
}

上面的代码中,Copy函数将file.txt的所有内容复制到file_copy.txt文件中。如果文件已经存在,则原有文件内容将被覆盖。

文件元数据

在Rust语言中,File类型还提供了一些用于获取文件元数据的函数,如metadata()函数。此函数返回一个std::fs::Metadata类型的元数据结构体,该结构体包含了文件的大小、创建时间、修改时间、权限等信息

use std::fs::metadata;
use std::time::SystemTime;

fn main() - > std::io::Result< () > {
  let metadata = metadata("file.txt")?;
  let created = metadata.created()?;
  let modified = metadata.modified()?;
  let size = metadata.len();
  let perms = metadata.permissions();

  println!("Created: {:?}", created);
  println!("Modified: {:?}", modified);
  println!("Size: {} bytes", size);
  println!("Permissions: {:?}", perms);
  Ok(())
}

上面的代码中,metadata()函数返回文件file.txt的元数据,并使用元数据中的created()函数和modified()函数获取创建时间和修改时间,使用len()函数来获取文件大小(字节数),使用permissions()函数获取文件的权限。

文件重命名和移动

在Rust语言中,使用std::fs::rename()函数可以将文件重命名或者移动到其他文件夹中。

use std::fs::rename;

fn main() - > std::io::Result< () > {
  rename("file.txt", "new_file.txt")?;
  Ok(())
}

上面的代码中,rename()函数将文件file.txt重命名为new_file.txt,如果new_file.txt文件已经存在,则重命名将失败。

此外,如果要移动文件到其他文件夹中,则可以在目标文件名中指定文件夹路径。例如,如果我们将文件移动到子文件夹/path/to/subdir/中,则可以在目标文件名中指定路径:/path/to/subdir/new_file.txt

多种操作组合

在Rust语言中,可以将多种文件操作组合使用,例如读取文件,删除文件内容,然后将新数据写入文件中。

use std::fs::OpenOptions;
use std::io::prelude::*;

fn main() - > std::io::Result< () > {
  let mut file = OpenOptions::new()
        .read(true)
        .write(true)
        .open("file.txt")?;
  let mut contents = String::new();
  file.read_to_string(&mut contents)?;
  contents = contents.replace("Hello", "World");
  file.set_len(0)?; // 清空文件
  file.write_all(contents.as_bytes())?;
  Ok(())
}

上面的代码中,使用OpenOptions打开文件,并使用read()函数将文件的打开方式设置为读取,同时打开文件写入的功能。读取文件的内容,并使用replace()函数将文本中的“Hello”替换为“World”。然后使用set_len()函数将文件长度重置为0(即清空文件)。使用write_all()函数将新数据写入文件。

扩展阅读 - 读取带BOM头的文件

BOM (Byte Order Mark) 是一个Unicode字符,用于标识文件的编码格式(UTF-8, UTF-16LE, UTF-16BE, UTF-32LE, UTF-32BE…)。BOM通常是在文件开头的位置插入的,用于确定字符的顺序和字节顺序。

源于Unicode编码,目前被广泛使用于自定义字符集。例如:GB18030-2022

读取带BOM头的文件

pub trait BOMReader {
    fn has_bom(&self) - > bool;
    fn read_content(&mut self) - > Result< String, std::io::Error >;
}

pub struct FileBOMReader {
    file: std::fs::File,
    bom: Option< Vec< u8 >>,
}

impl FileBOMReader {
    pub fn new(file: std::fs::File) - > Self {
        Self { file, bom: None }
    }

    fn read_bom(&mut self) - > Result< (), std::io::Error > {
        let mut bom_buf = [0u8; 3];
        let bytes_read = self.file.read(&mut bom_buf)?;
        if bytes_read >= 3 && bom_buf[..3] == [0xEF, 0xBB, 0xBF] {
            self.bom = Some(bom_buf[..3].to_vec());
        } else if bytes_read >= 2 && bom_buf[..2] == [0xFE, 0xFF] {
            self.bom = Some(bom_buf[..2].to_vec());
        } else if bytes_read >= 2 && bom_buf[..2] == [0xFF, 0xFE] {
            self.bom = Some(bom_buf[..2].to_vec());
        } else if bytes_read >= 4 && bom_buf[..4] == [0x00, 0x00, 0xFE, 0xFF] {
            self.bom = Some(bom_buf[..4].to_vec());
        } else if bytes_read >= 4 && bom_buf[..4] == [0xFF, 0xFE, 0x00, 0x00] {
            self.bom = Some(bom_buf[..4].to_vec());
        }
        Ok(())
    }
}

impl BOMReader for FileBOMReader {
    fn has_bom(&self) - > bool {
        self.bom.is_some()
    }

    fn read_content(&mut self) - > Result< String, std::io::Error > {
        if self.bom.is_none() {
            self.read_bom()?;
        }
        let mut buf = String::new();
        self.file.read_to_string(&mut buf)?;
        if self.has_bom() {
            match &self.bom {
                Some(bom) if bom.starts_with([0xEF, 0xBB, 0xBF].as_ref()) = > {
                    buf.drain(..3);
                }
                Some(bom) if bom.starts_with([0xFF, 0xFE].as_ref()) = > {
                    buf = buf.as_bytes().chunks_exact(2).map(|c| c[1]).collect();
                }
                Some(bom) if bom.starts_with([0xFE, 0xFF].as_ref()) = > {
                    buf = buf.as_bytes().chunks_exact(2).map(|c| c[0]).collect();
                }
                Some(bom) if bom.starts_with([0x00, 0x00, 0xFE, 0xFF].as_ref()) = > {
                    buf = buf.as_bytes().chunks_exact(2).skip(2).map(|c| c[1]).collect();
                }
                Some(bom) if bom.starts_with([0xFF, 0xFE, 0x00, 0x00].as_ref()) = > {
                    buf = buf.as_bytes().chunks_exact(4).skip(1).flat_map(|c| &c[2..]).collect();
                }
                _ = > {}
            }
        }
        Ok(buf)
    }
}

该trait定义了一个BOMReader并提供了一个FileBOMReader的实现,可检测和读取文件中的 BOM(Byte Order Mark)。BOM 通常用于标识文件的编码格式,因为某些编码格式的字符集在读取时可能有不同的字节序。

示例代码

use std::fs::File;
use std::io::{Read, Write};

fn main() {
    let mut file = File::create("test_utf8.txt").unwrap();
    let content = "Hello, World!n";
    file.write_all(content.as_bytes()).unwrap();
    let mut reader = FileBOMReader::new(File::open("test_utf8.txt").unwrap());
    let result = reader.read_content().unwrap();
    assert_eq!(result, content);

    let mut file = File::create("test_utf16be.txt").unwrap();
    let bom = [0xFE, 0xFF];
    file.write_all(&bom).unwrap();
    let content = "Hello, World!n";
    file.write_all(content.as_bytes()).unwrap();
    let mut reader = FileBOMReader::new(File::open("test_utf16be.txt").unwrap());
    let result = reader.read_content().unwrap();
    assert_eq!(result, content);

    let mut file = File::create("test_utf16le.txt").unwrap();
    let bom = [0xFF, 0xFE];
    file.write_all(&bom).unwrap();
    let content = "Hello, World!n";
    file.write_all(content.as_bytes()).unwrap();
    let mut reader = FileBOMReader::new(File::open("test_utf16le.txt").unwrap());
    let result = reader.read_content().unwrap();
    assert_eq!(result, content);

    let mut file = File::create("test_utf32be.txt").unwrap();
    let bom = [0x00, 0x00, 0xFE, 0xFF];
    file.write_all(&bom).unwrap();
    let content = "Hello, World!n";
 file.write_all(content.as_bytes()).unwrap();
    let mut reader = FileBOMReader::new(File::open("test_utf32be.txt").unwrap());
    let result = reader.read_content().unwrap();
    assert_eq!(result, content);

    let mut file = File::create("test_utf32le.txt").unwrap();
    let bom = [0xFF, 0xFE, 0x00, 0x00];
    file.write_all(&bom).unwrap();
    let content = "Hello, World!n";
    file.write_all(content.as_bytes()).unwrap();
    let mut reader = FileBOMReader::new(File::open("test_utf32le.txt").unwrap());
    let result = reader.read_content().unwrap();
    assert_eq!(result, content);
}

通过编写这样的例子,我们可以测试我们的代码,确保它能正确地读取各种类型的文件。

使用encoding_rs读取带BOM头的文件

在Rust中,可以使用std::fs::Filestd::io::BufReader模块读取文件,并使用encoding_rs模块解析BOM头以获取文件的编码信息。

use std::fs::File;
use std::io::BufReader;
use encoding_rs::Encoding;

fn main() {
    let filename = "example.txt";
    let file = File::open(filename).unwrap();
    let mut reader = BufReader::new(file);

    // 按照Utf8读取文件    let decoder = Encoding::utf8().new_decoder_with_bom_handling();
    let (result, _, _) = decoder.decode(&mut reader);
 match result {
        Some(s) = > {
            println!("Content: {}", s);
        }
        None = > {
            println!("Error decoding file");
        }
    }
}

这个示例使用了Utf8编码格式,但是在实现中使用了new_decoder_with_bom_handling()函数以自动检测和处理BOM头。

如果需要支持其他编码类型,则需要使用不同的编码器(比如GBK)和相应的 decoder。

// 按照GBK读取文件
let decoder = Encoding::GBK.new_decoder_with_bom_handling();
// 解码
let (result, _, _) = decoder.decode(&mut reader);

根据具体的编码类型来选择对应的编码器,就可以正常读取文件内容了。

总结

以上是在Rust语言中操作文件的实际应用示例,涵盖了文件读取、追加写入、重命名和移动、复制、写入、获取元数据等操作。这些操作非常基础,但往往也是程序开发中必不可少的操作。在以后的程序开发中,读者可以根据需求将这些操作进行各种组合,以实现更为复杂的文件操作需求。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 编程语言
    +关注

    关注

    9

    文章

    1657

    浏览量

    32294
  • 函数
    +关注

    关注

    3

    文章

    3225

    浏览量

    60661
  • C++
    C++
    +关注

    关注

    20

    文章

    1981

    浏览量

    72817
  • rust语言
    +关注

    关注

    0

    文章

    53

    浏览量

    2889
  • Rust
    +关注

    关注

    1

    文章

    180

    浏览量

    6281
收藏 人收藏

    评论

    相关推荐

    电气CAD文件中高效的工作流程

    文件中高效的工作流程性能卓越的 PCschemetic ELautomation软件具有作电气设计时所需要的所有功能。其独一无二的工作流程可节省您大量的时间,它代替了所有的订货信息——从
    发表于 12-04 11:24

    STM32F407使用FatFS,发现跟文件夹相关函数命令都可操作,但不能操作文件的函数

    文件夹相关函数命令都可操作,就是不能操作文件的函数,请问这是为什么?
    发表于 12-17 08:48

    只会用Python?教你在树莓派上开始使用Rust

    操作系统可能会产生不同的结果,它也可以通过远程SSH连接正常运行。如何在Raspberry Pi上安装Rust要安装rust,请转到rust-lang安装页面,然后将install命令复制到您的终端中
    发表于 05-20 08:00

    何在STM32 (Cortex M3)和GD32(RISC-V)上用Rust开发

    操作系统。Rust 的官方主页标语就是 reliable and efficient,吉祥物也是硬壳的螃蟹,自然就有人想到把 Rust 应用到安全可靠的嵌入式。嵌入式的特点就在于指令集
    发表于 06-21 10:38

    自己改动过的MP3制作文件资料合集

    作文件资料合集
    发表于 01-11 09:08 0次下载

    何在Go中操作文本文件

    文件文件的功能。 文件是现代世界我们日常生活的重要组成部分。文本文件对于存储结构化的人类可读数据非常有用,而无需使用外部软件或数据库。 如果您想知道如何开始在Go中操作文本文件,那么本文是适合您的地方。
    发表于 09-29 09:48 471次阅读

    WeLink协作文档,高效协同办公的重要选择

    作文档,高效协同办公的重要选择 一直以来,打工人都在追求更高的办公效率,以期达到事半功倍的效果。尤其是新冠疫情期间,不少人的出行和工作都受到了影响,很多上班族被迫在家办公,线上办公也
    的头像 发表于 10-11 20:51 427次阅读
    WeLink协<b>作文</b>档,<b>高效</b>协同办公的重要选择

    华为云WeLink协作文档,助您开启职场高效办公

    文件的痛苦、远程体验同步沟通的高效,华为云WeLink协作文档可以帮到你。 1)免转换,全面兼容office Welink协作文档是华为云旗下研发的一款数字化办公应用,能够让办公更高效的在线文档协同工具。WeLink协作文
    的头像 发表于 12-14 11:37 519次阅读
    华为云WeLink协<b>作文</b>档,助您开启职场<b>高效</b>办公

    Google在Chromium项目中支持使用Rust

    Rust 版本都容易受到攻击。 Rust 1.66.0 的补丁文件也可获得,用于定制工具链。 如果您还不能升级到 Rust 1.66.1,官方建议将
    的头像 发表于 01-16 10:52 909次阅读

    何在Linux中高效运行终端命令

    操作文件操作、程序管理和服务自动化是您可以使用 shell 命令高效执行的一些操作
    的头像 发表于 03-20 09:39 251次阅读

    如何使用Rust连接Redis

    Rust操作Redis。 Redis依赖库 在Rust中有很多Redis的客户端库可以选择,这里我们选择使用redis-rs库。在Cargo.toml文件中添加依赖: [dependencies
    的头像 发表于 09-19 16:22 238次阅读

    何在Rust中使用Memcached

    Rust是一种系统级编程语言,具有内存安全、高性能和并发性等特点。Rust语言的Memcached库提供了
    的头像 发表于 09-19 16:30 418次阅读

    何在Rust项目中使用InfluxDB 2.x

    Rust语言提供了InfluxDB 2.x的官方客户端库,可以方便地在Rust项目中使用InfluxDB 2.x。 本教程将介绍如何在Rust项目中使用InfluxDB
    的头像 发表于 09-19 16:33 56次阅读

    何在Rust中读写文件

    Rust中,读写文件是一项非常常见的任务。本教程将介绍如何在Rust中读写文件,包括基础用法和进阶用法。 基础用法 读取文件内容 使用 std::fs::File 和 std::io::Read 模块可以读取文件内容。首先,我
    的头像 发表于 09-20 10:57 216次阅读