3个不稳定版本
0.4.1 | 2023年4月24日 |
---|---|
0.4.0 | 2023年4月21日 |
0.3.0 | 2022年11月24日 |
1252 在 算法
320KB
7K SLoC
dbase-rs
Rust库,用于读取和写入 .dbf(dBase / FoxPro)文件。
大多数dBase III和FoxPro类型都可以读取和写入,但Memo类型只能读取(写入将在后续版本中提供)。
如果dbase-rs在读取或写入时失败或执行了不正确的操作,请毫不犹豫地提交问题。
lib.rs
:
typed_shapefile是一个旨在读取和写入dBase / FoxPro文件的Rust库。
这些文件现在通常只与shapefile相关联。
读取
Reader 结构是您需要使用以读取dBase文件内容的。
一旦您访问到记录,您将需要对实际的 FieldValue 进行 match
。
示例
use typed_shapefile::FieldValue;
let records = typed_shapefile::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 = typed_shapefile::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 typed_shapefile::Encoding;
struct StationRecord {
name: String,
marker_col: String,
marker_sym: String,
line: String,
}
impl typed_shapefile::ReadableRecord for StationRecord {
fn read_using<T>(field_iterator: &mut typed_shapefile::FieldIterator<T>) -> Result<Self, typed_shapefile::FieldIOError>
where T: Read + Seek
{
use typed_shapefile::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<(), typed_shapefile::Error> {
let mut reader = typed_shapefile::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 = typed_shapefile::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");
其他代码页/编码
通过crate yore
提供对Unicode以外的编码的支持。此crate仅支持一些基本的单字节代码页,但其中许多在旧系统中使用,您可能想要打开的dBase数据库可能会使用这些代码页。
use yore::code_pages::CP850;
let mut reader = typed_shapefile::Reader::from_path_with_encoding("tests/data/cp850.dbf", CP850)?;
let records = reader.read()?;
assert_eq!(records[0].get("TEXT"), Some(&typed_shapefile::FieldValue::Character(Some("Äöü!§$%&/".to_string()))));
不接收编码作为参数的函数默认使用 UnicodeLossy
,它们尝试将所有数据作为Unicode读取,并用Unicode替换字符替换不可表示的字符。另可选 Unicode
,当数据无法表示为Unicode时返回 [Err
]
写入
为了获取一个 TableWriter,您需要使用其 TableWriterBuilder 来构建它,并指定构成记录的字段。
至于读取,如果您实现了 WritableRecord,则可以将结构体序列化到 dBase 文件中,前提是它们与构建 TableWriterBuilder 时声明的字段相匹配。
示例
let mut reader = typed_shapefile::Reader::from_path("tests/data/stations.dbf")?;
let mut stations = reader.read()?;
let mut writer = typed_shapefile::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 typed_shapefile::{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 typed_shapefile::{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);
依赖项
~5.5MB
~134K SLoC