【问题标题】:Rust - How to check EOF in File?Rust - 如何检查文件中的 EOF?
【发布时间】:2020-04-01 04:01:07
【问题描述】:

我正在尝试实现https://github.com/pingcap/talent-plan/blob/master/rust/building-blocks/bb-2.md 的最后一个练习。

简而言之,我需要将一些枚举序列化为 bson,写入文件并从文件中读取它们。 我一直在检查是否达到 EOF。我用谷歌搜索了一段时间,但没有找到答案。

use std::path::Path;
use std::fs::{create_dir_all, OpenOptions};
use std::io::{Write, Seek, Cursor, SeekFrom};
use serde::{Serialize, Deserialize};
use std::str;
use bson;
use bson::{encode_document, decode_document};

fn main() {
    let dir = Path::new("D:/download/rust");
    create_dir_all(dir).expect("Cannot create dir");

    let txt = dir.join("move.txt");

    // Encode some moves
    let mut file = OpenOptions::new()
        .append(true)
        .create(true)
        .open(&txt)
        .expect("Cannot open txt");

    encode_and_write_move(&mut file, &Move::Up(1));
    encode_and_write_move(&mut file, &Move::Down(2));
    encode_and_write_move(&mut file, &Move::Left(3));
    encode_and_write_move(&mut file, &Move::Right(4));

    // Decode and print moves
    let mut file = OpenOptions::new()
        .read(true)
        .open(&txt)
        .expect("Cannot open txt");

    loop {
        let end_of_file = false; // How?
        if end_of_file {
            break;
        }

        let doc = decode_document(&mut file).expect("cannot decode doc");
        println!("doc = {:?}", doc);
    }
}

fn encode_and_write_move<W: Write>(writer: &mut W, mov: &Move) {
    let serialized = bson::to_bson(mov).unwrap();
    let doc = serialized.as_document().unwrap();
    encode_document(writer, doc).expect("failed to encode doc");
}

#[derive(Debug, Serialize, Deserialize)]
enum Move {
    Up(i32),
    Down(i32),
    Left(i32),
    Right(i32),
}

更新:
似乎查看是否达到 EOF 的唯一方法是检查返回的 Err。这是我对整个练习的尝试。

use std::path::Path;
use std::fs::{create_dir_all, OpenOptions};
use std::io::Write;
use serde::{Serialize, Deserialize};
use std::{str, io};
use bson;
use bson::{encode_document, decode_document, DecoderError};

fn main() {
    let dir = Path::new("D:/download/rust");
    create_dir_all(dir).expect("Cannot create dir");

    let txt = dir.join("move.txt");

    // Encode some moves
    let mut writer = OpenOptions::new()
        .append(true)
        .create(true)
        .open(&txt)
        .expect("Cannot open txt");

    encode_and_write_move(&mut writer, &Move::Up(1));
    encode_and_write_move(&mut writer, &Move::Down(2));
    encode_and_write_move(&mut writer, &Move::Left(3));
    encode_and_write_move(&mut writer, &Move::Right(4));

    // Decode and print moves
    let mut reader = OpenOptions::new()
        .read(true)
        .open(&txt)
        .expect("Cannot open txt");

    loop {
        match decode_document(&mut reader) {
            Result::Ok(doc) => println!("doc = {:?}", &doc),
            Result::Err(DecoderError::IoError(e)) if e.kind() == io::ErrorKind::UnexpectedEof => break,
            Result::Err(err) => panic!("Decoding failed with {}", err)
        }
    }
}

fn encode_and_write_move<W: Write>(writer: &mut W, mov: &Move) {
    let serialized = bson::to_bson(mov).unwrap();
    let doc = serialized.as_document().unwrap();
    encode_document(writer, doc).expect("failed to encode doc");
}

#[derive(Debug, Serialize, Deserialize)]
enum Move {
    Up(i32),
    Down(i32),
    Left(i32),
    Right(i32),
}

【问题讨论】:

  • 为什么是EOF?我猜你只需要检查从decode_document 返回的DecoderResult
  • @aventurin 请参阅我对以下 muhuk 的回答的回复

标签: rust bson


【解决方案1】:

bson::decode_document 返回DecoderResult&lt;Document&gt;,它是Result&lt;T, DecoderError&gt; 的别名。 如果您检查枚举DecoderError 的可能值,您将看到EndOfStream 似乎decode_document 在EOF 的情况下返回Result::Err&lt;DecoderError::IoError&lt;_&gt;&gt;

因此,与其尝试检测代码中的 EOF,不如直接使用流(通过重复调用 decode_document)直到出现错误。然后就可以处理错误了,或者EndOfStream的情况下可以正常继续处理。

你可以试试这样的:

loop {
    match decode_documment(&mut file) {
        Result::Ok(doc) => println!("doc = {:?}", &doc),     
        Result::Err(DecoderError::IoError(io_error)) => match io_error.kind() {
            std::io::ErrorKind::UnexpectedEof => break,
            _ => panic!("Decoding failed with I/O error {}", io_error)
        }
        Result::Err(err) => panic!("Decoding failed with {}", err)
    }
}

【讨论】:

  • 不,它不起作用,因为在 EOF 的情况下代码会出现恐慌。在 EOF 时返回 IoError(Custom { kind: UnexpectedEof, error: "failed to fill whole buffer" } 非常令人困惑,我不确定在调用 decode_document() 之前检查此错误而不是检查 EOF 是否是一种好习惯。
  • EndOfStream 标识为EOF 值可能是我的错误。代码恐慌时的确切输出是什么?
  • 谢谢,但你的代码无法编译,我想出的最好的是Result::Err(DecoderError::IoError(e)) if e.kind() == io::ErrorKind::UnexpectedEof =&gt; break,
  • 很抱歉。你是对的,你不能在kind 字段上进行模式匹配,因为它不是一个字段。我会将上面的代码更新为您所获得的更易读的版本。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-04
  • 2011-01-16
  • 1970-01-01
  • 2012-06-18
相关资源
最近更新 更多