Reputation: 422
I am new to rust programming and trying to read a file line by line. It seems as it removes newline characters in the end and returns only the text. I am reading a metadata file where it has \n as well as \r\n. File sample is below where I have added \n and \r\n explicitly.
TAG 0\n
15:\n
32348SIPpTag091\n
SDP from 0 after offer
215:
v=0\r\n
o=user1 53655765 2353687637 IN IP4 172.31.8.95\r\n
s=-\r\n
c=IN IP4 172.31.8.95\r\n
t=0 0\r\n
m=audio 34218 RTP/AVP 8\r\n
c=IN IP4 172.31.8.95\r\n
a=direction:both\r\n
a=label:a_leg\r\n
a=rtpmap:8 PCMA/8000\r\n
a=sendonly\r\n
a=rtcp:34219\r\n
I am capturing this information in a map, where TAG 0
is my key and 32348SIPpTag091
is the value and this line 15:
gives me the length of value. Based on this length I am figuring out whether I have received the value or not.
But with my below code I am losing \r along with \n and because of that the length is not matching with the content.
Is there a way in rust where I can configure to only look for \n for newline or not to remove those characters from the line.
Here is my code
fn read_meta(path: &str) -> MetaInfo {
let mut map = HashMap::new();
let mut idx: String = String::from("");
let mut data: String = String::from("");
let mut dlen: i32 = -1;
println!("reading from {}", path);
let file = File::open(path).unwrap();
let reader = BufReader::new(file);
for line in reader.lines() {
let line = line.unwrap();
if idx.is_empty() {
if line.len() <= 1 {
continue;
}
idx = String::from(line.trim_end_matches("\n"));
} else if dlen == -1 {
let c = String::from(line.trim_end_matches("\n").trim_end_matches(":"));
dlen = c.parse::<i32>().unwrap();
} else {
data = data + &line;
if data.len() as i32 >= dlen {
let diff = (data.len() as i32 - dlen) * -1;
if diff < 0 {
let val = data.chars().take(dlen as usize).collect();
map.insert(idx.to_string(), val);
} else {
map.insert(idx.to_string(), data);
}
idx = String::from("");
dlen = -1;
data = String::from("");
}
}
}
let meta_info = MetaInfo {
index: String::from(map.get("PARENT").unwrap()),
is_complete: map.contains_key("PARENT") && map.contains_key("SDP from 1 after answer")
};
return meta_info;
}
Upvotes: 3
Views: 1774
Reputation: 42492
As you've noticed, the lines
utility will strip out ending newlines (CR LF or LF alone) for convenience. This is not configurable
If you do not want this behaviour, you can use the lower-level read_line
: it will read a line and put it in the buffer you provided including the EOL content, whether it's a lone LF or CR LF. It's not an iterable though so you'll have to process it by hand e.g.:
let mut buf = String::new();
while let Ok(n) = reader.read_line(&mut buf) {
if n == 0 { break; } // eof
// do stuff with `buf` string here
buf.clear(); // otherwise the data will accumulate in your buffer
}
Upvotes: 6