14 个不稳定版本 (5 个破坏性更新)
0.5.0 | 2024年1月2日 |
---|---|
0.4.0 | 2023年7月25日 |
0.3.0 | 2022年9月6日 |
0.2.3 | 2022年1月16日 |
0.0.2 | 2019年1月27日 |
#296 in 数据库接口
7,991 每月下载量
用于 10 个Crates (6 个直接使用)
205KB
4.5K SLoC
dbase-rs
用于读取和写入 .dbf (dBase / FoxPro) 文件的Rust库。
大多数dBase III和FoxPro类型都可以读取和写入,但Memo类型只能读取(写入将在后续版本中提供)。
如果dbase-rs读取或写入失败或执行不正确,请毫不犹豫地提交问题。
lib.rs
:
dbase是一个旨在读取和写入dBase / FoxPro文件的Rust库。
这些文件现在通常与shapefiles相关联。
读取
Reader 结构是您需要用来读取dBase文件内容的。
一旦您有权访问记录,您将需要使用 match
来匹配实际的 FieldValue
示例
use dbase::FieldValue;
let records = dbase::read("tests/data/line.dbf")?;
for record in records {
for (name, value) in record {
println!("{} -> {:?}", name, value);
match value {
FieldValue::Character(Some(string)) => println!("Got string: {}", string),
FieldValue::Numeric(value) => println!("Got numeric value of {:?}", value),
_ => {}
}
}
}
您还可以创建一个 Reader 并遍历记录。
let mut reader = dbase::Reader::from_path("tests/data/line.dbf")?;
for record_result in reader.iter_records() {
let record = record_result?;
for (name, value) in record {
println!("name: {}, value: {:?}", name, value);
}
}
反序列化
如果您知道特定文件的数据类型,可以使用实现 ReadableRecord 特性将记录“反序列化”到您的自定义结构中。
use std::io::{Read, Seek};
use dbase::Encoding;
struct StationRecord {
name: String,
marker_col: String,
marker_sym: String,
line: String,
}
impl dbase::ReadableRecord for StationRecord {
fn read_using<R1, R2>(field_iterator: &mut dbase::FieldIterator<R1, R2>) -> Result<Self, dbase::FieldIOError>
where R1: Read + Seek,
R2: Read + Seek,
{
use dbase::Encoding;
Ok(Self {
name: field_iterator.read_next_field_as()?.value,
marker_col: field_iterator.read_next_field_as()?.value,
marker_sym: field_iterator.read_next_field_as()?.value,
line: field_iterator.read_next_field_as()?.value,
})
}
}
# fn main() -> Result<(), dbase::Error> {
let mut reader = dbase::Reader::from_path("tests/data/stations.dbf")?;
let stations = reader.read_as::<StationRecord>()?;
assert_eq!(stations[0].name, "Van Dorn Street");
assert_eq!(stations[0].marker_col, "#0000ff");
assert_eq!(stations[0].marker_sym, "rail-metro");
assert_eq!(stations[0].line, "blue");
# Ok(())
# }
如果您使用 serde
可选功能并包含 serde_derive crate,则可以自动实现 ReadableRecord
extern crate serde_derive;
use std::io::{Read, Seek};
use serde_derive::Deserialize;
#[derive(Deserialize)]
struct StationRecord {
name: String,
marker_col: String,
marker_sym: String,
line: String,
}
let mut reader = dbase::Reader::from_path("tests/data/stations.dbf")?;
let stations = reader.read_as::<StationRecord>()?;
assert_eq!(stations[0].name, "Van Dorn Street");
assert_eq!(stations[0].marker_col, "#0000ff");
assert_eq!(stations[0].marker_sym, "rail-metro");
assert_eq!(stations[0].line, "blue");
其他代码页/编码
除了Unicode之外,还通过crate yore
提供了对其他编码的支持。此crate仅支持一些基本的单字节代码页,但许多这样的代码页被旧系统使用,您可能想要打开的dBase数据库可能使用这些代码页。
use yore::code_pages::CP850;
let mut reader = dbase::Reader::from_path_with_encoding("tests/data/cp850.dbf", CP850)?;
let records = reader.read()?;
assert_eq!(records[0].get("TEXT"), Some(&dbase::FieldValue::Character(Some("Äöü!§$%&/".to_string()))));
不接受编码参数的功能默认使用 UnicodeLossy
,它们尝试将所有数据作为 Unicode 读取,并用 Unicode 替换字符无法表示的字符。另外,还可以使用 Unicode
,当数据无法表示为 Unicode 时返回 [Err
]。
写入
要获取一个 TableWriter,您需要使用其 TableWriterBuilder 来构建它,并指定构成记录的字段。
至于读取,您可以将结构体序列化为 dBase 文件,前提是它们与构建 TableWriterBuilder 时声明的字段匹配,通过实现 WritableRecord。
示例
let mut reader = dbase::Reader::from_path("tests/data/stations.dbf")?;
let mut stations = reader.read()?;
let mut writer = dbase::TableWriterBuilder::from_reader(reader)
.build_with_file_dest("stations.dbf").unwrap();
stations[0].get_mut("line").and_then(|_old| Some("Red".to_string()));
writer.write_records(&stations)?;
use dbase::{TableWriterBuilder, FieldName, WritableRecord, FieldWriter, FieldIOError, Encoding};
use std::convert::TryFrom;
use std::io::{Cursor, Write};
struct User {
nick_name: String,
age: f64
}
impl WritableRecord for User {
fn write_using<'a, W>(&self, field_writer: &mut FieldWriter<'a, W>) -> Result<(), FieldIOError>
where W: Write
{
field_writer.write_next_field_value(&self.nick_name)?;
field_writer.write_next_field_value(&self.age)?;
Ok(())
}
}
let mut writer = TableWriterBuilder::new()
.add_character_field(FieldName::try_from("Nick Name").unwrap(), 50)
.add_numeric_field(FieldName::try_from("Age").unwrap(), 20, 10)
.build_with_dest(Cursor::new(Vec::<u8>::new()));
let records = User{
nick_name: "Yoshi".to_string(),
age: 32.0,
};
writer.write_record(&records).unwrap();
如果您使用 serde 可选功能以及 serde_derive crate,您可以为您实现 WritableRecord。
extern crate serde_derive;
use serde_derive::Serialize;
use dbase::{TableWriterBuilder, FieldName, WritableRecord, FieldWriter};
use std::convert::TryFrom;
use std::io::{Cursor, Write};
#[derive(Serialize)]
struct User {
nick_name: String,
age: f64
}
let writer = TableWriterBuilder::new()
.add_character_field(FieldName::try_from("Nick Name").unwrap(), 50)
.add_numeric_field(FieldName::try_from("Age").unwrap(), 20, 10)
.build_with_dest(Cursor::new(Vec::<u8>::new()));
let records = vec![User{
nick_name: "Yoshi".to_string(),
age: 32.0,
}];
writer.write_records(&records);
文件
此 crate 还提供了第三个处理 dBase 文件的选项,即 [File] 结构。
此结构允许在完全读取之前读取/写入现有或新文件。
依赖项
~0.8–18MB
~275K SLoC