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 数据库接口

Download history 1577/week @ 2024-03-14 1951/week @ 2024-03-21 1873/week @ 2024-03-28 1809/week @ 2024-04-04 2026/week @ 2024-04-11 1303/week @ 2024-04-18 1586/week @ 2024-04-25 1535/week @ 2024-05-02 1219/week @ 2024-05-09 1914/week @ 2024-05-16 1608/week @ 2024-05-23 2035/week @ 2024-05-30 2246/week @ 2024-06-06 2106/week @ 2024-06-13 1918/week @ 2024-06-20 1466/week @ 2024-06-27

7,991 每月下载量
用于 10 个Crates (6 个直接使用)

MIT 许可证

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