1use std::collections::HashMap;
2use std::fs::{File,OpenOptions};
3use std::io::{BufReader, BufWriter, Read, Write};
4use std::sync::mpsc;
5use std::thread;
6use encoding_rs::GBK;
7
8use memmap2::{Mmap, MmapMut};
9use std::sync::Arc;
10use rayon::prelude::*;
11use rayon::slice::ParallelSlice;
12use std::collections::HashSet;
13use chrono::{Local, Datelike};
14use anyhow::{Result, Context};
15use anyhow::anyhow;
16use std::fs;
17
18
19#[derive(Clone)]
20pub struct DbfHeader {
21 pub record_count: u32,
22 pub header_len: u16,
23 pub record_len: u16,
24 pub fields: Vec<FieldDescriptor>,
25 pub file_type: u8,
26 pub year: u8,
27 pub month: u8,
28 pub day: u8,
29 pub reserved: [u8; 20], }
31
32
33#[derive(Debug, Clone)]
34pub struct FieldDescriptor {
35 pub name: String,
36 pub field_type: char,
37 pub length: u8,
38 pub decimal: u8,
39}
40
41#[derive(Debug, Clone)]
42struct FieldDescriptor1 {
43 name: String,
44 field_type: u8, length: u8,
46 decimal: u8,
47}
48fn parse_record(data: &[u8], fields: &[FieldDescriptor]) -> Result<HashMap<String, String>> {
64 let mut record = HashMap::new();
65 let mut offset = 1; for field in fields {
68 let end = offset + field.length as usize;
69
70 if end > data.len() {
72 break;
73 }
74
75 let field_data = &data[offset..end];
77
78 let (value, _, _) = GBK.decode(field_data);
80 let value = value.trim().to_string();
81
82 record.insert(field.name.clone(), value);
84
85 offset = end;
87 }
88
89 Ok(record)
90}
91
92
93
94#[derive(Clone)]
97pub struct DbfFile {
98 mmap: Arc<Mmap>,
99 header: Arc<DbfHeader>,
100}
101impl DbfFile {
102 pub fn open(path: &str) -> Result<Self> {
104 let file = File::open(path)?;
105 let mmap = Arc::new(unsafe { Mmap::map(&file)? });
106 let header = Arc::new(parse_header(&mmap)?);
107 Ok(Self { mmap, header })
108 }
109
110 pub fn get_fields(&self) -> &[FieldDescriptor] {
112 &self.header.fields
113 }
114
115 pub fn record_count(&self) -> u32 {
117 self.header.record_count
118 }
119
120 pub fn read_records(&self) -> Result<Vec<HashMap<String, String>>> {
122 read_concurrent_internal(Arc::clone(&self.mmap), Arc::clone(&self.header))
123 }
124
125 pub fn find_records(&self, query: &HashMap<String, String>) -> Result<Vec<HashMap<String, String>>> {
127 find_records_internal(
128 Arc::clone(&self.mmap),
129 Arc::clone(&self.header),
130 Arc::new(query.clone()), )
132 }
133
134 pub fn read_paged(&self, page: usize, page_size: usize) -> Result<Vec<HashMap<String, String>>> {
136 read_paged_internal(Arc::clone(&self.mmap), Arc::clone(&self.header), page, page_size)
137 }
138 pub fn read_paged_query(&self, query: &HashMap<String, String>,page: usize, page_size: usize) -> Result<Vec<HashMap<String, String>>> {
140 read_paged_query_internal(Arc::clone(&self.mmap), Arc::clone(&self.header),Arc::new(query.clone()), page, page_size)
141 }
142
143 pub fn filtered_count(&self, query: &HashMap<String, String>) -> Result<u32> {
145 filtered_count_internal(Arc::clone(&self.mmap), Arc::clone(&self.header), Arc::new(query.clone()))
146 }
147
148 pub fn update_records(&mut self, path: &str, query: HashMap<String, String>, updates: HashMap<String, String>) -> Result<usize> {
150 let mut all_records = self.read_records()?;
152 let mut updated_count = 0;
153
154 for record in all_records.iter_mut() {
155 if record_matches_query(record, &query) {
156 for (key, value) in &updates {
157 if let Some(v) = record.get_mut(key) {
158 *v = value.clone();
159 }
160 }
161 updated_count += 1;
162 }
163 }
164
165 let fields = self.get_fields().to_vec();
167 write_dbf(path, &all_records, &fields)?;
168
169 *self = Self::open(path)?;
171 Ok(updated_count)
172 }
173 pub fn write(&self, path: &str, records: &[HashMap<String, String>]) -> Result<()> {
175 write_dbf(path, records, &self.header.fields)
176 .map_err(|e| anyhow!("Failed to write DBF: {}", e))
177 }
178
179 pub fn add_record(&mut self, path: &str, new_record: HashMap<String, String>) -> Result<()> {
181 let mut all_records = self.read_records()?;
182
183 all_records.push(new_record);
191 self.write(path, &all_records)?;
192 self.reload(path)
193 }
194
195 pub fn delete_records(&mut self, path: &str, query: &HashMap<String, String>) -> Result<usize> {
197 let mut all_records = self.read_records()?;
198 let original_count = all_records.len();
199
200 all_records.retain(|record| !record_matches_query(record, query));
201 let deleted_count = original_count - all_records.len();
202
203 self.write(path, &all_records)?;
204 self.reload(path)?;
205 Ok(deleted_count)
206 }
207
208
209
210 pub fn add_fields(&mut self, path: &str, new_fields: Vec<FieldDescriptor>) -> Result<()> {
212 let mut fields = self.header.fields.clone();
214
215 {
217 let existing_names: HashSet<_> = fields.iter().map(|f| f.name.to_uppercase()).collect();
218
219 let unique_fields: Vec<_> = new_fields
221 .into_iter()
222 .filter(|f| !existing_names.contains(&f.name.to_uppercase()))
223 .collect();
224
225 fields.extend(unique_fields);
227 }
228
229 let mut new_header = self.header.as_ref().clone();
231 new_header.fields = fields;
232 new_header.header_len = 32 + (new_header.fields.len() * 32) as u16 + 1;
233 new_header.record_len = new_header.fields.iter().map(|f| f.length as u16).sum::<u16>() + 1; let all_records = self.read_records()?;
237 write_dbf(path, &all_records, &new_header.fields)?;
238 self.reload(path)
239 }
240
241
242 pub fn delete_fields(&mut self, path: &str, field_names: &[String]) -> Result<()> {
244 let mut new_fields = self.header.fields.clone();
245 new_fields.retain(|f| !field_names.contains(&f.name));
246
247 let mut new_header = self.header.as_ref().clone();
249 new_header.fields = new_fields;
250 new_header.header_len = 32 + (new_header.fields.len() * 32) as u16 + 1;
251 new_header.record_len = new_header.fields.iter().map(|f| f.length as u16).sum();
252
253 let all_records = self.read_records()?;
255 write_dbf(path, &all_records, &new_header.fields)?;
256 self.reload(path)
257 }
258
259 pub fn modify_fields(&mut self, path: &str, modified_fields: &[FieldDescriptor]) -> Result<()> {
261 let mut new_fields = self.header.fields.clone();
262
263 for modified in modified_fields {
264 if let Some(field) = new_fields.iter_mut().find(|f| f.name == modified.name) {
265 *field = modified.clone();
266 }
267 }
268
269 let mut new_header = self.header.as_ref().clone();
271 new_header.fields = new_fields;
272 new_header.header_len = 32 + (new_header.fields.len() * 32) as u16 + 1;
273 new_header.record_len = new_header.fields.iter().map(|f| f.length as u16).sum();
274
275 let all_records = self.read_records()?;
277 write_dbf(path, &all_records, &new_header.fields)?;
278 self.reload(path)
279 }
280
281 pub fn reload(&mut self, path: &str) -> Result<()> {
283 *self = Self::open(path)?;
284 Ok(())
285 }
286}
287
288
289fn read_concurrent_internal(
292 mmap: Arc<Mmap>, header: Arc<DbfHeader>, ) -> Result<Vec<HashMap<String, String>>> {
295 let num_threads = num_cpus::get().min(header.record_count as usize / 1000 + 1);
296 let records_per_thread = (header.record_count as usize + num_threads - 1) / num_threads;
297 let (tx, rx) = mpsc::channel();
298 let record_size = header.record_len as usize;
299 let base_offset = header.header_len as usize;
300
301 for i in 0..num_threads {
302 let tx = tx.clone();
303 let mmap_clone = Arc::clone(&mmap);
305 let header_clone = Arc::clone(&header);
306
307 thread::spawn(move || {
308 let start_idx = i * records_per_thread;
309 let end_idx = (start_idx + records_per_thread).min(header_clone.record_count as usize);
310
311 let start_offset = base_offset + start_idx * record_size;
312 let end_offset = base_offset + end_idx * record_size;
313
314 let chunk = &mmap_clone[start_offset..end_offset];
315 let mut records = Vec::with_capacity(end_idx - start_idx);
316
317 for (idx, record_data) in chunk.chunks(record_size).enumerate() {
318 if record_data[0] == 0x2A { continue; }
319 match parse_record(record_data, &header_clone.fields) {
320 Ok(record) => records.push(record),
321 Err(e) => eprintln!("Error parsing record: {:?}", e),
322 }
323 }
324
325 tx.send(records).unwrap();
326 });
327 }
328
329 drop(tx);
330 let mut all_records = Vec::with_capacity(header.record_count as usize);
331 for received in rx {
332 all_records.extend(received);
333 }
334
335 Ok(all_records)
336}
337
338fn find_records_internal(
339 mmap: Arc<Mmap>,
340 header: Arc<DbfHeader>,
341 query: Arc<HashMap<String, String>>,
342) -> Result<Vec<HashMap<String, String>>> {
343 let num_threads = num_cpus::get().min(header.record_count as usize / 1000 + 1);
344 let records_per_thread = (header.record_count as usize + num_threads - 1) / num_threads;
345 let (tx, rx) = mpsc::channel();
346
347 let record_size = header.record_len as usize;
349 let base_offset = header.header_len as usize;
350 let fields = Arc::new(header.fields.clone());
351
352 for i in 0..num_threads {
353 let tx = tx.clone();
354 let mmap_clone = Arc::clone(&mmap);
355 let fields_clone = Arc::clone(&fields);
356 let query_clone = Arc::clone(&query);
357 let header_clone = Arc::clone(&header); thread::spawn(move || {
360 let start_idx = i * records_per_thread;
361 let end_idx = (start_idx + records_per_thread).min(header_clone.record_count as usize);
363
364 let start_offset = base_offset + start_idx * record_size;
366 let end_offset = base_offset + end_idx * record_size;
367
368 let chunk = &mmap_clone[start_offset..end_offset];
369 let mut records = Vec::with_capacity(end_idx - start_idx);
370
371 for record_data in chunk.chunks(record_size) {
372 if record_data[0] == 0x2A {
373 continue;
374 }
375
376 match parse_record(record_data, &fields_clone) {
377 Ok(record) => {
378 if record_matches_query(&record, &query_clone) {
379 records.push(record);
380 }
381 }
382 Err(e) => eprintln!("Error parsing record: {}", e),
383 }
384 }
385
386 tx.send(records).unwrap();
387 });
388 }
389
390 drop(tx);
391 let mut all_records = Vec::new();
392 for received in rx {
393 all_records.extend(received);
394 }
395
396 Ok(all_records)
397}
398
399
400
401fn parse_header(data: &[u8]) -> Result<DbfHeader> {
404 if data.len() < 32 {
406 return Err(anyhow::anyhow!("Incomplete header data").into());
407 }
408
409 let header_data = &data[0..32];
411
412 let record_count = u32::from_le_bytes(header_data[4..8].try_into()?);
414 let header_len = u16::from_le_bytes(header_data[8..10].try_into()?);
415 let record_len = u16::from_le_bytes(header_data[10..12].try_into()?);
416
417 let reserved = header_data[12..32].try_into()?;
419
420 let fields_start = 32; let fields_end = header_len as usize; if data.len() < fields_end {
426 return Err(anyhow::anyhow!("Field descriptors exceed data bounds").into());
427 }
428
429 let fields = parse_field_descriptors(&data[fields_start..fields_end])?;
431
432 Ok(DbfHeader {
434 record_count,
435 header_len,
436 record_len,
437 fields,
438 reserved, file_type: header_data[0], year: header_data[1], month: header_data[2], day: header_data[3], })
444}
445
446
447
448
449
450
451fn parse_field_descriptors(data: &[u8]) -> Result<Vec<FieldDescriptor>> {
463 let mut fields = Vec::new();
464 let mut cursor = 0;
465
466 while cursor + 32 <= data.len() {
468 let chunk = &data[cursor..cursor+32];
469
470 let name = String::from_utf8_lossy(&chunk[0..11])
472 .trim_end_matches('\0')
473 .to_string();
474
475 let field_type = char::from(chunk[11]);
477
478 let length = chunk[16]; let decimal = chunk[17]; fields.push(FieldDescriptor {
483 name,
484 field_type,
485 length,
486 decimal, });
488
489 cursor += 32;
490
491 if cursor < data.len() && data[cursor] == 0x0D {
493 break;
494 }
495 }
496
497 Ok(fields)
498}
499
500pub fn get_dbf_fields(path: &str) -> Result<Vec<FieldDescriptor>> {
511 let file = File::open(path).context("Failed to open DBF file")?;
513 let mmap = unsafe { Mmap::map(&file).context("Failed to map DBF file into memory")? };
514
515 let header = parse_header(&mmap)?;
517
518 Ok(header.fields)
519}
520
521pub fn find_records(
532 path: &str,
533 query: &HashMap<String, String>,
534) -> Result<Vec<HashMap<String, String>>> {
535 let file = File::open(path).context("Failed to open DBF file")?;
536 let mmap = unsafe { Mmap::map(&file).context("Failed to map DBF file into memory")? };
537
538 let header = parse_header(&mmap)?;
539 let num_threads = num_cpus::get().min(header.record_count as usize / 1000 + 1);
540 let records_per_thread = (header.record_count as usize + num_threads - 1) / num_threads;
541
542 let mmap = Arc::new(mmap); let (tx, rx) = mpsc::channel();
544
545 let record_size = header.record_len as usize;
546 let base_offset = header.header_len as usize;
547 let fields = Arc::new(header.fields);
548
549 for i in 0..num_threads {
550 let tx = tx.clone();
551 let mmap = Arc::clone(&mmap);
552 let fields = Arc::clone(&fields);
553 let query = Arc::new(query.clone());
554
555 thread::spawn(move || {
556 let start_idx = i * records_per_thread;
557 let end_idx = (start_idx + records_per_thread).min(header.record_count as usize);
558
559 let start_offset = base_offset + start_idx * record_size;
560 let end_offset = base_offset + end_idx * record_size;
561
562 let chunk = &mmap[start_offset..end_offset];
563 let mut records = Vec::with_capacity(end_idx - start_idx);
564
565 for (idx, record_data) in chunk.chunks(record_size).enumerate() {
566 if record_data[0] == 0x2A { continue; } match parse_record(record_data, &fields) {
569 Ok(record) => {
570 if record_matches_query(&record, &query) {
572 records.push(record);
573 }
574 }
575 Err(e) => {
576 eprintln!("Error parsing record: {:?}", e);
577 }
578 }
579 }
580
581 tx.send(records).unwrap();
582 });
583 }
584
585 drop(tx); let mut all_records = Vec::new();
587
588 for received in rx {
589 all_records.extend(received);
590 }
591
592 Ok(all_records)
593}
594
595fn record_matches_query(
596 record: &HashMap<String, String>,
597 query: &HashMap<String, String>,
598) -> bool {
599 query.iter().all(|(key, value)| {
600 record.get(key).map_or(false, |record_value| record_value == value)
601 })
602}
603
604
605
606pub fn write_dbf(path: &str, records: &[HashMap<String, String>], fields: &[FieldDescriptor]) -> Result<(), std::io::Error> {
627 let file = File::create(path)?;
629 let mut writer = BufWriter::new(file);
630
631 let today = Local::now();
633
634 let header_len = 32 + fields.len() * 32 + 1;
635 let record_len = fields.iter().map(|f| f.length as usize).sum::<usize>() + 1;
636
637 let mut header = vec![0u8; 32];
638 header[0] = 0x03; header[1] = (today.year() - 1900) as u8; header[2] = today.month() as u8; header[3] = today.day() as u8; header[4..8].copy_from_slice(&(records.len() as u32).to_le_bytes());
643 header[8..10].copy_from_slice(&(header_len as u16).to_le_bytes());
644 header[10..12].copy_from_slice(&(record_len as u16).to_le_bytes());
645
646 writer.write_all(&header)?;
647
648 for field in fields {
650 let mut field_data = [0u8; 32];
651 let name_bytes = field.name.as_bytes();
652 let name_len = name_bytes.len().min(11); field_data[0..name_len].copy_from_slice(&name_bytes[0..name_len]);
654 field_data[11] = field.field_type as u8; field_data[16] = field.length; field_data[17] = field.decimal; writer.write_all(&field_data)?;
658 }
659
660 writer.write_all(&[0x0D])?; let mut buffer = Vec::with_capacity(record_len);
664 for record in records {
665 buffer.clear();
666 buffer.push(0x20); for field in fields {
669 let value = record.get(&field.name).map(|s| s.as_str()).unwrap_or(""); let encoded = if field.field_type == 'C' {
671 let (encoded, _, _) = GBK.encode(value);
673 encoded.to_vec()
674 } else {
675 value.as_bytes().to_vec()
677 };
678
679 let mut padded = vec![0x20; field.length as usize]; let copy_len = encoded.len().min(field.length as usize); match field.field_type {
684 'C' => {
685 padded[..copy_len].copy_from_slice(&encoded[..copy_len]); },
687 _ => {
688 let start = field.length as usize - copy_len; padded[start..].copy_from_slice(&encoded[..copy_len]);
690 }
691 }
692 buffer.extend(&padded); }
694 writer.write_all(&buffer)?;
695 }
696
697 writer.flush()?;
698 Ok(())
699}
700
701
702pub fn update_records(path: &str, query: HashMap<String, String>, updates: HashMap<String, String>) -> Result<usize, std::io::Error> {
714 let mut all_records = read_dbf_concurrent(path)
716 .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?; let mut updated_count = 0;
718
719 for record in all_records.iter_mut() {
721 let mut match_query = true;
722 for (key, value) in &query {
723 if let Some(record_value) = record.get(key) {
724 if record_value != value {
725 match_query = false;
726 break;
727 }
728 } else {
729 match_query = false;
730 break;
731 }
732 }
733 if match_query {
734 for (key, value) in &updates {
735 if let Some(record_value) = record.get_mut(key) {
736 *record_value = value.clone();
737 }
738 }
739 updated_count += 1;
740 }
741 }
742
743 println!("更新后的所有记录:");
745 for record in &all_records {
746 for (key, value) in record {
747 println!("{} -> {}", key, value);
748 }
749 println!("------");
750 }
751
752 let fields = get_dbf_fields(path)
754 .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?; write_dbf(path, &all_records, &fields)?;
758
759 Ok(updated_count)
760}
761
762
763
764pub fn add_record(path: &str, mut new_record: HashMap<String, String>) -> Result<(), std::io::Error> {
775 let mut all_records = read_dbf_concurrent(path)
777 .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?; let fields = get_dbf_fields(path)
781 .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?; for field in &fields {
785 if !new_record.contains_key(&field.name) {
786 new_record.insert(field.name.clone(), String::new());
787 }
788 }
789
790 for field in &fields {
792 if let Some(value) = new_record.get(&field.name) {
793 match field.field_type {
794 'C' => {
795 if value.len() > field.length as usize {
797 return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, format!("Field {} exceeds maximum length of {}", field.name, field.length)));
798 }
799 }
800 'N' => {
801 if value.parse::<f64>().is_err() {
803 return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, format!("Field {} must be a valid number", field.name)));
804 }
805 }
806 _ => {}
807 }
808 }
809 }
810
811 all_records.push(new_record.clone());
813
814 println!("新增记录:");
816 for (key, value) in &new_record {
817 println!("{} -> {}", key, value);
818 }
819
820 write_dbf(path, &all_records, &fields)
822 .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?; Ok(())
825}
826
827
828
829pub fn delete_records(path: &str, query: &HashMap<String, String>) -> Result<usize> {
840 let mut all_records = read_dbf_concurrent(path)
842 .context("Failed to read DBF records")?;
843 let original_count = all_records.len();
844
845 all_records.retain(|record| {
847 for (key, value) in query {
848 if let Some(record_value) = record.get(key) {
849 if record_value != value {
850 return true;
851 }
852 } else {
853 return true;
854 }
855 }
856 false
857 });
858
859 let deleted_count = original_count - all_records.len();
860
861 let fields = get_dbf_fields(path)
863 .context("Failed to get DBF fields")?;
864
865 write_dbf(path, &all_records, &fields)
867 .context("Failed to write updated DBF file")?;
868
869 Ok(deleted_count)
870}
871
872pub fn read_dbf_concurrent(path: &str) -> Result<Vec<HashMap<String, String>>> {
873 let file = File::open(path).context("Failed to open DBF file")?;
874 let mmap = unsafe { Mmap::map(&file).context("Failed to map DBF file into memory")? };
875
876 let header = parse_header(&mmap)?;
878
879 let num_threads = num_cpus::get().min(header.record_count as usize / 1000 + 1);
880 let records_per_thread = (header.record_count as usize + num_threads - 1) / num_threads;
881
882 let mmap = Arc::new(mmap); let (tx, rx) = mpsc::channel();
884
885 let record_size = header.record_len as usize;
886 let base_offset = header.header_len as usize;
887
888 for i in 0..num_threads {
889 let tx = tx.clone();
890 let mmap = Arc::clone(&mmap);
891 let fields = header.fields.clone(); thread::spawn(move || {
894 let start_idx = i * records_per_thread;
895 let end_idx = (start_idx + records_per_thread).min(header.record_count as usize);
896
897 let start_offset = base_offset + start_idx * record_size;
898 let end_offset = base_offset + end_idx * record_size;
899
900 let chunk = &mmap[start_offset..end_offset];
901 let mut records = Vec::with_capacity(end_idx - start_idx);
902
903 for (idx, record_data) in chunk.chunks(record_size).enumerate() {
904 if record_data[0] == 0x2A { continue; } let _global_idx = start_idx + idx;
906
907 match parse_record(record_data, &fields) {
909 Ok(record) => records.push(record),
910 Err(e) => {
911 eprintln!("Error parsing record: {:?}", e);
912 }
913 }
914 }
915
916 tx.send(records).unwrap();
917 });
918 }
919
920 drop(tx); let mut all_records = Vec::with_capacity(header.record_count as usize);
922 for received in rx {
923 all_records.extend(received);
924 }
925
926 Ok(all_records)
927}
928
929pub fn get_record_count(path: &str) -> Result<u32> {
940 let file = File::open(path)
942 .context(format!("Failed to open file: {}", path))?;
943 let mmap = unsafe { Mmap::map(&file) }
944 .context("Failed to map file to memory")?;
945
946 if mmap.len() < 8 { return Err(anyhow::anyhow!("文件太小无法读取有效头部").into());
949 }
950
951 let record_count = u32::from_le_bytes(mmap[4..8].try_into()?);
953
954 Ok(record_count)
955}
956
957pub fn read_dbf_paged(
970 path: &str,
971 page: usize,
972 page_size: usize,
973) -> Result<Vec<HashMap<String, String>>> {
974 let file = File::open(path)
976 .context(format!("Failed to open file: {}", path))?;
977 let mmap = Arc::new(unsafe { Mmap::map(&file) }
978 .context("Failed to map file to memory")?);
979 let header = parse_header(&mmap)
980 .context("Failed to parse DBF header")?;
981
982 let total_records = header.record_count as usize;
984 let start_idx = (page - 1).saturating_mul(page_size);
985 let end_idx = (start_idx + page_size).min(total_records);
986
987 if start_idx >= total_records {
989 return Ok(Vec::new());
990 }
991
992 let record_size = header.record_len as usize;
994 let data_start = header.header_len as usize;
995 let start_offset = data_start + start_idx * record_size;
996 let end_offset = data_start + end_idx * record_size;
997
998 let records_data = &mmap[start_offset..end_offset.min(mmap.len())];
1000
1001 let records: Result<Vec<_>, _> = records_data
1003 .par_chunks(record_size)
1004 .filter(|chunk| chunk[0] != 0x2A)
1005 .map(|chunk| parse_record(chunk, &header.fields))
1006 .collect();
1007
1008 records.map_err(|e| anyhow::anyhow!("Error parsing records: {}", e).into())
1009}
1010
1011
1012pub(crate) fn read_paged_internal(
1013 mmap: Arc<Mmap>,
1014 header: Arc<DbfHeader>,
1015 page: usize,
1016 page_size: usize,
1017) -> Result<Vec<HashMap<String, String>>> {
1018 let total_records = header.record_count as usize;
1020 let start_idx = (page - 1).saturating_mul(page_size);
1021 let end_idx = (start_idx + page_size).min(total_records);
1022
1023 if start_idx >= total_records {
1025 return Ok(Vec::new());
1026 }
1027
1028 let record_size = header.record_len as usize;
1030 let data_start = header.header_len as usize;
1031 let start_offset = data_start + start_idx * record_size;
1032 let end_offset = data_start + end_idx * record_size;
1033
1034 let records_data = &mmap[start_offset..end_offset.min(mmap.len())];
1036
1037 let records: Vec<_> = records_data
1039 .par_chunks(record_size)
1040 .filter(|chunk| {
1041 !chunk.is_empty() && chunk[0] != 0x2A
1043 })
1044 .filter_map(|chunk| {
1045 parse_record(chunk, &header.fields)
1046 .map_err(|e| eprintln!("解析记录失败: {}", e))
1047 .ok()
1048 })
1049 .collect();
1050
1051 Ok(records)
1052}
1053
1054pub fn read_dbf_paged_query(
1067 path: &str,
1068 query: &HashMap<String, String>,
1069 page: usize,
1070 page_size: usize,
1071) -> Result<Vec<HashMap<String, String>>> {
1072 let file = File::open(path).context("Failed to open DBF file")?;
1073 let mmap = unsafe { Mmap::map(&file) }.context("Failed to memory-map DBF file")?;
1074 let header = parse_header(&mmap).context("Failed to parse DBF header")?;
1075
1076 let num_threads = num_cpus::get().min(header.record_count as usize / 1000 + 1);
1077 let records_per_thread = (header.record_count as usize + num_threads - 1) / num_threads;
1078
1079 let mmap = Arc::new(mmap);
1080 let query = Arc::new(query.clone());
1081 let (tx, rx) = mpsc::channel();
1082
1083 let record_size = header.record_len as usize;
1084 let base_offset = header.header_len as usize;
1085
1086 for i in 0..num_threads {
1087 let tx = tx.clone();
1088 let mmap = Arc::clone(&mmap);
1089 let fields = header.fields.clone();
1090 let query = Arc::clone(&query);
1091
1092 thread::spawn(move || {
1093 let start_idx = i * records_per_thread;
1094 let end_idx = (start_idx + records_per_thread).min(header.record_count as usize);
1095
1096 let start_offset = base_offset + start_idx * record_size;
1097 let end_offset = base_offset + end_idx * record_size;
1098
1099 let chunk = &mmap[start_offset..end_offset];
1100 let mut records = Vec::with_capacity(end_idx - start_idx);
1101
1102 for record_data in chunk.chunks(record_size) {
1103 if record_data[0] == 0x2A {
1104 continue;
1105 }
1106
1107 match parse_record(record_data, &fields) {
1109 Ok(record) => {
1110 if matches_query(&record, &query) {
1111 records.push(record);
1112 }
1113 }
1114 Err(e) => {
1115 eprintln!("Error parsing record: {}", e);
1116 }
1117 }
1118 }
1119
1120 tx.send(records).unwrap();
1121 });
1122 }
1123
1124 drop(tx);
1125 let mut all_records = Vec::new();
1126 for received in rx {
1127 all_records.extend(received);
1128 }
1129
1130 let start = (page - 1) * page_size;
1132 let end = start + page_size;
1133 let total = all_records.len();
1134
1135 Ok(if start >= total {
1136 Vec::new()
1137 } else {
1138 all_records[start..end.min(total)].to_vec()
1139 })
1140}
1141
1142fn read_paged_query_internal(
1143 mmap: Arc<Mmap>,
1144 header: Arc<DbfHeader>, query: Arc<HashMap<String, String>>,
1146 page: usize,
1147 page_size: usize,
1148) -> Result<Vec<HashMap<String, String>>> {
1149 let num_threads = num_cpus::get().min(header.record_count as usize / 1000 + 1);
1150 let records_per_thread = (header.record_count as usize + num_threads - 1) / num_threads;
1151
1152 let (tx, rx) = mpsc::channel();
1153 let record_size = header.record_len as usize;
1154 let base_offset = header.header_len as usize;
1155
1156 for i in 0..num_threads {
1157 let tx = tx.clone();
1158 let mmap = Arc::clone(&mmap);
1159 let header = Arc::clone(&header); let query = Arc::clone(&query);
1161
1162 thread::spawn(move || {
1163 let start_idx = i * records_per_thread;
1165 let end_idx = (start_idx + records_per_thread).min(header.record_count as usize);
1166
1167 let start_offset = base_offset + start_idx * record_size;
1168 let end_offset = base_offset + end_idx * record_size;
1169
1170 let chunk = &mmap[start_offset..end_offset];
1171 let mut records = Vec::with_capacity(end_idx - start_idx);
1172
1173 for record_data in chunk.chunks(record_size) {
1174 if record_data[0] == 0x2A {
1175 continue;
1176 }
1177
1178 match parse_record(record_data, &header.fields) { Ok(record) => {
1180 if matches_query(&record, &query) {
1181 records.push(record);
1182 }
1183 }
1184 Err(e) => {
1185 eprintln!("Record parsing error: {}", e);
1186 }
1187 }
1188 }
1189
1190 tx.send(records).unwrap_or_else(|e| eprintln!("Channel send error: {}", e));
1191 });
1192 }
1193
1194 drop(tx);
1195 let mut all_records: Vec<_> = rx.into_iter().flatten().collect();
1196
1197 all_records.sort_by(|a, b| {
1199 let a_offset = a.get("_offset").and_then(|s| s.parse::<usize>().ok()).unwrap_or(0);
1200 let b_offset = b.get("_offset").and_then(|s| s.parse::<usize>().ok()).unwrap_or(0);
1201 a_offset.cmp(&b_offset)
1202 });
1203
1204 let start = (page - 1) * page_size;
1206 let end = start + page_size;
1207 let total = all_records.len();
1208
1209 Ok(if start >= total {
1210 Vec::new()
1211 } else {
1212 all_records[start..end.min(total)].to_vec()
1213 })
1214}
1215
1216
1217
1218fn matches_query(record: &HashMap<String, String>, query: &HashMap<String, String>) -> bool {
1220 query.iter()
1221 .all(|(k, v)| record.get(k).map_or(false, |val| val == v))
1222}
1223
1224pub fn add_fields_to_dbf(path: &str, add_fields: Vec<FieldDescriptor>) -> Result<()> {
1225 let file_data = {
1227 let file = File::open(path).context("Failed to open DBF file")?;
1228 let mut buf = Vec::new();
1229 BufReader::new(file).read_to_end(&mut buf).context("Failed to read DBF file")?;
1230 buf
1231 };
1232
1233 let header = parse_header(&file_data).context("Failed to parse DBF header")?;
1235
1236 if header.record_len == 0 {
1238 return Err(anyhow!("Original record length cannot be zero"));
1239 }
1240 let old_record_len = header.record_len as usize;
1241
1242 let data_start = header.header_len as usize;
1244 let expected_data_len = header.record_count as usize * old_record_len;
1245 if file_data.len() < data_start + expected_data_len {
1246 return Err(anyhow!("File data is incomplete or corrupted"));
1247 }
1248
1249 let mut fields = header.fields.clone();
1251 let existing_names: HashSet<_> = fields.iter().map(|f| &f.name).collect();
1252 let new_fields = add_fields.into_iter()
1253 .filter(|f| !existing_names.contains(&f.name))
1254 .collect::<Vec<_>>();
1255 fields.extend(new_fields);
1256
1257 let updated_header_len = 32 + (fields.len() * 32) as u16 + 1; let updated_record_len = fields.iter().map(|f| f.length as usize).sum::<usize>();
1260
1261 if updated_record_len < old_record_len {
1263 return Err(anyhow!("New record length is shorter than the original record length"));
1264 }
1265
1266 let mut new_data = Vec::with_capacity(header.record_count as usize * updated_record_len);
1268
1269 for chunk in file_data[data_start..].chunks(old_record_len) {
1270 let mut record = chunk.to_vec();
1271
1272 if record.len() < old_record_len {
1274 let padding_len = old_record_len - record.len();
1275 record.extend(vec![b' '; padding_len]);
1276 }
1277
1278 let padding_len = updated_record_len - old_record_len;
1280 record.extend(vec![b' '; padding_len]);
1281
1282 new_data.extend_from_slice(&record);
1283 }
1284
1285 let mut new_file = Vec::new();
1287
1288 new_file.push(header.file_type);
1301 new_file.push(header.year);
1303 new_file.push(header.month);
1304 new_file.push(header.day);
1305 new_file.extend_from_slice(&header.record_count.to_le_bytes());
1307 new_file.extend_from_slice(&updated_header_len.to_le_bytes());
1309 new_file.extend_from_slice(&(updated_record_len as u16).to_le_bytes());
1311 new_file.extend_from_slice(&header.reserved);
1313
1314 for field in &fields {
1316 let mut desc = [0; 32];
1317 let name_bytes = field.name.as_bytes();
1318 let len = name_bytes.len().min(11);
1319 desc[..len].copy_from_slice(&name_bytes[..len]);
1320 desc[11] = field.field_type as u8;
1321 desc[16] = field.length;
1322 desc[17] = field.decimal;
1323 new_file.extend_from_slice(&desc);
1324 }
1325
1326 new_file.push(0x0D);
1328
1329 new_file.extend_from_slice(&new_data);
1331
1332 fs::write(path, new_file).context("Failed to write updated DBF file")?;
1334
1335 Ok(())
1336}
1337
1338pub fn modify_fields_in_dbf(path: &str, modify_fields: Vec<FieldDescriptor>) -> Result<()> {
1347 let file = OpenOptions::new()
1349 .read(true)
1350 .write(true)
1351 .open(path)
1352 .context(format!("Failed to open file with write access: {}", path))?;
1353
1354 let mut mmap_mut = unsafe { MmapMut::map_mut(&file).context("Failed to map file to memory")? };
1356
1357 let mut header = parse_header(&mmap_mut).context("Failed to parse DBF header")?;
1359
1360 let mut fields = header.fields.clone();
1362 for modify_field in modify_fields {
1363 if let Some(field) = fields.iter_mut().find(|f| f.name == modify_field.name) {
1364 *field = modify_field;
1365 }
1366 }
1367
1368 let fields1: Vec<FieldDescriptor1> = fields
1370 .iter()
1371 .map(|field| FieldDescriptor1 {
1372 name: field.name.clone(),
1373 field_type: field.field_type as u8, length: field.length,
1375 decimal: field.decimal,
1376 })
1377 .collect();
1378
1379 let updated_header_len = 32 + fields1.len() as u16 * 32 + 1; let updated_record_len = fields1.iter().map(|f| f.length as u16).sum::<u16>();
1382 header.header_len = updated_header_len;
1383 header.record_len = updated_record_len;
1384
1385 let total_records = header.record_count as usize;
1387 let old_record_size = header.record_len as usize;
1388 let new_record_size = updated_record_len as usize;
1389 let data_start = header.header_len as usize;
1390 let required_file_size = data_start + total_records * new_record_size + 1; if required_file_size > mmap_mut.len() {
1394 println!(
1395 "Resizing file: old_size={}, new_size={}",
1396 mmap_mut.len(),
1397 required_file_size
1398 );
1399 file.set_len(required_file_size as u64)
1400 .context("Failed to resize file")?;
1401 mmap_mut = unsafe { MmapMut::map_mut(&file).context("Failed to re-map file")? };
1403 }
1404
1405 let header_data = &mut mmap_mut[0..32];
1407 header_data[0] = header.file_type;
1408 header_data[1] = header.year;
1409 header_data[2] = header.month;
1410 header_data[3] = header.day;
1411 header_data[4..8].copy_from_slice(&header.record_count.to_le_bytes());
1412 header_data[8..10].copy_from_slice(&header.header_len.to_le_bytes());
1413 header_data[10..12].copy_from_slice(&header.record_len.to_le_bytes());
1414 header_data[12..32].copy_from_slice(&header.reserved);
1415
1416 let terminator_pos = 32 + fields1.len() * 32;
1418 if terminator_pos >= mmap_mut.len() {
1419 return Err(anyhow!("Terminator position out of bounds"));
1420 }
1421 mmap_mut[terminator_pos] = 0x0D;
1422
1423 let fields_start = 32;
1425 for (i, field) in fields1.iter().enumerate() {
1426 let field_data_start = fields_start + i * 32;
1427 let field_data = &mut mmap_mut[field_data_start..field_data_start + 32];
1428
1429 let (name_bytes, _, _) = GBK.encode(&field.name);
1431 let name_len = name_bytes.len().min(11); field_data[0..name_len].copy_from_slice(&name_bytes[..name_len]);
1433 field_data[name_len] = 0; field_data[11] = field.field_type; field_data[16] = field.length;
1438 field_data[17] = field.decimal;
1439
1440 for j in 12..32 {
1442 if j != 16 && j != 17 {
1443 field_data[j] = 0;
1444 }
1445 }
1446 }
1447
1448 let original_fields = fields1.clone(); for record_idx in 0..total_records {
1452 let old_offset = data_start + record_idx * old_record_size;
1453 let new_offset = data_start + record_idx * new_record_size;
1454
1455 if old_offset >= mmap_mut.len() || new_offset >= mmap_mut.len() {
1457 return Err(anyhow!("Record offset out of bounds"));
1458 }
1459
1460 mmap_mut[new_offset] = mmap_mut[old_offset];
1462
1463 let mut pos_old = 1;
1464 let mut pos_new = 1;
1465
1466 for (i, new_field) in fields1.iter().enumerate() {
1467 let old_field = &original_fields[i]; let old_data_range = pos_old..(pos_old + old_field.length as usize);
1469 let new_data_range = pos_new..(pos_new + new_field.length as usize);
1470
1471 if old_offset + old_data_range.end > mmap_mut.len()
1473 || new_offset + new_data_range.end > mmap_mut.len()
1474 {
1475 return Err(anyhow!("Field data out of bounds"));
1476 }
1477
1478 let old_data: Vec<u8> = mmap_mut[old_offset + old_data_range.start..old_offset + old_data_range.end]
1480 .to_vec();
1481
1482 let mut new_data_buffer = vec![b' '; new_field.length as usize];
1484
1485 match new_field.field_type {
1487 b'C' => process_string_field(&old_data, &mut new_data_buffer, old_field, new_field),
1488 b'N' => process_numeric_field(&old_data, &mut new_data_buffer, old_field, new_field),
1489 b'D' => process_date_field(&old_data, &mut new_data_buffer),
1490 b'L' => process_logical_field(&old_data, &mut new_data_buffer),
1491 _ => new_data_buffer.copy_from_slice(&old_data),
1492 }
1493
1494 let new_data_start = new_offset + new_data_range.start;
1496 let new_data_end = new_offset + new_data_range.end;
1497 mmap_mut[new_data_start..new_data_end].copy_from_slice(&new_data_buffer);
1498
1499 pos_old += old_field.length as usize;
1500 pos_new += new_field.length as usize;
1501 }
1502
1503 if new_record_size > pos_new {
1505 if new_offset + new_record_size > mmap_mut.len() {
1506 return Err(anyhow!(
1507 "New record size out of bounds: new_offset={}, new_record_size={}, mmap_len={}",
1508 new_offset, new_record_size, mmap_mut.len()
1509 ));
1510 }
1511 mmap_mut[new_offset + pos_new..new_offset + new_record_size].fill(b' ');
1512 }
1513}
1514
1515 if required_file_size > 0 {
1517 mmap_mut[required_file_size - 1] = 0x1A;
1518 }
1519
1520 mmap_mut.flush().context("Failed to flush memory map changes to file")?;
1522 file.sync_all().context("Failed to sync file changes")?;
1523 println!("Changes saved to file.");
1524
1525 Ok(())
1526}
1527
1528fn process_string_field(
1530 old_data: &[u8],
1531 new_data: &mut [u8],
1532 old_field: &FieldDescriptor1,
1533 new_field: &FieldDescriptor1,
1534) {
1535 let (decoded, _, _) = GBK.decode(old_data);
1537 let decoded_str = decoded.trim_end().to_string();
1538
1539 let (encoded, _, _) = GBK.encode(&decoded_str);
1541 let write_len = encoded.len().min(new_data.len());
1542
1543 new_data[..write_len].copy_from_slice(&encoded[..write_len]);
1545 new_data[write_len..].fill(b' ');
1546}
1547
1548fn process_numeric_field(
1550 old_data: &[u8],
1551 new_data: &mut [u8],
1552 old_field: &FieldDescriptor1,
1553 new_field: &FieldDescriptor1,
1554) {
1555 let copy_len = old_data.len().min(new_data.len());
1557 new_data[..copy_len].copy_from_slice(&old_data[..copy_len]);
1558
1559 if new_data.len() > copy_len {
1561 let padding = new_data.len() - copy_len;
1562 new_data.copy_within(..copy_len, padding);
1563 new_data[..padding].fill(b' ');
1564 }
1565}
1566
1567fn process_date_field(old_data: &[u8], new_data: &mut [u8]) {
1569 let copy_len = old_data.len().min(new_data.len());
1571 new_data[..copy_len].copy_from_slice(&old_data[..copy_len]);
1572}
1573
1574fn process_logical_field(old_data: &[u8], new_data: &mut [u8]) {
1576 if !old_data.is_empty() {
1578 new_data[0] = old_data[0];
1579 }
1580}
1581
1582
1583pub fn delete_fields_from_dbf(
1587 path: &str,
1588 delete_field_names: Vec<String>,
1589) -> Result<()> {
1590 let file = OpenOptions::new()
1592 .read(true)
1593 .write(true)
1594 .open(path)
1595 .context("Failed to open file")?;
1596
1597 let mut mmap = unsafe { MmapMut::map_mut(&file).context("Failed to map file")? };
1599
1600 let header = {
1602 let header = parse_header(&mmap)?;
1603 header };
1605
1606 let mut fields = header.fields.clone();
1608 fields.retain(|field| !delete_field_names.contains(&field.name));
1609
1610 let updated_header_len = 32 + fields.len() as u16 * 32;
1612 let updated_record_len = fields.iter().map(|f| f.length as u16).sum::<u16>();
1613 let updated_header = DbfHeader {
1614 record_count: header.record_count,
1615 header_len: updated_header_len,
1616 record_len: updated_record_len,
1617 fields,
1618 file_type: header.file_type,
1619 year: header.year,
1620 month: header.month,
1621 day: header.day,
1622 reserved: header.reserved,
1623 };
1624
1625 let header_data = &mut mmap[0..32];
1627 header_data[0] = updated_header.file_type;
1628 header_data[1] = updated_header.year;
1629 header_data[2] = updated_header.month;
1630 header_data[3] = updated_header.day;
1631 header_data[4..8].copy_from_slice(&updated_header.record_count.to_le_bytes());
1632 header_data[8..10].copy_from_slice(&updated_header.header_len.to_le_bytes());
1633 header_data[10..12].copy_from_slice(&updated_header.record_len.to_le_bytes());
1634 header_data[12..32].copy_from_slice(&updated_header.reserved);
1635
1636 let fields_start = 32;
1638 for (i, field) in updated_header.fields.iter().enumerate() {
1639 let field_data_start = fields_start + i * 32;
1640 let field_data = &mut mmap[field_data_start..field_data_start + 32];
1641
1642 let name_len = field.name.len().min(11);
1644 field_data[0..name_len].copy_from_slice(field.name.as_bytes());
1645 field_data[name_len] = 0; field_data[11] = field.field_type as u8;
1649 field_data[16] = field.length;
1650 field_data[17] = field.decimal;
1651
1652 for j in 12..32 {
1654 if j != 16 && j != 17 {
1655 field_data[j] = 0;
1656 }
1657 }
1658 }
1659
1660 let old_fields_end = fields_start + header.fields.len() * 32;
1662 let new_fields_end = fields_start + updated_header.fields.len() * 32;
1663 if new_fields_end < old_fields_end {
1664 mmap[new_fields_end..old_fields_end].fill(0);
1665 }
1666
1667 let data_start = header.header_len as usize;
1669 let record_size = header.record_len as usize;
1670 let updated_record_size = updated_header.record_len as usize;
1671 let total_records = header.record_count as usize;
1672
1673 for record_idx in 0..total_records {
1674 let old_offset = data_start + record_idx * record_size;
1675 let new_offset = data_start + record_idx * updated_record_size;
1676
1677 let mut pos_old = 1; let mut pos_new = 1;
1679
1680 for field in &updated_header.fields {
1682 let old_field = header.fields.iter().find(|f| f.name == field.name).unwrap();
1683 let old_end = pos_old + old_field.length as usize;
1684 let new_end = pos_new + field.length as usize;
1685
1686 let mut temp_buffer = vec![0u8; (old_end - pos_old)];
1688 temp_buffer.copy_from_slice(&mmap[old_offset + pos_old..old_offset + old_end]);
1689
1690 let new_data = &mut mmap[new_offset + pos_new..new_offset + new_end];
1691 new_data.copy_from_slice(&temp_buffer);
1692
1693 pos_old = old_end;
1694 pos_new = new_end;
1695 }
1696
1697 if updated_record_size > pos_new {
1699 mmap[new_offset + pos_new..new_offset + updated_record_size].fill(b' ');
1700 }
1701 }
1702
1703 mmap.flush().context("Failed to flush memory map")?;
1705 file.sync_all().context("Failed to sync file")?;
1706
1707 Ok(())
1708}
1709
1710fn is_record_matching(record: &HashMap<String, String>, query: &HashMap<String, String>) -> bool {
1712 query.iter().all(|(field_name, value)| {
1713 match record.get(field_name) {
1714 Some(field_value) => field_value == value,
1715 None => false,
1716 }
1717 })
1718}
1719
1720pub fn get_filtered_record_count(path: &str, query: &HashMap<String, String>) -> Result<u32> {
1731 let file = File::open(path).context("Failed to open DBF file")?;
1732 let mmap = unsafe { Mmap::map(&file).context("Failed to map DBF file into memory")? };
1733
1734 let header = parse_header(&mmap)?;
1736
1737 let num_threads = num_cpus::get().min(header.record_count as usize / 1000 + 1);
1739 let records_per_thread = (header.record_count as usize + num_threads - 1) / num_threads;
1740
1741 let mmap = Arc::new(mmap); let base_offset = header.header_len as usize;
1743 let record_size = header.record_len as usize;
1744 let fields = Arc::new(header.fields.clone()); let filtered_count = (0..num_threads).into_par_iter().map(|i| {
1748 let start_idx = i * records_per_thread;
1749 let end_idx = (start_idx + records_per_thread).min(header.record_count as usize);
1750
1751 let start_offset = base_offset + start_idx * record_size;
1752 let end_offset = base_offset + end_idx * record_size;
1753
1754 let chunk = &mmap[start_offset..end_offset];
1755 let mut local_count = 0;
1756
1757 for record_data in chunk.chunks(record_size) {
1758 if record_data[0] == 0x2A {
1760 continue;
1761 }
1762
1763 match parse_record(record_data, &fields) {
1765 Ok(record) => {
1766 if is_record_matching(&record, query) {
1768 local_count += 1;
1769 }
1770 }
1771 Err(e) => {
1772 eprintln!("Error parsing record: {:?}", e);
1773 }
1774 }
1775 }
1776
1777 local_count }).sum::<u32>(); Ok(filtered_count)
1781}
1782pub(crate) fn filtered_count_internal(
1783 mmap: Arc<Mmap>,
1784 header: Arc<DbfHeader>,
1785 query: Arc<HashMap<String, String>>,
1786) -> Result<u32> {
1787 let num_threads = num_cpus::get().min(header.record_count as usize / 1000 + 1);
1789 let records_per_thread = (header.record_count as usize + num_threads - 1) / num_threads;
1790
1791 let base_offset = header.header_len as usize;
1792 let record_size = header.record_len as usize;
1793 let fields = Arc::new(header.fields.clone()); let filtered_count = (0..num_threads)
1797 .into_par_iter()
1798 .map(|i| {
1799 let start_idx = i * records_per_thread;
1801 let end_idx = (start_idx + records_per_thread).min(header.record_count as usize);
1802
1803 let start_offset = base_offset + start_idx * record_size;
1805 let end_offset = base_offset + end_idx * record_size;
1806
1807 let chunk = &mmap[start_offset..end_offset];
1809 let mut local_count = 0;
1810
1811 for record_data in chunk.chunks(record_size) {
1813 if record_data[0] == 0x2A {
1815 continue;
1816 }
1817
1818 match parse_record(record_data, &fields) {
1820 Ok(record) => {
1821 if is_record_matching(&record, &*query) {
1822 local_count += 1;
1823 }
1824 }
1825 Err(e) => {
1826 eprintln!("Error parsing record: {:?}", e);
1827 }
1828 }
1829 }
1830
1831 local_count })
1833 .sum::<u32>(); Ok(filtered_count)
1836}