Rust报错‘EOF while parsing an object’问题排查求助
Rust读取JSON插入MySQL解析panic问题解决
问题场景
以下是一段用于读取JSON文件并将数据插入MySQL的Rust代码:
use std::fs::File; use std::io::{prelude::*, BufReader}; use serde_json::{Value}; use mysql::*; use mysql::prelude::*; struct Show { title: String, show_poster: String, show_url: String, } fn main() { // Open and read the file lines let path = r"C:\Users\egete\Desktop\projects\cdeneme\rust\mysqljson\src\info.json"; let file = File::open(path).expect("Unable to read file"); let reader = BufReader::new(file); let lines: Vec<String> = reader.lines().map(|l| l.expect("Could not parse line")).collect(); // Connect to your my-sql database let url = Opts::from_url("mysql://root:Egetelli99@localhost:3306/jsonmysql").unwrap(); let pool = Pool::new(url).unwrap(); let mut conn = pool.get_conn().unwrap(); // Loop through the lines for line in lines { // Parse the line into a JSON object serde_json::Value let v: Value = serde_json::from_str(&line).expect("Unable to parse"); // Since we want to save the streaming services of the said show, we need to // loop an array inside the JSON file. let l = v["watchAvailability"][0]["directUrls"].as_array().unwrap().len(); for n in 0..l { let streaming_url = v["watchAvailability"][0]["directUrls"][n].as_str().clone(); match streaming_url { Some(url) => { // Display the streaming url. I have to do this to remove the Some(url) warning. // Unused variables in Rust emits warnings println!("{:?}", url); // Create a vector (array of object). // This provides you the ability to process multiple objects upon saving let shows = vec![ Show { title: v["title"].as_str().as_deref().unwrap_or("Error").to_string(), show_poster: v["posterPath"].as_str().as_deref().unwrap_or("Error").to_string(), show_url: v["watchAvailability"][0]["directUrls"][n].as_str().as_deref().unwrap_or("Error").to_string(), }, ]; //Execute an insert query conn.exec_batch( r"INSERT INTO `shows` (`title`, `show_poster`, `show_url`) VALUES (:title, :show_poster, :show_url)", shows.iter().map(|s| params! { "title" => s.title.clone(), "show_poster" => s.show_poster.clone(), "show_url" => s.show_url.clone(), }) ).unwrap_err(); }, _ => println!("Error"), } } } }
运行时触发panic,错误信息:
thread 'main' panicked at 'Unable to parse: Error("EOF while parsing an object", line: 1, column: 1)', src\main.rs:30:52 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace error: process didn't exit successfully: `target\debug\mysqljson.exe` (exit code: 101)
错误原因
- JSON读取方式错误:代码按行读取文件后尝试将每行单独解析为JSON对象,但你的
info.json应该是单个完整的JSON结构(比如一个对象或数组),而非每行一个独立JSON的JSON Lines格式。单独读取第一行(比如仅{或数组开头)时,解析器会因JSON不完整触发EOF错误。 - 数据库执行逻辑错误:
conn.exec_batch调用了unwrap_err(),这会强制在SQL执行成功时panic(unwrap_err()仅接受错误结果,成功时会触发panic)。 - unwrap滥用:多处使用
unwrap(),一旦JSON结构不符合预期会直接panic,代码鲁棒性差。
解决方法
1. 读取整个JSON文件内容
放弃按行读取,直接读取整个文件的字符串内容,再一次性解析成JSON结构。
2. 修正数据库执行的错误处理
将unwrap_err()改为unwrap(),或使用match/if let处理执行结果,避免不必要的panic。
3. 优化JSON取值逻辑
使用更安全的方式获取JSON字段,减少unwrap()的使用,避免因结构变化导致的panic。
修改后的完整代码
use std::fs::read_to_string; use serde_json::Value; use mysql::{params, Opts, Pool}; use mysql::prelude::*; struct Show { title: String, show_poster: String, show_url: String, } fn main() { // 读取整个JSON文件内容 let path = r"C:\Users\egete\Desktop\projects\cdeneme\rust\mysqljson\src\info.json"; let json_content = read_to_string(path).expect("无法读取文件"); // 解析整个JSON结构 let v: Value = serde_json::from_str(&json_content).expect("无法解析JSON"); // 连接MySQL数据库 let url = Opts::from_url("mysql://root:Egetelli99@localhost:3306/jsonmysql").unwrap(); let pool = Pool::new(url).unwrap(); let mut conn = pool.get_conn().unwrap(); // 处理watchAvailability中的directUrls if let Some(watch_list) = v["watchAvailability"].as_array() { for watch_item in watch_list { if let Some(direct_urls) = watch_item["directUrls"].as_array() { let title = v["title"].as_str().unwrap_or("Error").to_string(); let show_poster = v["posterPath"].as_str().unwrap_or("Error").to_string(); // 批量准备数据 let shows: Vec<Show> = direct_urls.iter() .filter_map(|url_val| url_val.as_str()) .map(|url| Show { title: title.clone(), show_poster: show_poster.clone(), show_url: url.to_string(), }) .collect(); // 执行批量插入 if !shows.is_empty() { match conn.exec_batch( r"INSERT INTO `shows` (`title`, `show_poster`, `show_url`) VALUES (:title, :show_poster, :show_url)", shows.iter().map(|s| params! { "title" => &s.title, "show_poster" => &s.show_poster, "show_url" => &s.show_url, }) ) { Ok(_) => println!("批量插入成功"), Err(e) => eprintln!("插入失败: {}", e), } } } } } }
额外说明
- 如果你的JSON文件确实是每行一个独立JSON(JSON Lines格式),则需要检查文件中是否有空行,或者每行的JSON是否完整,空行解析时会触发EOF错误。
- 实际生产环境中,建议替换所有
unwrap()为match或?操作符(需要将main改为Result<(), Box<dyn std::error::Error>>),提升代码鲁棒性。
内容的提问来源于stack exchange,提问作者Ege Telli
相关产品推荐
相关产品推荐

