使用Rust读取固定宽度文件并导入Polars DataFrame遇问题
问题分析与解决
核心问题
你的代码中,从文件读取的from_file方法缺少指定每行固定宽度的关键步骤——字符串版本的from_string调用了.width(72)来定义行长度,但文件读取逻辑遗漏了这一步。fixed_width的Reader从文件读取时必须明确每行宽度,否则无法确定行边界,导致程序卡住无响应。
修复后的代码
修改from_file方法,添加.width(72)(和字符串版本一致,你的文件每行长度为72):
use serde::{Serialize, Deserialize}; use fixed_width::{FixedWidth, FieldSet, Reader}; fn main() { let r_file = "path/to/file.r01"; // let data = String::from("R 5001.00 1001.00 513777.5 2093285.7 0.0 R 5001.00 1002.00 513786.6 2093281.6 0.0 R 5001.00 1003.00 513795.7 2093277.4 0.0 R 5001.00 1004.00 513708.8 2093273.3 0.0 "); #[derive(Serialize, Deserialize, Debug)] struct SpsRecord { pub line: f32, pub point: f32, pub easting: f32, pub northing: f32 } impl FixedWidth for SpsRecord { fn fields() -> FieldSet { FieldSet::Seq(vec![ FieldSet::new_field(1..11).name("line"), FieldSet::new_field(11..21).name("point"), FieldSet::new_field(46..55).name("easting"), FieldSet::new_field(55..65).name("northing") ]) } } impl SpsRecord { fn from_file(path: &str) -> Result<Vec<Self>, fixed_width::Error> { // 添加.width(72)指定每行固定宽度 let mut reader = Reader::from_file(path)?.width(72); let records: Result<Vec<Self>, fixed_width::Error> = reader .byte_reader() .filter_map(Result::ok) .map(|bytes| fixed_width::from_bytes(&bytes)) .collect(); records // 直接返回Result,无需额外match语句 } // fn from_string(data: &str) -> Result<Vec<Self>, fixed_width::Error> { // let mut reader = Reader::from_string(data).width(72); // let records: Result<Vec<Self>, fixed_width::Error> = reader // .byte_reader() // .filter_map(Result::ok) // .map(|bytes| fixed_width::from_bytes(&bytes)) // .collect(); // records // } } println!("Reading {}...", r_file); match SpsRecord::from_file(r_file) { Ok(records) => { for record in records { println!("{:?}", record); } } Err(err) => { eprintln!("{:#?}", err); } } // println!("Reading {}...", data); // match SpsRecord::from_string(&data) { // Ok(records) => { // for record in records { // println!("{:?}", record); // } // } // Err(err) => { // eprintln!("{:#?}", err); // } // } }
额外优化说明
- 直接返回
records变量即可,无需额外的match语句,Result类型本身符合方法返回要求。 - 若运行仍报错,可通过
eprintln!打印的错误信息排查文件路径是否正确。
转Polars DataFrame示例
解析完成后,可将Vec<SpsRecord>转换为Polars DataFrame:
use polars::prelude::*; // 假设已获取records: Vec<SpsRecord> let df = DataFrame::new(vec![ Series::new("line", records.iter().map(|r| r.line).collect::<Vec<f32>>()), Series::new("point", records.iter().map(|r| r.point).collect::<Vec<f32>>()), Series::new("easting", records.iter().map(|r| r.easting).collect::<Vec<f32>>()), Series::new("northing", records.iter().map(|r| r.northing).collect::<Vec<f32>>()), ]).unwrap(); println!("{}", df);
内容的提问来源于stack exchange,提问作者YeO
相关产品推荐
相关产品推荐

