Я разбираю немного причудливый, собственный текстовый формат файла.
Формат содержит CSV, смешанный с файлами, отличными от CSV. Меня интересует только часть CSV, которая находится где-то в файле и окружена не-csv.
Мне было интересно, можно ли указать CsvReader
/LazyCsvReader
что-то вроде std::io::BufReader
или даже Vec<u8>
, содержащее содержимое CSV, вместо того, чтобы предоставлять AsRef<Path>
(который должен указывать на файл, если я не ошибаюсь).
Я хочу инициализировать программу чтения CSV одним из следующих способов:
BufReader
, который будет оборачивать строки, которые я хочу прочитать.Vec<u8>
, который содержит все байты, которые я хочу прочитать.Можно ли это сделать или мне нужно написать временный файл, содержащий только CSV?
Я попробовал задать CsvReader
BufReader<File>
, где я уже переместил итератор .lines()
туда, где начинаются мои данные. Но похоже, что CsvReader
перед чтением перемещает курсор в начало потока.
Вы можете передать свой Vec<u8>
(или любую другую вещь, реализующую AsRef<[u8]>
), завернутую в Курсор , в CsvReader::new:
use polars::prelude::*;
use std::io::Cursor;
fn main() {
let bytes = b"a,b,c\nd,e,f\ng,h,i".to_vec();
let reader = CsvReader::new(Cursor::new(bytes));
dbg!(reader.finish().unwrap());
}
Если ваши данные CSV разделены символами новой строки из ваших собственных дополнительных данных, вы также можете просто использовать with_skip_rows и with_n_rows, чтобы пропустить ведущие внешние данные и прочитать только количество строк, которые являются фактическим CSV:
let reader = CsvReader::from_path("tmp.data")
.unwrap()
.with_skip_rows(1);
.with_n_rows(Some(2));
tmp.data
:
some proprietary none csv data
a,b,c
d,e,f
g,h,i
even more proprietary none csv data
Оба варианта производят одно и то же DataFrame
:
┌─────┬─────┬─────┐
│ a ┆ b ┆ c │
│ --- ┆ --- ┆ --- │
│ str ┆ str ┆ str │
╞═════╪═════╪═════╡
│ d ┆ e ┆ f │
│ g ┆ h ┆ i │
└─────┴─────┴─────┘
Кроме этого, я не думаю, что вы можете использовать BufReader без реализации MmapBytesReader
для его оболочки.
Нет, это не сработает, как я уже писал, это должна быть реализация типа AsRef<[u8]>
. Вы можете увидеть это в документации по MmapBytesReader, это признак, CsvReader::new
связывающий его аргумент.
Очень полезный совет, спасибо! Из этого я понимаю, что
Cursor<Vec<u8>>
иBufReader<File>
должны иметь некоторые общие черты. Могу ли я использоватьCursor<T>
, гдеT
— это любая итерацияu8
, или это не сработает? В частности, меня интересует что-то вродеCursor::new(vec![...].iter().map(|x| ...))