File2 - 撰寫讀取檔案
前一篇文章[1]有介紹過File常見的一些功能
這篇會介紹讀寫的方法
讀寫都是一個trait
常見寫有兩種,write和write_all
讀則是有三種,read、read_to_end、read_to_string
寫
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會嘗試將整個緩衝區寫入資料
但有時候只會寫入部分、甚至寫入失敗
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();
}
最後檔案內會長這樣
讀
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的長度
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]
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