隱私權政策

搜尋此網誌

技術提供:Blogger.

關於我自己

我的相片
目前從事軟體相關行業,喜歡閱讀、健身、喝調酒。習慣把遇到的問題記下來,每天做一些整理方便自己以後查。 Python、Rust、Kotlin等程式語言皆為自學,目前比較著重在Rust語言,歡迎一起討論。

2023年12月29日 星期五

Rust File概述2 - 撰寫讀取檔案


File2 - 撰寫讀取檔案

前一篇文章[1]有介紹過File常見的一些功能

這篇會介紹讀寫的方法

讀寫都是一個trait

常見寫有兩種,write和write_all

讀則是有三種,read、read_to_end、read_to_string


write[2]

fn write(&mut self, buf: &[u8]) -> Result<usize>

write為將緩衝區buf寫入資料

回傳result,內容為寫入資料的byte值

例如

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

fn main() {
    let file_path = "example.txt";
    let mut file = File::options()
        .write(true)
        .read(true)
        .open(file_path)
        .unwrap();
    let buf_write = String::from("1234567890");
    let write_byte = file.write(buf_write.as_bytes()).unwrap();
    println!("{}", write_byte);
}
10

就是將1234567890寫入example.txt

並且回傳寫入的byte值

也就是10


要注意write會嘗試將整個緩衝區寫入資料

但有時候只會寫入部分、甚至寫入失敗


write_all[3]

fn write_all(&mut self, buf: &[u8]) -> Result<()>

write_all會將整個緩衝區寫進資料裡

此方法會持續呼叫write直到緩衝區沒資料

因此不會發生緩衝區寫到一半的情況

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

fn main() {
    let file_path = "example.txt";
    let mut file = File::options()
        .write(true)
        .read(true)
        .open(file_path)
        .unwrap();
    let buf_write = String::from("1234567890");
    file.write_all(buf_write.as_bytes()).unwrap();
}

最後檔案內會長這樣


read[4]

fn read(&mut self, buf: &mut [u8]) -> Result<usize>

read可以讀取文件內的東西

輸入一個緩衝區,用來存取檔案內的東西

假設檔案內容為1234567890

則緩衝區大小至少要10以上,才可以完整存取

而輸出則是ASCII碼

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

fn main() {
    let file_path = "example.txt";
    let mut file = File::options()
        .write(true)
        .read(true)
        .open(file_path)
        .unwrap();
    let mut buf_read = [0; 10];
    file.read(&mut buf_read).unwrap();
    println!("{:?}", buf_read);
}
[49, 50, 51, 52, 53, 54, 55, 56, 57, 48]

如果buf_read大於10則會出現

    let mut buf_read = [0; 20];
    file.read(&mut buf_read).unwrap();
    println!("{:?}", buf_read);
[49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

小於10則出現只出現字串長度的數字

    let mut buf_read = [0; 2];
    file.read(&mut buf_read).unwrap();
    println!("{:?}", buf_read);
[49, 50]

因此使用read的時候要注意buf的長度


read_to_end[5]

fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize>

read_to_end為此時游標位置到文件末端

游標位置的觀念要看Seek[6]

輸入為一個數組,輸出一樣是ASCII碼

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

fn main() {
    let file_path = "example.txt";
    let mut file = File::options()
        .write(true)
        .read(true)
        .open(file_path)
        .unwrap();
    let mut buf_read = Vec::new();
    file.read_to_end(&mut buf_read).unwrap();
    println!("{:?}", buf_read);
}
[49, 50, 51, 52, 53, 54, 55, 56, 57, 48]

那現在假設buf_read裡面本來就有數據

read_to_end會繼續往後加數據

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

fn main() {
    let file_path = "example.txt";
    let mut file = File::options()
        .write(true)
        .read(true)
        .open(file_path)
        .unwrap();
    let mut buf_read = vec![0];
    file.read_to_end(&mut buf_read).unwrap();
    println!("{:?}", buf_read);
}
[0, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48]


read_to_string[6]

fn read_to_string(&mut self, buf: &mut String) -> Result<usize>

read_to_string為將資料讀成string

輸出則直接是字串

而不是像上面一樣是ASCII

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

fn main() {
    let file_path = "example.txt";
    let mut file = File::options()
        .write(true)
        .read(true)
        .open(file_path)
        .unwrap();
    let mut buf_read = String::new();
    file.read_to_string(&mut buf_read).unwrap();
    println!("{:?}", buf_read);
}
1234567890

如果說這次example.txt改成有換行的


則輸出會長這樣

1234567890\r\n9876543210

會增加換行符號


延伸問題

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

fn main() {
    let file_path = "example.txt";
    let mut file = File::options()
        .write(true)
        .read(true)
        .open(file_path)
        .unwrap();
    let buf_write = String::from("1234567890");
    file.write(buf_write.as_bytes()).unwrap();
    let mut buf_read = String::new();
    file.read_to_string(&mut buf_read).unwrap();
    println!("{}", buf_read);
}

我用File::options打開一個read-write模式的檔案

我先把1234567890寫入檔案後

用read_to_string讀取

此時結果為


甚麼東西都沒讀取到




Ans:

那是因為我write寫完後

游標會在檔案最後面

此時讀取不會有東西

必須把游標往前移動才可以

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

fn main() {
    let file_path = "example.txt";
    let mut file = File::options()
        .write(true)
        .read(true)
        .open(file_path)
        .unwrap();
    let buf_write = String::from("1234567890");
    file.write(buf_write.as_bytes()).unwrap();
    file.seek(SeekFrom::Start(0)).unwrap();
    let mut buf_read = String::new();
    file.read_to_string(&mut buf_read).unwrap();
    println!("{}", buf_read);
}
1234567890


延伸閱讀

Rust File概述1 - 存取檔案 ~ LaGee-Blog (lageeblog.blogspot.com)

Rust Seek概述 - 移動檔案內游標位置 ~ LaGee-Blog (lageeblog.blogspot.com)




參考資料

[1] https://lageeblog.blogspot.com/2023/12/Rust-File1.html

[2] https://doc.rust-lang.org/std/io/trait.Write.html#tymethod.write

[3] https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all

[4] https://doc.rust-lang.org/std/io/trait.Read.html#tymethod.read

[5] https://doc.rust-lang.org/std/io/trait.Read.html#method.read_to_end

[6] https://lageeblog.blogspot.com/2023/12/rust-seek.html

[7] https://doc.rust-lang.org/std/io/trait.Read.html#method.read_to_string


0 comments:

張貼留言